zoukankan      html  css  js  c++  java
  • Qt 自定义标题栏

    1 头文件

    #ifndef TITLEBAR_H
    #define TITLEBAR_H
    
    #include <QLabel>
    #include <QPushButton>
    #include "ui_TitleBar.h"
    
    class  TitleBar : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit TitleBar(QWidget *parent = nullptr);
        ~TitleBar();
        void setMiniBtnIcon(const QIcon& icon);
        void setMaxiBtnIcon(const QIcon& icon);
        void setCloseBtnIcon(const QIcon& icon);
    protected:
        //鼠标双击事件
        virtual void mouseDoubleClickEvent(QMouseEvent *event);
        //鼠标按下事件
        virtual void mousePressEvent(QMouseEvent *event);
        //鼠标释放事件
        virtual void mouseReleaseEvent(QMouseEvent *event);
        //鼠标移动事件
        virtual void mouseMoveEvent(QMouseEvent *event);
        //设置界面标题与图标
        virtual bool eventFilter(QObject *obj, QEvent *event);
    
    private slots:
    
        //进行最小化、最大化/还原、关闭操作
        void onClicked();
    private:
    
        //最大化/还原
        void updateMaximize();
    
    private:
        Ui::TitleBar ui;
        QPoint pos;        //鼠标当前点击坐标
        bool mouse_press; //鼠标按下 
    };
    
    #endif // TitleBar_H

    2 cpp文件

    #include <QLabel>
    #include <QPushButton>
    #include <QHBoxLayout>
    #include <QEvent>
    #include <QMouseEvent>
    #include <QApplication>
    #include "TitleBar.h"
    
    //调用WIN API
    #ifdef Q_OS_WIN
    #include <qt_windows.h>
    #endif
    
    TitleBar::TitleBar(QWidget *parent)
        : QWidget(parent) {
        ui.setupUi(this);
        mouse_press = false;
        //setFixedHeight(30);
        // 设置窗口背景透明;
        //setAttribute(Qt::WA_TranslucentBackground);
        //给按钮设置静态tooltip,当鼠标移上去时显示tooltip
        ui.btnMinimize->setToolTip(tr("Minimize"));
        ui.btnMaximize->setToolTip(tr("Maximize"));
        ui.btnClose->setToolTip(tr("Close"));
    
        QPalette pal(palette());
        pal.setColor(QPalette::Background, QColor(150, 150, 150));
        setAutoFillBackground(true);
        setPalette(pal);
    
        connect(ui.btnMinimize, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
        connect(ui.btnMaximize, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
        connect(ui.btnClose, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
    
        //隐藏更换皮肤按钮
        ui.btnSkin->setVisible(false);
    
        setAttribute(Qt::WA_StyledBackground);
    
    
    }
    
    TitleBar::~TitleBar() {
    
    }
    //双击标题栏进行界面的最大化/还原
    void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) {
        Q_UNUSED(event);
    
        emit ui.btnMaximize->clicked();
    }
    
    void TitleBar::mousePressEvent(QMouseEvent *event) {
        if (event->button() == Qt::LeftButton) {
            mouse_press = true;
    
            pos = event->globalPos();
        }
        event->ignore();
    }
    
    void TitleBar::mouseMoveEvent(QMouseEvent *event) {
        //若鼠标左键被按下
        if (mouse_press) {
            QPoint move_pos = event->globalPos()-pos;   //鼠标现在位置-原来位置
            //移动主窗体
            window()->move(window()->pos() + move_pos);//窗口位置+鼠标移动距离
            pos = event->globalPos();                 //更新位置
        }
        event->ignore();
    }
    
    void TitleBar::mouseReleaseEvent(QMouseEvent *event) {
        //设置鼠标为未被按下
        mouse_press = false;
        event->ignore();
    }
    //使用事件过滤器监听标题栏所在的窗体,所以当窗体标题、图标等信息发生改变时,标题栏也应该随之改变
    bool TitleBar::eventFilter(QObject *obj, QEvent *event) {
        switch (event->type()) {         //判断发生事件的类型
        case QEvent::WindowTitleChange: { //窗口标题改变事件
            QWidget *pWidget = qobject_cast<QWidget *>
                               (obj); //获得发生事件的窗口对象
            if (pWidget) {
                //窗体标题改变,则标题栏标题也随之改变
                ui.labelTitle->setText(pWidget->windowTitle());
                return true;
            }
        }
        break;
    
        case QEvent::WindowIconChange: { //窗口图标改变事件
            QWidget *pWidget = qobject_cast<QWidget *>(obj);
            if (pWidget) {
                //窗体图标改变,则标题栏图标也随之改变
                QIcon icon = pWidget->windowIcon();
    //            ui.labelIcon->setPixmap(icon.pixmap(ui.labelIcon->size()));
                return true;
            }
        }
        break;
    
        case QEvent::Resize:
            updateMaximize(); //最大化/还原
            return true;
    
        default:
            return QWidget::eventFilter(obj, event);
        }
    
        return QWidget::eventFilter(obj, event);
    }
    //进行最小化、最大化/还原、关闭操作
    void TitleBar::onClicked() {
        QPushButton *pButton = qobject_cast<QPushButton *>(sender());
    
        QWidget *pWindow = this->window(); //获得标题栏所在的窗口
    
        if (pWindow->isTopLevel()) {
            if (pButton == ui.btnMinimize) {
                pWindow->showMinimized(); //窗口最小化显示
            } else if (pButton == ui.btnMaximize) {
                pWindow->isMaximized() ? pWindow->showNormal() :
                pWindow->showMaximized();  //窗口最大化/还原显示
            } else if (pButton == ui.btnClose) {
                pWindow->close();       //窗口关闭
            }
        }
    }
    
    //最大化/还原
    void TitleBar::updateMaximize() {
        QWidget *pWindow = this->window();           //获得标题栏所在的窗口
    
        if (pWindow->isTopLevel()) {
            bool bMaximize =
                pWindow->isMaximized(); //判断窗口是不是最大化状态,是则返回true,否则返回false
            if (bMaximize) {
                //目前窗口是最大化状态,则最大化/还原的toolTip设置为"Restore"
                ui.btnMaximize->setToolTip(tr("Restore"));
                //设置按钮的属性名为"maximizeProperty"
                ui.btnMaximize->setProperty("maximizeProperty", "restore");
            } else {
                //目前窗口是还原状态,则最大化/还原的toolTip设置为"Maximize"
                ui.btnMaximize->setToolTip(tr("Maximize"));
                //设置按钮的属性名为"maximizeProperty"
                ui.btnMaximize->setProperty("maximizeProperty", "maximize");
            }
    
            ui.btnMaximize->setStyle(QApplication::style());
        }
    }
    
    
    void TitleBar::setMiniBtnIcon(const QIcon& icon) {
        ui.btnMinimize->setIcon(icon.pixmap(ui.btnMinimize->size()));
    }
    
    void TitleBar::setMaxiBtnIcon(const QIcon& icon) {
        ui.btnMaximize->setIcon(icon.pixmap(ui.btnMaximize->size()));
    }
    
    void TitleBar::setCloseBtnIcon(const QIcon& icon) {
        ui.btnClose->setIcon(icon.pixmap(ui.btnClose->size()));
    }

    3 使用说明

    自定义标题栏使用说明(包含TitleBar.h,TitleBar.cpp,TitleBar.ui三个文件):
    1主窗体类中添加头文件:
    //调用WIN API需要用到的头文件 [实现缩放]
    #ifdef Q_OS_WIN
    #include <qt_windows.h>
    #include <Windowsx.h>
    #endif
    
    2主窗体类中
       添加成员变量:
     int m_nBorderWidth;//表示鼠标位于边框缩放范围的宽度
       添加成员函数:
    //nativeEvent主要用于进程间通信-消息传递,使用这种方式后来实现窗体的缩放 
    bool xxx::nativeEvent(const QByteArray &eventType, void *message, long *result)
    {
        Q_UNUSED(eventType)
    
            MSG *param = static_cast<MSG *>(message);
    
        switch (param->message)
        {
        case WM_NCHITTEST:
        {
            int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();
            int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();
    
            // 如果鼠标位于子控件上,则不进行处理
            if (childAt(nX, nY) != nullptr)
                return QWidget::nativeEvent(eventType, message, result);
    
            *result = HTCAPTION;
    
            // 鼠标区域位于窗体边框,进行缩放
            if ((nX > 0) && (nX < m_nBorderWidth))
                *result = HTLEFT;
    
            if ((nX > this->width() - m_nBorderWidth) && (nX < this->width()))
                *result = HTRIGHT;
    
            if ((nY > 0) && (nY < m_nBorderWidth))
                *result = HTTOP;
    
            if ((nY > this->height() - m_nBorderWidth) && (nY < this->height()))
                *result = HTBOTTOM;
    
            if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0)
                && (nY < m_nBorderWidth))
                *result = HTTOPLEFT;
    
            if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
                && (nY > 0) && (nY < m_nBorderWidth))
                *result = HTTOPRIGHT;
    
            if ((nX > 0) && (nX < m_nBorderWidth)
                && (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
                *result = HTBOTTOMLEFT;
    
            if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
                && (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
                *result = HTBOTTOMRIGHT;
    
            return true;
        }
        }
    
        return QWidget::nativeEvent(eventType, message, result);
    }
    
    3 在widget中应用自定义标题栏
    (1)在需要添加自定义标题栏的widget的ui文件中,拖动一个widget加入到当前widget布局的最上方,然后提升控件类为TitleBar
    (2)主窗体类的构造函数中添加如下代码:
    
    //Qt::FramelessWindowHint设置窗口标志为无边框,而Qt::WindowStaysOnTopHint使窗口位于所有界面之上
    setWindowFlags(Qt::FramelessWindowHint);
    //ui中提升控件
    installEventFilter(ui.widget);//ui.widget 为布局中提升的自定义标题控件
     //设置标题栏标题 图标 按钮图标,可在ui文件中直接修改,也可在代码中修改
    setWindowTitle("Custom Window");
    setWindowIcon(QIcon(""));
    ui.widget->setMiniBtnIcon(QIcon(""));
    ui.widget->setMaxiBtnIcon(QIcon(""));
    ui.widget->setCloseBtnIcon(QIcon(""));
    m_nBorderWidth= 5;
    
    4 在mainwindow中应用自定义标题栏
    (1)新建一个widget,拖动一个子widget到当前widget布局的最上放,提升控件为TitleBar
    (2) 在当前widget的类中添加头文件,成员变量和成员函数,同上
    (3)在当前widget的构造函数中添加如下代码
    //Qt::FramelessWindowHint设置窗口标志为无边框,而Qt::WindowStaysOnTopHint使窗口位于所有界面之上
    setWindowFlags(Qt::FramelessWindowHint);
    //ui中提升控件
    installEventFilter(ui.widget);//ui.widget 为布局中提升的自定义标题控件
     //设置标题栏标题 图标 按钮图标,可在ui文件中直接修改,也可在代码中修改
    /*
    setWindowTitle("Custom Window");
    setWindowIcon(QIcon(""));
    ui.widget->setMiniBtnIcon(QIcon(""));
    ui.widget->setMaxiBtnIcon(QIcon(""));
    ui.widget->setCloseBtnIcon(QIcon(""));
    */
    m_nBorderWidth= 5;
    
    //MainWindow为需要添加自定义标题栏的主界面类
    MainWindow *maindow = new MainWindow(this);
    maindow->setWindowFlags(Qt::FramelessWindowHint);
    
    /*
    QVBoxLayout *vlayout = new QVBoxLayout;
    vlayout->addWidget(ui.titlebar_widget_);
    QString path = QStringLiteral(":/png/最小化.png");
    QIcon minicon(path);
    ui.titlebar_widget_->setMiniBtnIcon(minicon);
    path = QStringLiteral(":/png/窗口.png");
    QIcon maxicon(path);
    ui.titlebar_widget_->setMaxiBtnIcon(maxicon);
    path = QStringLiteral(":/png/关  闭.png");
    QIcon closeicon(path);
    ui.titlebar_widget_->setCloseBtnIcon(closeicon);
    
    QString filestyle =
        QStringLiteral("background-image: url(:/png/标题栏-背景.png);");
    ui.titlebar_widget_->setStyleSheet(filestyle);
    */
    
    QVBoxLayout *vlayout = new QVBoxLayout;
    vlayout->addWidget(ui.titlebar_widget_);
    vlayout->addWidget(maindow);
    //设置布局距离上下左右的距离,根据需要设置,也可在ui中修改
    vlayout->setContentsMargins(2,1,2,1);
    setLayout(vlayout);
    
    (4)在显示主界面的时候,在main函数中将MainWindow类换为新加的widget,即可显示自定义标题栏

     4 ui文件见上传文件

  • 相关阅读:
    队列的python实现
    MySQL主从复制原理的是啥?
    Centos7 将应用添加快捷方式到applications 中以pycham为例[ubuntu]适用
    Centos7 虚拟环境安装Django 出现ImproperlyConfigured('SQLite 3.8.3 or later is required (found %s).' %Database.sqlite_version)错误
    Centos7 安装virtualenv bash: virtualenv: command not found...的解决
    Flask学习之 Jinja2模板引擎
    Flask学习之 Flask-Script 扩展
    Flask学习之 请求钩子
    VUE项目部署公网ip和端口以及使用域名访问配置
    Android app图标总是显示默认的机器人图标,且在manifest文件的application中修改无效...
  • 原文地址:https://www.cnblogs.com/LuckCoder/p/11195704.html
Copyright © 2011-2022 走看看