• C++ Qt 学习(四):自定义控件与 qss 应用


    1. qss 简介

    • Qt style sheet(qss,Qt 样式表),不需要用 C++ 代码控件进行重载,就可以修改控件外观,类似于前端的 css

    2. qss 选择器

    2.1 通配符选择器

    /* 设置后控件窗口背景色都被修改为黄色 */
    * {
        background-color:yellow;
    }
    
    /* 指明子类 */
    * QPushButton{
        background-color:yellow;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.2 类型选择器

    /* 通过控件类型来匹配控件的 (包括子类) */
    QWidget {
        background-color:yellow
    }
    
    /* 禁止父窗口影响子窗口样式 (不包括子类) */
    setAttribute(Qt::WA_StyledBackground);
    
    /* 在类前面加个 .(不包括子类),这样就只对 QWidget 生效,如果界面上有其它控件则不生效 */
    .QWidget {
        background-color:yellow
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.3 ID 选择器

    • ID 选择器是结合控件的 objectname 来匹配控件的,qss 里 objectname 前加个 “#” 来表示
      /* 只对 pushButton_2 有效*/
      QPushButton#pushButton_2 {
          background-color:blue
      }
      
      • 1
      • 2
      • 3
      • 4

    2.4 属性选择器

    • 属性选择器是结合控件的属性值来匹配控件的,首先要设定控件的属性,qss 里属性用 [proterty = attitude] 来限制
      label1.setProperty('notice_level', 'error')
      label2.setProperty('notice_level', 'warning')
      
      • 1
      • 2
      .QLabel {
          background-color:pink;
      }
      
      .QLabel[notice_level='warning'] {
          border:5px solid yellow;
      }
      
      .QLabel[notice_level='error'] {
          border:5px solid red;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    3. QLabel

    /* 设置普通样式 */
    QLabel {
        font-family: "Microsoft YaHei";  /*字体类型*/
        font-size: 18px;                 /*字体大小*/
        color: #BDC8E2;                  /*字体颜色*/    
        font-style: normal;              /*字体斜体样式*/
        font-weight: normal;             /*字体加粗样式*/
     
        /*设置边框属性*/
        border-style: solid;
        border-width: 2px;
        border-color: aqua;
        border-radius: 20px;
     
        /*设置文字显示位置*/
        padding-left: 20px;
        padding-top: 3px;
     
        /*设置背景样式*/
        background-color: #2E3648;
        background-image: url("./res/image/123.png");
        background-repeat: no-repeat;
        background-position: left center;
    }
    
    /* 设置鼠标悬浮样式*/
    QLabel:hover {
        color: red;
        border-color: green;
        background-color: aqua;
    }
    
    /* 设置禁止样式 */
    QLabel:disabled {
    	color: blue;
    	border-color: brown;
        background-color: #363636;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4. QLineEdit

    在这里插入图片描述

    • widget.ui
      在这里插入图片描述

    • qss 样式

    QWidget{
        background-color:rgb(54,54,54);
    }
    
    QLineEdit{
        border: 1px solid #ABCDA0;      /* 边框宽度为1px,颜色为#A0A0A0 */
        border-radius: 3px;             /* 边框圆角 */
        padding-left: 5px;              /* 文本距离左边界有5px */
        background-color: #F2F2F2;      /* 背景颜色 */
        color: black;                   /* 文本颜色 */
        selection-background-color: #A0A0A0;  /* 选中文本的背景颜色 */
        selection-color: #F2F2F2;         /* 选中文本的颜色 */
        font-family: "Microsoft YaHei";   /* 文本字体族 */
        font-size: 10pt;                  /* 文本字体大小 */
    }
        
    QLineEdit:hover { /* 鼠标悬浮在QLineEdit时的状态 */
        border: 1px solid #298DFF;
        border-radius: 3px;
        background-color: #F2F2F2;
        color: #298DFF;
        selection-background-color: #298DFF;
        selection-color: #F2F2F2;
    }
        
    QLineEdit[echoMode="2"] { /* QLineEdit有输入掩码时的状态 */
        lineedit-password-character: 9679;
        lineedit-password-mask-delay: 2000;
    }
    
    QLineEdit:disabled { /* QLineEdit在禁用时的状态 */
        border: 1px solid #CDCDCD;
        background-color: #CDCDCD;
        color: #B4B4B4;
    }
    
    QLineEdit:read-only { /* QLineEdit在只读时的状态 */
        background-color: #CDCDCD;
        color: #F2F2F2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class Widget; }
    QT_END_NAMESPACE
    
    class Widget : public QWidget {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    private slots:
        void on_lineEdit_rex_returnPressed();
        void on_lineEdit_rex_inputRejected();
        void on_btnCheck_clicked();
    
    private:
        Ui::Widget *ui;
    };
    #endif // WIDGET_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include   // 使用正则表达式限制输入
    #include 
    #include 
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        ui->lineEdit_1->setText("Hello LineEdit");
    
        ui->lineEdit_2->setReadOnly(true);  // 设置为只读状态
        ui->lineEdit_2->setText("Hello LineEdit");
    
        ui->lineEdit_3->setText("Hello LineEdit");
        ui->lineEdit_3->setEchoMode(QLineEdit::Password);  // 设置密码为圆点隐藏状态
    
        ui->lineEdit_4->setDisabled(true);  // 设置为不可用状态
    
        // 使用正则表达式(QRegExp)来验证电子邮件地址的格式
        QRegExp regx("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}");
        // 指定验证的目标为 ui->lineEdit_rex(一个文本输入框)
        QValidator *validator = new QRegExpValidator(regx, ui->lineEdit_rex);
        // 将验证器应用到 lineEdit_rex上,这样用户在该输入框中输入文本时,将根据正则表达式进行验证
        ui->lineEdit_rex->setValidator(validator);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    // 当用户在 lineEdit_rex 中按下回车键并释放时触发这个函数
    void Widget::on_lineEdit_rex_returnPressed() {
        qDebug() << "on_lineEdit_rex_returnPressed";
    }
    
    // 当 lineEdit_rex 中的输入被验证器拒绝时触发这个函数
    void Widget::on_lineEdit_rex_inputRejected() {
        qDebug() << "on_lineEdit_rex_inputRejected";
    }
    
    // 获取 lineEdit_rex 文本框的验证器,并根据输入的文本内容进行验证
    void Widget::on_btnCheck_clicked() {
        // 验证器 validator 用于限制用户输入的内容符合特定的模式或规则
        const QValidator *v = ui->lineEdit_rex->validator();
        int pos = 0;
        
        // 获取 lineEdit_rex 文本框中的文本内容
        QString text = ui->lineEdit_rex->text();
        // 用于检查刚才获取的文本内容是否满足验证器的要求
        if (v->validate(text, pos) != QValidator::Acceptable) {
            ui->lineEdit_rex->setText(QString::fromLocal8Bit("邮箱格式不正确"));
        } else {
            QMessageBox::information(this, u8"标题", u8"邮箱格式正确");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    5. QPushButton

    5.1 点击按钮弹出菜单

    在这里插入图片描述

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include 
    #include 
    #include "qss.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
        this->setStyleSheet("background-color:rgb(54,54,54)");
    
        // 1、创建 文件 菜单项
        QMenu *fileMenuItems = new QMenu;
        fileMenuItems->setIcon(QIcon(":/resources/file.png"));
        fileMenuItems->setTitle(u8"文件");
        fileMenuItems->setStyleSheet(QString::fromStdString(menuItemQss));
        QList<QAction*> acList;  // 用于存放子级菜单
    
        // 为 文件 菜单项添加 action 构成子菜单
        QAction *openFileAc = new QAction(QIcon(":/resources/file.png"), u8"打开文件", this);
        //openFileAc->setShortcuts(QKeySequence::Print);   // 设置快捷键,系统内置枚举量
        openFileAc->setShortcut(QKeySequence("Ctrl+8"));   // 随意指定快捷键
        QAction *openFloderAc = new QAction(u8"打开文件夹", this);
        QAction *openUrlAc = new QAction(u8"打开url", this);
    
        // QMenu 添加 QMenu 构成多级菜单
        acList << openFileAc << openFloderAc << openUrlAc;
        fileMenuItems->addActions(acList);
    
        // 0、主菜单(父菜单,包括 文件 播放 工具 设置 退出)
        QMenu *pMenu = new QMenu;
        pMenu->addMenu(fileMenuItems);
    
        // 2、创建 播放 工具 菜单项(无子级菜单)
        QAction *play = new QAction(QIcon(":/resources/play.png"), u8"播放", this);
        QAction *tools = new QAction(QIcon(":/resources/tools.png"), u8"工具", this);
        pMenu->addAction(play);
        pMenu->addAction(tools);
    
        pMenu->addSeparator();  // 添加分割线
    
        // 3、创建 设置 菜单项
        QMenu *setMenuItems = new QMenu;
        setMenuItems->setTitle(u8"设置");
        setMenuItems->setIcon(QIcon(":/resources/set.png"));
        QList<QAction*> setList;
    
        // 为 设置 菜单项添加 action 构成子菜单
        QAction *sysSetAc = new QAction(u8"系统设置", this);
        QAction *playSetAc = new QAction(u8"播放设置", this);
        QAction *zimuSetAc = new QAction(u8"字幕设置", this);
        setList << sysSetAc << playSetAc << zimuSetAc;
        setMenuItems->addActions(setList);
        setMenuItems->setStyleSheet(QString::fromStdString(menuItemQss));
        pMenu->addMenu(setMenuItems);
    
        pMenu->addSeparator();  // 添加分割线
    
        // 4、创建 退出 菜单项
        QAction *exitAc = new QAction(QIcon(":/resources/exit.png"), u8"退出", this);
        pMenu->addAction(exitAc);
    
        ui->pushButton->setMenu(pMenu);
    
        connect(openFileAc, &QAction::triggered, [=]{
            QString fileName = QFileDialog::getOpenFileName(this,
                                                            u8"请选择视频文件",
                                                            "D:/",
                                                            "视频(*.mp4 *.flv);;");
            if (fileName.isEmpty()) {
                return;
            }
        });
    
        ui->pushButton->setText(u8"QW影音");
        ui->pushButton->setFixedSize(100, 32);
        ui->pushButton->setStyleSheet(QString::fromStdString(button_qss));
        pMenu->setStyleSheet(QString::fromStdString(menuQss));
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • qss.h
    #ifndef QSS_H
    #define QSS_H
    
    #include 
    
    using namespace std;
    
    string button_qss = R"(
        QPushButton {
            font:18px "Microsoft YaHei";
            color:rgb(255,255,255);
            border:none
        }
    
        QPushButton::menu-indicator:open {
            image:url(:/resources/down_arrow.svg);
            subcontrol-position:right center;
            subcontrol-origin:padding;border:none;
        }
    
        QPushButton::menu-indicator:closed {
            image:url(:/resources/up_arrow.svg);
            subcontrol-position:right center;
            subcontrol-origin:padding;border:none;
        }
    )";
    
    string menuQss = R"(
        QMenu {
            background-color:rgb(53, 63, 73);
        }
    
        QMenu::item {
            font:16px;
            color:white;
            background-color:rgb(53, 63, 73);
            padding:8px 32px;
            margin:8px 8px;
            /*border-bottom:1px solid #DBDBDB;  item底部颜色*/
        }
    
        /*选择项设置*/
        QMenu::item:selected {
            background-color:rgb(54, 54, 54);
        }
    )";
    
    string menuItemQss = R"(
        QMenu {
            background-color:rgb(73, 73, 73);
        }
    
        QMenu::item {
            font:16px;
            color:white;
            background-color:rgb(73, 73, 73);
            padding:8px 32px;
            margin:8px 8px;
            /*border-bottom:1px solid #DBDBDB;  item底部颜色*/
        }
    
        /*选择项设置*/
        QMenu::item:selected {
             background-color:rgb(54, 54, 54);
        }
    )";
    
    #endif // QSS_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    5.2 鼠标悬浮弹出对话框

    在这里插入图片描述

    5.2.1 主窗口
    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include "CVolumeButton.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        resize(800, 600);
    
        QHBoxLayout *pHlay = new QHBoxLayout(this);
    
        // 音量调节按钮
        CVolumeButton* pVolumeButton = new CVolumeButton(this);
        pHlay->addWidget(pVolumeButton);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    5.2.2 音量按钮
    • CVolumeButton.h
    /*
    音量调节按钮
    功能:
        1. 鼠标悬浮到音量时显示 slider dialog
        2. 点击时 mute
    注意问题:
        重写按钮类,样式表无效
    */
    #pragma once
    
    #include 
    #include "CVolumeSliderDialog.h"
    
    class CVolumeButton : public QPushButton {
        Q_OBJECT
    
    public:
        CVolumeButton(QWidget* parent = nullptr);
        ~CVolumeButton();
    
        bool getMute() const {
            return m_isMute;
        }
        // 设置静音
        void setMute(bool mute) { 
            m_isMute = mute;
        }
    
    signals:
        void sig_VolumeValue(int value);
    
    protected:
        void paintEvent(QPaintEvent* event) override;
        void enterEvent(QEvent* event) override;
        //void leaveEvent(QEvent* event) override;
        void mousePressEvent(QMouseEvent* event) override;
        void timerEvent(QTimerEvent* event) override;
    
    private:
        bool m_isMute = false;  // 是否静音
        CVolumeSliderDialog* m_pVolumeSliderDlg = nullptr;
    
        int m_timerId = -1;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • CVolumeButton.cpp
    #include "CVolumeButton.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    CVolumeButton::CVolumeButton(QWidget* parent) : QPushButton(parent) {
        this->setFixedSize(32, 32);  // 音量按钮大小
    
        setStyleSheet("QPushButton{background-image:url(:/resources/audio_open.svg);border:none;}"
            "QPushButton:hover{background-image:url(:/resources/audio_open_hover.svg);border:none;}"
            "QPushButton:pressed{background-image:url(:/resources/audio_open.svg);border:none;}");
    }
    
    CVolumeButton::~CVolumeButton() {}
    
    // 绘制一个样式化的按钮,以便与应用程序的整体外观和主题保持一致
    void CVolumeButton::paintEvent(QPaintEvent*) {
        QStylePainter p(this);  // QStylePainter 用于样式化绘制 widget
        QStyleOptionButton option;  // 用于存储按钮的样式选项
        initStyleOption(&option);   // 初始化 option 对象,以便正确设置按钮的样式选项
        p.drawControl(QStyle::CE_PushButton, option);  // 绘制一个样式化的按钮
    }
    
    // 在鼠标进入 CVolumeButton 对象时显示一个音量滑动条,其位置在 CVolumeButton 的正上方
    void CVolumeButton::enterEvent(QEvent* event) {
    	if (!m_pVolumeSliderDlg)
            m_pVolumeSliderDlg = new CVolumeSliderDialog(this);
    
        // 将 widget 坐标 pos 转换为全局屏幕坐标
        QPoint p1 = this->mapToGlobal(QPoint(0, 0));  // 声音按钮左上角相对于桌面的绝对位置
    	QRect rect1 = this->rect();
        QRect rect2 = m_pVolumeSliderDlg->rect();     // rect 包含标题栏,去掉标题栏后 height 不变
    
    	int x = p1.x() + (rect1.width() - rect2.width()) / 2;
    	int y = p1.y() - rect2.height() - 5;
        m_pVolumeSliderDlg->move(x, y);               // move 是相对于桌面原点的位置
    
    	m_pVolumeSliderDlg->show();
        m_timerId = startTimer(250);
    
    	connect(m_pVolumeSliderDlg, &CVolumeSliderDialog::sig_SliderValueChanged, [=](int value) {
    		emit sig_VolumeValue(value);
        });
    }
    
    // 鼠标移出控件或窗口
    //void CVolumeButton::leaveEvent(QEvent* event)
    //{
    //	根据鼠标的位置判断音量调节窗口是否消失
    //	//QPoint p1 = QCursor::pos();   // 绝对位置
    //
    //	//cout << "QCursor x= " << p1.x() << " y = " << p1.y() << endl;
    //
    //	//if (m_pVolumeSliderDlg) {
    //	//	QRect rect1 = this->rect();  // 按钮矩形
    //	//	QRect rect2 = m_pVolumeSliderDlg->rect();
    //	//	QRect rect3 = m_pVolumeSliderDlg->geometry();
    //
    //	//	QPoint p2 = this->mapToGlobal(QPoint(0, 0));   // 声音按钮左上角相对于桌面的绝对位置
    //
    //	//	// 已知:音量框宽 40 > 按钮宽 30
    //	//  // 左上宽高
    //	//	QRect area(rect3.left(), rect3.top(), rect2.width(), p2.y() + rect1.height() - rect3.top());
    //	//	cout << "p1 x = " << p1.x() << " y = " << p1.y() << endl;
    //
    //	//	if (!area.contains(p1)) {
    //	//		m_pVolumeSliderDlg->hide();
    //	//	}
    //	//}
    //}
    
    // 鼠标按下事件,用于处理音量按钮的交互行为
    void CVolumeButton::mousePressEvent(QMouseEvent* event) {
        if (event->button() == Qt::LeftButton) {  // 检测鼠标事件的按钮类型是否为左键
            m_isMute = !m_isMute;
            if (m_isMute) {  // 如果是左键点击,则切换静音状态
    			if (m_pVolumeSliderDlg)
    				m_pVolumeSliderDlg->setSliderValue(0);
            } else {         // 如果静音状态为假,将滑动条的值设置为 50
    			if (m_pVolumeSliderDlg)
    				m_pVolumeSliderDlg->setSliderValue(50);
    		}
    	}
    }
    
    /**
     * @brief 用定时器模拟 leaveEvent
     * 直接在 leaveEvent 里让 m_pVolumeSliderDlg 消失,效果不太好
     * 用鼠标移动事件也不太好,定时器是比较好的做法
     */
    void CVolumeButton::timerEvent(QTimerEvent* event) {
        if ((m_pVolumeSliderDlg != nullptr) && (m_pVolumeSliderDlg->isVisible())) {
            QPoint p1 = QCursor::pos();      // 鼠标绝对位置
            if (m_pVolumeSliderDlg) {
                QRect rect1 = this->rect();  // 按钮矩形
    			QRect rect2 = m_pVolumeSliderDlg->rect();
    			QRect rect3 = m_pVolumeSliderDlg->geometry();
    
                QPoint p2 = this->mapToGlobal(QPoint(0, 0));   // 声音按钮左上角相对于桌面的绝对位置
    
                // 已知:音量框宽 40 > 按钮宽 30
                // 左上宽高
                QRect area(rect3.left(), rect3.top(), rect2.width(), p2.y() + rect1.height() - rect3.top());
    
                if (!area.contains(p1)) {
    				m_pVolumeSliderDlg->hide();
    			}
    		}
        } else {
            killTimer(m_timerId);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    5.2.3 音量调节滑动条
    • CVolumeSliderDialog.h
    #ifndef CVOLUMESLIDERDIALOG_H
    #define CVOLUMESLIDERDIALOG_H
    
    #include 
    #include 
    
    class CVolumeSliderDialog : public QDialog {
    	Q_OBJECT
    
    public:
    	CVolumeSliderDialog(QWidget *parent = Q_NULLPTR);
    	~CVolumeSliderDialog();
    
        void setSliderValue(int value) {
    		m_pSlider->setValue(value);
    	}
    
    protected:
    	bool event(QEvent* event) override;
    
    signals:
    	void sig_SliderValueChanged(int value);
    
    private:
    	QSlider* m_pSlider = nullptr;
    };
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • CVolumeSliderDialog.cpp
    #include "CVolumeSliderDialog.h"
    #include 
    #include 
    #include 
    
    // 注意由于此类使用了 windows 的函数 SetClassLong,需要包含 user32.lib
    // 如果是在 vs2019 中使用则不需要包含 user32.lib
    #pragma comment(lib, "user32.lib")
    
    CVolumeSliderDialog::CVolumeSliderDialog(QWidget* parent) : QDialog(parent) {
        // 创建竖直滑动条并添加进竖直布局中
    	this->setFixedSize(40, 200);
    	QVBoxLayout* pVLay = new QVBoxLayout(this);
    	m_pSlider = new QSlider(this);
    	m_pSlider->setOrientation(Qt::Vertical);
    	pVLay->addWidget(m_pSlider);
    
        // 创建滑动按钮
    	setFixedSize(40, 120);
        setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);   // ToolTip : 悬浮是显示,离开时消失
        // 0.5 表示透明度,0 表示全透明、1 表示不透明;也可以使用百分比表示
        setStyleSheet("QDialog{background-color: rgba(54, 54, 54, 0.5);}");
    
    	connect(m_pSlider, &QSlider::valueChanged, [=](int value) {
    		emit sig_SliderValueChanged(value);
        });
    }
    
    CVolumeSliderDialog::~CVolumeSliderDialog() {}
    
    // 参考 qt 文档:bool QWidget::event(QEvent *event)
    // 设置 popup 后,dialog 有窗口阴影,需要去除就重写 event 函数
    bool CVolumeSliderDialog::event(QEvent* event) {
        static bool class_amended = false;
    
        if (event->type() == QEvent::WinIdChange) {
            HWND hwnd = (HWND)winId();
    
            if (class_amended == false) {
                class_amended = true;
                DWORD class_style = ::GetClassLong(hwnd, GCL_STYLE);
                class_style &= ~CS_DROPSHADOW;
                ::SetClassLong(hwnd, GCL_STYLE, class_style); // windows 系统函数
            }
        }
    
    	return QWidget::event(event);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    6. QCheckBox 实现打开、关闭状态按钮

    在这里插入图片描述

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        ui->checkBox->setFixedSize(128, 64);
    
        QString qss = "QCheckBox::indicator:unchecked{ \
            image:url(:/resources/status_close.png); \
            } \
            QCheckBox::indicator:checked { \
            image: url(:/resources/status_open.png); \
        }";
    
        ui->checkBox->setStyleSheet(qss);
        ui->checkBox->setChecked(true);
        //ui->checkBox->setTristate(true);
    
        connect(ui->checkBox, &QCheckBox::stateChanged, [=](int state){
            qDebug() << state;
        });
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    7. QComboBox 样式表

    在这里插入图片描述

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include 
    
    using namespace std;
    
    Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        QStringList strList;
        strList << "item1" << "item2" << "item3" << "item4"
                << "item1" << "item2" << "item3" << "item4"
                << "item1" << "item2" << "item3" << "item4"
                << "item1" << "item2" << "item3" << "item4";
    
        ui->comboBox->addItems(strList);
        // 将 QComboBox 的下拉列表视图设置为 QListView,并将此视图限定在当前的 QWidget 类的范围内显示
        ui->comboBox->setView(new QListView(this));
        ui->comboBox->setEditable(true);
        //ui->comboBox->insertSeparator(10);
        //ui->comboBox->insertSeparator(12);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • qss
    /* 未下拉时,QComboBox的样式 */
    QComboBox {
        border: 1px solid gray;   /* 边框 */
        border-radius: 5px;   /* 圆角 */
        padding: 1px 18px 1px 3px;   /* 字体填衬 */
        color: white;
        font: normal normal 24px "Microsoft YaHei";
        background:rgb(54,54,54);
    }
    
    /* 下拉后,整个下拉窗体样式 */
    QComboBox QAbstractItemView {
        outline: 0px solid gray;   /* 选定项的虚框 */
        border: 1px solid yellow;   /* 整个下拉窗体的边框 */
        color: rgb(250,251,252);
        background-color: rgb(70,80,90);   /* 整个下拉窗体的背景色 */
        selection-background-color: lightgreen;   /* 整个下拉窗体被选中项的背景色 */
    }
    
    /* 下拉后,整个下拉窗体每项的样式 */
    /* 项的高度(设置 ComboBox->setView(new QListView(this)); 后该项才起作用) */
    QComboBox QAbstractItemView::item {
        height: 50px;   
    }
    
    /* 下拉后,整个下拉窗体越过每项的样式 */
    QComboBox QAbstractItemView::item:hover {
        color: rgb(90,100,105);
        background-color: lightgreen;   /* 整个下拉窗体越过每项的背景色 */
    }
    
    /* 下拉后,整个下拉窗体被选择的每项的样式 */
    QComboBox QAbstractItemView::item:selected {
        color: rgb(12, 23, 34);
        background-color: lightgreen;
    }
    
    /* QComboBox中的垂直滚动条 */
    QComboBox QAbstractScrollArea QScrollBar:vertical {
        width: 13px;
        background-color: #d0d2d4;   /* 空白区域的背景色*/
    }
    
    QComboBox QAbstractScrollArea QScrollBar::handle:vertical {
        border-radius: 5px;   /* 圆角 */
        background: rgb(60,60,60);   /* 小方块的背景色深灰lightblue */
    }
    
    QComboBox QAbstractScrollArea QScrollBar::handle:vertical:hover {
        background: rgb(90, 91, 93);   /* 越过小方块的背景色yellow */
    }
    
    /* 设置为可编辑(setEditable(true))editable时,编辑区域的样式 */
    QComboBox:editable {
        background: green;
    }
    
    /* 设置为非编辑(setEditable(false))!editable时,整个QComboBox的样式 */
    QComboBox:!editable {
        background: rgb(54,54,54);
    }
    
    /* 设置为可编辑editable时,点击整个QComboBox的样式 */
    QComboBox:editable:on {
        background: rgb(54,54,54);
    }
    
    /* 设置为非编辑!editable时,点击整个QComboBox的样式 */
    QComboBox:!editable:on {
        background: rgb(54,54,54);
    }
    
    /* 设置为可编辑editable时,下拉框的样式 */
    QComboBox::drop-down:editable {
        background: rgb(54,54,54);
    }
    
    /* 设置为可编辑editable时,点击下拉框的样式 */
    QComboBox::drop-down:editable:on {
        background: rgb(54,54,54);
    }
    
    /* 设置为非编辑!editable时,下拉框的样式 */
    QComboBox::drop-down:!editable {
        background: rgb(54,54,54);
    }
    
    /* 设置为非编辑!editable时,点击下拉框的样式 */
    QComboBox::drop-down:!editable:on {
        background: rgb(54,54,54);
        image: url(:/resources/up.png); /* 显示上拉箭头 */ 
    }
    
    /* 下拉框样式 */
    QComboBox::drop-down {
        subcontrol-origin: padding;   /* 子控件在父元素中的原点矩形。如果未指定此属性,则默认为padding。 */
        subcontrol-position: top right;   /* 下拉框的位置(右上) */
        width: 32px;   /* 下拉框的宽度 */
    
        border-left-width: 1px;   /* 下拉框的左边界线宽度 */
        border-left-color: darkgray;   /* 下拉框的左边界线颜色 */
        border-left-style: solid;   /* 下拉框的左边界线为实线 */
        border-top-right-radius: 3px;   /* 下拉框的右上边界线的圆角半径(应和整个QComboBox右上边界线的圆角半径一致) */
        border-bottom-right-radius: 3px;   /* 同上 */
        image: url(:/resources/down.png); 
    }
    
    /* 越过下拉框样式 */
    QComboBox::drop-down:hover {
        background: rgb(80, 75, 90);
    }
    
    /* 下拉箭头样式 */ 
    QComboBox::down-arrow {  
        width: 32px; /* 下拉箭头的宽度(建议与下拉框drop-down的宽度一致) */   
        background: rgb(54,54,54); /* 下拉箭头的的背景色 */   
        padding: 0px 0px 0px 0px; /* 上内边距、右内边距、下内边距、左内边距 */  
        image: url(:/resources/down.png); 
    } 
    
    /* 点击下拉箭头 */ 
    QComboBox::down-arrow:on {   
        image: url(:/resources/up.png); /* 显示上拉箭头 */ 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124

    8. QProgressBar 用法及样式表

    在这里插入图片描述

    • widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    #include 
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class Widget; }
    QT_END_NAMESPACE
    
    class Widget : public QWidget {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    private slots:
        void on_btnStart_clicked();
        void on_btnStop_clicked();
    
    private:
        Ui::Widget *ui;
    
        QTimer *m_pTimer = nullptr;
    };
    #endif // WIDGET_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        m_pTimer = new QTimer(this);
    
        ui->progressBar->setValue(0);
        ui->progressBar->setRange(0, 100);
        ui->progressBar->setFormat("%p%");
        
        // lambda 表达式用于每个定时器超时时更新 QProgressBar 组件的当前进度值,其中的 step 变量用于存储当前进度值
        // 当定时器超时时,step 的值会自增 1,并将新的进度值设置到 QProgressBar 组件上
        connect(m_pTimer, &QTimer::timeout, [=]{
            static int step = 0;
            ui->progressBar->setValue(step++);
        });
    
        ui->progressBar_2->setOrientation(Qt::Vertical);
        ui->progressBar_2->setFixedWidth(60);
        ui->progressBar_2->setFixedHeight(300);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    void Widget::on_btnStart_clicked() {
        m_pTimer->start(50);
    }
    
    void Widget::on_btnStop_clicked() {
        m_pTimer->stop();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • qss
    QProgressBar {
          background:rgb(54,54,54);
          border:none;   /*无边框*/
          border-radius:5px;
          text-align:center;   /*文本的位置*/
          color: rgb(229, 229, 229);  /*文本颜色*/
    }
     
    QProgressBar::chunk  {
          background-color:rgb(58, 154, 255);
          border-radius:4px;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    QProgressBar:vertical {
    	border-radius:5px;
    	background-color:darkgray;
    	text-align:center;
    	padding-left: 5px; padding-right: 4px; padding-bottom: 2px; 
    }
    
    QProgressBar::chunk:vertical {
    	background-color:QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #00ff58,stop: 1 #034f1f);
    	margin:1px;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    9. QSlider 用法及样式表

    在这里插入图片描述

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include "qss.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        ui->hSlider->setStyleSheet(QString::fromStdString(hslider_qss));
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • qss.h
    #ifndef QSS_H
    #define QSS_H
    
    #include 
    
    using namespace std;
    
    string hslider_qss = R"(
        QSlider {
            background-color: #FF0000;
            border-style: outset;
            border-radius: 1px;
        }
    
        QSlider::groove:horizontal {
            height: 12px;
            background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);
            margin: 2px 0
        }
    
        QSlider::handle:horizontal {
            background: QRadialGradient(cx:0, cy:0, radius: 1, fx:0.5, fy:0.5, stop:0 white, stop:1 green);
            width: 16px;
            height: 16px;
            margin: -5px 6px -5px 6px;
            border-radius:11px;
            border: 3px solid #ffffff;
        }
    )";
    
    #endif // QSS_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    10. qss 加载方式详解

    • 方式一:在 qt 设计器里写

    • 方式二:C++ 代码写

      • QString 或 R 字符串
    • 方式三:写到 qss 文件里,读文件

      • 放到程序外部,暴露给用户
      • 加到 qrc 文件里,编译到 exe 里
    • widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
    #include 
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        QFile file(":/res/skin.qss");
    
        QString lineStr;
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QTextStream txtInput(&file);
            while (!txtInput.atEnd()) {
                lineStr += txtInput.readLine();  // 逐行读取 qss 代码
            }
        }
        file.close();
    
        this->setStyleSheet(lineStr);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • skin.css
    QWidget {
        background-color: rgb(54, 54, 54);
        border-top:2px;
        border-bottom:2px;
        border-left:2px;
        border-right:2px;
    }
     
    QLineEdit {
        background-color: rgb(249, 249, 249); 
        border: 1px solid black;
        border-radius:5;
        font:14px;
    }
     
    QLabel {
        background-color: rgb(54, 54, 54); 
        font:12px;
        color:white;
    }
     
    QPushButton {
        color:rgb(251,251,251);    
        font:12px, "微软雅黑";
        background-color:rgb(105, 105, 105);
        border-radius:4px;
    	padding:2px; 
    }
     
    QPushButton:hover {
        color:#0000ff;
        background-color:rgb(210, 205, 205); /*改变背景色*/
        border-style:inset;/*改变边框风格*/
        padding-left:2px;
        padding-top:2px;
    } 
     
    QPushButton:flat {  
        border:2px solid red;  
    } 
     
    QPushButton:pressed {
        color:green;
    } 
     
    QPlainTextEdit {
        background-color: rgb(169, 169, 169); 
        font:14px;
        color:white;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    11. 控件提升与自定义控件

    • 控件提升相当于把控件变成另一个控件,或者说称为自定义控件,控件提升需要在 qt 设计器里操作
    • 案例:按钮图片在上,文字在下

    在这里插入图片描述

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        ui->pushButton->setText("");
        ui->pushButton->setFixedSize(64, 88);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    • cmybutton.h
    #ifndef CMYBUTTON_H
    #define CMYBUTTON_H
    
    #include 
    #include 
    #include 
    
    class CMyButton : public QPushButton {
        Q_OBJECT
    
    public:
        CMyButton(QWidget *parent = nullptr);
        void set_Text(const QString& text);
    
    private:
        QLabel *m_pIconLabel;
        QLabel *m_pTextLabel;
    };
    
    #endif // CMYBUTTON_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • cmybutton.cpp
    #include "cmybutton.h"
    #include 
    
    CMyButton::CMyButton(QWidget *parent) : QPushButton(parent) {
        this->setFixedSize(64, 88);
        this->setText("");
    
        m_pTextLabel = new QLabel(this);
        m_pIconLabel->setFixedSize(64, 64);
        m_pIconLabel->setPixmap(QPixmap(":/resources/save.png"));
    
        m_pTextLabel = new QLabel(this);
        m_pTextLabel->setFixedSize(64, 24);
        m_pTextLabel->setText(u8"保存");
    
        QVBoxLayout* pVlay = new QVBoxLayout(this);
        pVlay->addWidget(m_pIconLabel);
        //pVlay->addSpacing(5);
        pVlay->addWidget(m_pTextLabel);
        pVlay->setContentsMargins(0, 0, 0, 0);
    }
    
    void CMyButton::set_Text(const QString& text) {
        m_pTextLabel->setText(text);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    12. Qt 鼠标、控件、窗口位置详解

    在这里插入图片描述

    • 桌面原点:在电脑桌面左上角(上图红点处)
    • 应用程序原点:在应用程序左上角
    • 坐标系一般都是 x 向左为正,y 向下为正
    • 绝对位置:相对于电脑桌面左上角的位置
    • 相对位置:相对于应用程序左上角的位置

    12.1 鼠标的位置

    • 获取鼠标相对于桌面左上角的绝对位置

      QCursor::pos()
      
      • 1
    • 获取 mousePressEvent 的参数 event 的位置

      event->pos()        // 鼠标相对于应用程序的位置,相对位置
      event->globalPos()  // 鼠标相对于桌面原点的位置,绝对位置
      
      • 1
      • 2

    12.2 控件的位置

    • 相对位置
      • 按钮相对于应用窗口原点的位置
      QPoint p = ui->pushButton->pos();
      
      • 1
    • 绝对位置
      • 按钮相对于桌面原点的位置
      QPoint p = ui->pushButton->mapToGlobal(QPoint(0, 0));
      
      • 1
    • 控件大小
      QRect rect = ui->pushButton->rect();
      
      • 1

    12.3 应用程序窗口的位置

    • 相对位置
      QRect rect = m_pDlg->pos();
      
      • 1
    • 绝对位置
      • 对话框相对于桌面原点的 rect
      QRect rect = m_pDlg->geometry();
      
      • 1
    • 应用窗口大小
      QRect rect = m_pDlg->rect();
      
      • 1

    12.4 案例

    在这里插入图片描述

    在这里插入图片描述

    • widget.cpp
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class Widget; }
    QT_END_NAMESPACE
    
    class Widget : public QWidget {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        void mousePressEvent(QMouseEvent *event) override;
    
    private:
        Ui::Widget *ui;
    };
    #endif // WIDGET_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include 
    #include "tempdialog.h"
    #include 
    
    using namespace std;
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        ui->pushButton->setFixedSize(100,200);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    void Widget::mousePressEvent(QMouseEvent *event) {
        qDebug() << QCursor::pos();  // 鼠标绝对位置
    
        qDebug() << "event->pos()         " << event->pos();
        qDebug() << "event->globalPos()   " << event->globalPos();
    }
    
    void Widget::on_pushButton_clicked() {
        qDebug() << u8"控件相对位置" << ui->pushButton->pos();
    
        QPoint jPos = ui->pushButton->mapToGlobal(QPoint(0,0));
        qDebug() << u8"控件绝对位置" << jPos;
    
    
        QRect rect = ui->pushButton->rect();
        qDebug() << rect;
    
        qDebug() << u8"窗口绝对位置" << this->geometry();  // 绝对位置
        qDebug() << u8"窗口矩形" << this->rect();
    
        //TempDialog *dlg = new TempDialog(this);
        std::unique_ptr<TempDialog> dlg(new TempDialog(this));
    
        dlg->move(jPos.x() - dlg->width(), jPos.y());
    
        dlg->exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • tempdialog.h
    #ifndef TEMPDIALOG_H
    #define TEMPDIALOG_H
    
    #include 
    
    namespace Ui {
        class TempDialog;
    }
    
    class TempDialog : public QDialog {
        Q_OBJECT
    
    public:
        explicit TempDialog(QWidget *parent = nullptr);
        ~TempDialog();
    
    private:
        Ui::TempDialog *ui;
    };
    
    #endif // TEMPDIALOG_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • tempdialog.cpp
    #include "tempdialog.h"
    #include "ui_tempdialog.h"
    #include 
    
    TempDialog::TempDialog(QWidget *parent) : QDialog(parent), ui(new Ui::TempDialog) {
        ui->setupUi(this);
    }
    
    TempDialog::~TempDialog() {
        delete ui;
        qDebug() << "123456";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    13. 自定义 QLineEdit 实现搜索编辑框

    在这里插入图片描述

    13.1 主窗口

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include "csearchlineedit.h"
    #include 
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        this->setStyleSheet("background-color:#1A1E21");
    
        // 创建搜索栏实例化对象 pEdit
        CSearchLineEdit* pEdit = new CSearchLineEdit(this);
    
        QVBoxLayout* pVLay = new QVBoxLayout(this);
        pVLay->addWidget(pEdit);
    
        // 链接 搜索栏 搜索信号与 主窗口 控制台打印槽函数
        connect(pEdit, &CSearchLineEdit::sig_Search, this, &Widget::onSearch);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    // 在控制台打印搜索的内容
    void Widget::onSearch(const QString& text) {
        qDebug() << u8"搜索的内容是 " << text;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    13.2 搜索输入栏

    • csearchlineedit.h
    #ifndef CSEARCHLINEEDIT_H
    #define CSEARCHLINEEDIT_H
    
    #include 
    #include 
    #include "csearchbutton.h"
    
    class CSearchLineEdit : public QLineEdit {
        Q_OBJECT
    
    public:
        CSearchLineEdit(QWidget *parent = nullptr);
    
    signals:
        void sig_Search(const QString& text);
    
    private:
        CSearchButton* m_pBtn = nullptr;
    };
    
    #endif // CSEARCHLINEEDIT_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • csearchlineedit.cpp
    #include "csearchlineedit.h"
    #include 
    #include 
    
    using namespace std;
    
    CSearchLineEdit::CSearchLineEdit(QWidget *parent) : QLineEdit(parent) {
        // 将当前的窗口部件设置为使用样式背景
        this->setAttribute(Qt::WA_StyledBackground);
    
        string qss = R"(
            QLineEdit{
                background-color:#33373E;             /* 背景颜色 */
                border: 1px solid #33373E;            /* 边框宽度为1px,颜色为#A0A0A0 */
                border-radius: 20px;                  /* 边框圆角 */
                padding-left: 10px;                   /* 文本距离左边界有5px */
                color: #FFFFFF;                       /* 文本颜色 */
                selection-background-color: #A0A0A0;  /* 选中文本的背景颜色 */
                selection-color: #F2F2F2;             /* 选中文本的颜色 */
                font-family: \"Microsoft YaHei\";     /* 文本字体族 */
                font-size:18px;                       /* 文本字体大小 */
            }
        )";
    
        this->setStyleSheet(QString::fromStdString(qss));
        this->setPlaceholderText(u8"请输入搜索内容");  // 只要行编辑为空,行编辑就会显示一个变灰显示占位符文本
    
        this->setFixedHeight(40);
        this->setMinimumWidth(400);
    
        // 创建搜索按钮实例化对象 m_pBtn
        m_pBtn = new CSearchButton(this);
    
        QHBoxLayout* pHlay = new QHBoxLayout(this);
        pHlay->addStretch();  // 添加弹簧挤压占位
        pHlay->addWidget(m_pBtn);
        // 设置控件周围边框大小
        pHlay->setContentsMargins(0, 0, 0, 0);
        // 设置文本周围的边距
        this->setTextMargins(10, 0, 130 + 5, 0);
    
        // 链接 搜索按钮点击信号 与 搜索栏 搜索信号
        connect(m_pBtn, &CSearchButton::clicked, [=]{
            emit sig_Search(this->text());
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    13.3 搜索按钮

    • csearchbutton.h
    #ifndef CSEARCHBUTTON_H
    #define CSEARCHBUTTON_H
    
    #include 
    #include 
    
    class CSearchButton : public QPushButton {
        Q_OBJECT
    
    public:
        CSearchButton(QWidget *parent = nullptr);
    
    private:
        void normalStyle();  // 按钮控件默认样式
    
    protected:
        // 鼠标进入事件
        void enterEvent(QEvent *event) override;
        // 鼠标离开事件
        void leaveEvent(QEvent *event) override;
    };
    
    #endif // CSEARCHBUTTON_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • csearchbutton.cpp
    #include "csearchbutton.h"
    #include 
    
    using namespace std;
    
    CSearchButton::CSearchButton(QWidget *parent) : QPushButton(parent) {
        this->setAttribute(Qt::WA_StyledBackground);
    
        this->setFixedHeight(40);
    
        normalStyle();  // 设置默认样式
    }
    
    // 鼠标进入按钮控件时触发的事件
    void CSearchButton::enterEvent(QEvent *event) {
        string qss = R"(QPushButton{
            background-color:#148AFF;
            background-image: url(:/resources/search.png);
            background-repeat: no-repeat;
            background-position:left;
            background-origin:content;
            padding-left:15px; /*图片相对于左边的偏移*/
            text-align:right;  /*文本的对齐方式*/
            padding-right:15px; /*文本相对于右边的偏移*/
            border-radius:20px;
            color:#FFFFFF;
            font-family: \"Microsoft YaHei\";
            font-size: 20px;
        })";
    
        this->setStyleSheet(QString::fromStdString(qss));
    
        this->setFixedWidth(130);
        this->setText(u8"搜全网");
    }
    
    // 鼠标离开按钮控件时触发的事件
    void CSearchButton::leaveEvent(QEvent *event) {
        normalStyle();
    }
    
    // 鼠标离开按钮控件时的 默认样式
    void CSearchButton::normalStyle() {
        string qss = R"(QPushButton{
            background-color:#148AFF;
            background-image: url(:/resources/search.png);
            background-repeat: no-repeat;
            background-position: center;
            border-radius:20px;
        })";
    
        this->setStyleSheet(QString::fromStdString(qss));
    
        this->setFixedWidth(60);
        this->setText(u8"");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    14. 自定义 QTabWidget 实现 tab 在左,文本水平

    在这里插入图片描述

    14.1 主窗口

    • widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include 
    #include "tabwidget.h"
    
    Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
        ui->setupUi(this);
    
        // 创建 标签窗口 实例对象
        TabWidget *tabWidget = new TabWidget(this);
    
        // 分别插入三个标签页
        QWidget* w1 = new QWidget;
        w1->setStyleSheet("background-color:rgb(54,54,54)");
        // int insertTab(int index, QWidget *widget, const QString &);
        tabWidget->insertTab(0, w1, u8"参数设置");
    
        QWidget* w2 = new QWidget;
        w2->setStyleSheet("background-color:rgb(154,54,54)");
        tabWidget->insertTab(1, w2, u8"设备管理");
    
        QWidget* w3 = new QWidget;
        w3->setStyleSheet("background-color:rgb(154,54,154)");
        tabWidget->insertTab(2, w3, u8"设备管理");
    
        QHBoxLayout* hLay = new QHBoxLayout(this);
        hLay->addWidget(tabWidget);
    }
    
    Widget::~Widget() {
        delete ui;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    14.2 标签窗口

    • tabwidget.cpp
    #include "tabwidget.h"
    #include 
    
    using namespace std;
    
    TabWidget::TabWidget(QWidget *parent): QTabWidget(parent) {
        // 创建一个新的选项卡栏对象,并将其设置为当前的选项卡栏
        this->setTabBar(new TabBar);
        // 将选项卡位置设置为西边(左侧)
        this->setTabPosition(QTabWidget::West);
    
        // 注意在 QTabBar::tab 里不能设置 tab 的大小,否则自定义的 TabBar 无效
        string qss = R"(
            QTabWidget::pane {
                border-top:1px solid #EAEAEA;
                position:absolute;
                top:-0.1px;
            }
    
            QTabBar::tab {
                font-size:18px;
                font-family:Microsoft YaHei;
                font-weight:400;
                background:#FFFFFF;
                border:2px solid #FFFFFF;
                border-bottom-color:#FFFFFF;
                border-top-left-radius:4px;
                border-top-right-radius:4px;
                padding:2px;
            }
    
            QTabBar::tab:selected {
                color:#333333;
                border-color:#FFFFFF;
                border-bottom-color:#4BA4F2;
            }
    
            QTabBar::tab:!selected {
                color:#B2B2B2;
                border-color:#FFFFFF;
                border-bottom-color:#FFFFFF;
            }
        )";
    
        this->setStyleSheet(QString::fromStdString(qss));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    14.3 标签栏

    • tabbar.h
    #ifndef TABBAR_H
    #define TABBAR_H
    
    #include 
    
    class TabBar : public QTabBar {
    public:
        TabBar(QWidget* parent = nullptr);
    
        QSize tabSizeHint(int index) const override;
    
    protected:
        void paintEvent(QPaintEvent *event) override;
    };
    
    #endif // TABBAR_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • tabbar.cpp
    #include "tabbar.h"
    #include 
    #include 
    
    TabBar::TabBar(QWidget* parent) : QTabBar(parent) {}
    
    // 获取原始选项卡的大小建议,交换宽度和高度,再返回修改后的大小建议,表达了对选项卡大小的自定义设置
    QSize TabBar::tabSizeHint(int index) const {
        QSize s = QTabBar::tabSizeHint(index);
        s.transpose();
    
        // 设置每个 tabBar 中 item 的大小
        // 注意在 qss QTabBar::tab 里不能设置 tab 的大小,否则自定义的 TabBar 无效
        s.rwidth() = 90;
        s.rheight() = 44;
        return s;
    }
    
    // 绘制标签栏,将标签栏的形状绘制为横向的条形,标签内容垂直显示
    void TabBar::paintEvent(QPaintEvent *event) {
        // QStylePainter 类用于 widget 窗口内部绘制 QStyle 元素
        QStylePainter painter(this);
        // QStyleOptionTab 类用于描述 标签栏 的参数
        QStyleOptionTab opt;
    
        for (int i = 0; i < count(); i++) {
            initStyleOption(&opt, i);  // i 为标签栏索引
            painter.drawControl(QStyle::CE_TabBarTabShape, opt);  // 绘制标签栏的形状
            painter.save();  // 保存当前绘图状态
    
            // 根据 opt.rect 的大小创建一个矩形 r,并将其移动到 opt.rect 的中心位置
            QSize s = opt.rect.size();
            s.transpose();
            QRect r(QPoint(), s);
            r.moveCenter(opt.rect.center());
            opt.rect = r;
    
            // 将绘图原点移到当前标签的中心位置,然后旋转 90 度,再将绘图原点移回初始位置
            QPoint c = tabRect(i).center();
            painter.translate(c);
            painter.rotate(90);
            painter.translate(-c);
            painter.drawControl(QStyle::CE_TabBarTabLabel, opt);  // 绘制标签栏的标签
            painter.restore();  // 恢复之前保存的绘图状态
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    c++11 智能指针 (std::shared_ptr)(三)
    Flink之窗口指派API模板
    FS2K人脸素描属性识别
    深夜学习:有关Inner、Outer等相关词汇的理解
    iOS小技能:去掉/新增导航栏黑边(iOS13适配)
    MongoDB的安装配置及使用(WIndows/Java)
    Qt 实战(4)信号与槽 | 4.1、信号与槽机制
    BDD - BDD Automation Framwork 自动化框架
    Ubuntu中用useradd创建用户时没指定家目录和shell版本,就不能su切换到新用户
    MediaSoup简介
  • 原文地址:https://blog.csdn.net/qq_42994487/article/details/134281475