• Qt自定义标题栏


    效果如下:
    在这里插入图片描述
    代码如下:

    // 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();
    protected:
        bool nativeEvent(const QByteArray&eventType,void *message,long*result) override;
    private slots:
        void on_close();
    
    private:
        void mousePressEvent(QMouseEvent*ev);
        void mouseMoveEvent(QMouseEvent*ev);
        QPoint pos;
    private:
        Ui::Widget *ui;
    
        int m_BorderWidth  =5;
    };
    
    //2、titlebar
    #ifndef CTABTITLEWIDGET_H
    #define CTABTITLEWIDGET_H
    
    #include 
    #include 
    #include
    
    class CTabTitleWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit CTabTitleWidget(QWidget *parent = nullptr);
        ~CTabTitleWidget();
    
        void setEmptyWidgetWidth(int w);
    
    protected:
        void paintEvent(QPaintEvent*event);
        void mousePressEvent(QMouseEvent*ev);
        void mouseDoubleClickEvent(QMouseEvent*event);
    
    
    signals:
        void sig_close();
        void sig_addtab();
    private slots:
        void on_clicked();
    
    private:
        QPushButton* m_pAddBtn = nullptr;
        QWidget*     m_pEmptyWidget = nullptr;
        QPushButton* m_pUserBtn = nullptr;
        QPushButton* m_pMinBtn = nullptr;
        QPushButton* m_pMaxBtn = nullptr;
        QPushButton* m_pCloseBtn = nullptr;
    };
    
    #endif // CTABTITLEWIDGET_H
    
    #endif // WIDGET_H
    
    //3.tabbrowser
    #ifndef TABBROWSER_H
    #define TABBROWSER_H
    
    #include 
    #include 
    #include 
    #include 
    #include "ctabtitlewidget.h"
    class tabbrowser : public QTabWidget
    {
        Q_OBJECT
    public:
        explicit tabbrowser(QWidget *parent = nullptr);
    
        enum TAB_FLAG
        {
            NEW,
            CLOSE,
            NORMAL,
            SPECIAL
        };
    
    protected:
        void resizeEvent(QResizeEvent*ev) override;
    
    private:
        void initTabWidget();
        void setTabBarFlag(TAB_FLAG);
        void createTabMenu();
    
    private slots:
        void on_newTab();
        void on_closeTab(int index);
        void onMenuShow(const QPoint&pos);
        void on_closeAllTab();
    
    private:
        CTabTitleWidget*m_pRightWidget = nullptr;
        QMenu* m_pTabMenu = nullptr;
    signals:
        void sig_close();
    
    };
    
    #endif // TABBROWSER_H
    
    
    
    .cpp
    /./1.widget.cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include "tabbrowser.h"
    #ifdef Q_OS_WIN
    #include 
    #include 
    #include 
    #include 
    #include 
    #endif
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        // 设置窗口为无边框
        setWindowFlag(Qt::FramelessWindowHint);
        setStyleSheet("background-color:#E3E4E7;");
    
        // 创建一个新的 tabbrowser 实例,并将其设置为此窗口的小部件
        tabbrowser* pTab = new tabbrowser(this);
    
        // 创建一个水平布局,并将 tabbrowser 添加到布局中
        QHBoxLayout* pHLay = new QHBoxLayout(this);
        pHLay->addWidget(pTab);
        pHLay->setContentsMargins(6, 6, 6, 6);
        setLayout(pHLay);
    
        // 连接 tabbrowser 的关闭信号到此窗口的 on_close 槽函数
        connect(pTab, &tabbrowser::sig_close, this, &Widget::on_close);
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    // 处理自定义窗口行为的原生事件(例如,调整大小和移动)
    bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
    {
        Q_UNUSED(eventType)
    
        MSG* param = static_cast(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);
    
            // 当鼠标靠近边框时,进行调整大小操作
            if ((nX > 0) && (nX < m_BorderWidth))
                *result = HTLEFT;
    
            if ((nX > this->width() - m_BorderWidth) && (nX < this->width()))
                *result = HTRIGHT;
    
            if ((nY > 0) && (nY < m_BorderWidth))
                *result = HTTOP;
    
            if ((nY > this->height() - m_BorderWidth) && (nY < this->height()))
                *result = HTBOTTOM;
    
            if ((nX > 0) && (nX < m_BorderWidth) && (nY > 0) && (nY < m_BorderWidth))
                *result = HTTOPLEFT;
    
            if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > 0) && (nY < m_BorderWidth))
                *result = HTTOPRIGHT;
    
            if ((nX > 0) && (nX < m_BorderWidth) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))
                *result = HTBOTTOMLEFT;
    
            if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))
                *result = HTBOTTOMRIGHT;
    
            return true;
        }
        }
    
        return QWidget::nativeEvent(eventType, message, result);
    }
    
    // 处理关闭信号的槽函数
    void Widget::on_close()
    {
        close();
    }
    
    // 处理鼠标按下事件以移动窗口
    void Widget::mousePressEvent(QMouseEvent *ev)
    {
        if (Qt::LeftButton == ev->button())
        {
            // 计算鼠标相对于窗口左上角的位置
            pos = ev->globalPos() - frameGeometry().topLeft();
            ev->accept();
        }
    }
    
    // 处理鼠标移动事件以移动窗口
    void Widget::mouseMoveEvent(QMouseEvent *ev)
    {
        if (Qt::LeftButton & ev->buttons())
        {
            // 移动窗口到鼠标移动后的位置
            move(ev->globalPos() - pos);
            ev->accept();
        }
    }
    
    
    

    //2.titlebar
    #include “CTabTitleWidget.h”

    #include
    #include
    #include
    #include

    #ifdef Q_OS_WIN
    #include
    #pragma comment(lib, “user32.lib”)
    #endif
    CTabTitleWidget::CTabTitleWidget(QWidget *parent)
    : QWidget{parent}
    {
    setStyleSheet(“background-color:#E3E4E7”);
    m_pAddBtn = new QPushButton(this);
    m_pAddBtn->setFlat(true);
    m_pAddBtn->setFixedSize(32, 32);
    m_pAddBtn->setStyleSheet(“background-image:url(:/resources/add.svg)”);

    m_pEmptyWidget = new QWidget(this);
    
    m_pUserBtn = new QPushButton(this);
    m_pUserBtn->setFlat(true);
    m_pUserBtn->setFixedSize(32, 32);
    m_pUserBtn->setStyleSheet("background-image:url(:/resources/user)");
    
    m_pMinBtn = new QPushButton(this);
    m_pMinBtn->setFlat(true);
    m_pMinBtn->setFixedSize(32, 32);
    m_pMinBtn->setStyleSheet("background-image:url(:/resources/min.svg)");
    
    m_pMaxBtn = new QPushButton(this);
    m_pMaxBtn->setFlat(true);
    m_pMaxBtn->setFixedSize(32, 32);
    m_pMaxBtn->setStyleSheet("background-image:url(:/resources/max.svg)");
    
    m_pCloseBtn = new QPushButton(this);
    m_pCloseBtn->setFlat(true);
    m_pCloseBtn->setFixedSize(32, 32);
    m_pCloseBtn->setStyleSheet("background-image:url(:/resources/close.svg)");
    
    QHBoxLayout* pHLay = new QHBoxLayout(this);
    pHLay->addWidget(m_pAddBtn);
    pHLay->addWidget(m_pEmptyWidget);
    this->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
    pHLay->addWidget(m_pUserBtn);
    pHLay->addSpacing(8);
    pHLay->addWidget(m_pMinBtn);
    pHLay->addWidget(m_pMaxBtn);
    pHLay->addWidget(m_pCloseBtn);
    pHLay->setContentsMargins(1, 0, 1, 3);
    setLayout(pHLay);
    
    connect(m_pAddBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
    connect(m_pMinBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
    connect(m_pMaxBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
    connect(m_pCloseBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
    

    }

    CTabTitleWidget::~CTabTitleWidget()
    {

    }

    void CTabTitleWidget::setEmptyWidgetWidth(int w)
    {
    m_pEmptyWidget->setMinimumWidth(w);
    }

    void CTabTitleWidget::paintEvent(QPaintEvent *event)
    {
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    QWidget::paintEvent(event);
    }

    void CTabTitleWidget::mousePressEvent(QMouseEvent ev)
    {
    if(ReleaseCapture())
    {
    QWidget
    win = this->window();
    if(win->isTopLevel())
    {
    SendMessage(HWND(win->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
    }
    }
    ev->ignore();
    }

    void CTabTitleWidget::mouseDoubleClickEvent(QMouseEvent *event)
    {
    emit m_pMaxBtn->clicked();
    }

    void CTabTitleWidget::on_clicked()
    {
    QPushButtonbtn = qobject_cast>(sender());
    QWidget*win = this->window();
    if(win->isTopLevel())
    {
    if (btn == m_pAddBtn)
    {
    emit sig_addtab();
    }
    else if (btn == m_pMinBtn)
    {
    win->showMinimized();
    }
    else if (btn == m_pMaxBtn)
    {
    win->isMaximized() ? win->showNormal() : win->showMaximized();
    }
    else if (btn == m_pCloseBtn)
    {
    emit sig_close();
    }
    }
    }
    //3.tabbrowser
    #include “tabbrowser.h”
    #include
    #include
    #include
    #include
    #include

    QString qss0 = “QTabBar::tab{
    font: 75 12pt Arial;
    text-align:left;
    width:184px;
    height:32;
    background:#FFFFFF;
    border:2px solid #FFFFFF;
    border-bottom-color:#FFFFFF;
    border-top-left-radius:4px;
    border-top-right-radius:4px;
    padding:2px;
    margin-top:0px;
    margin-right:1px;
    margin-left:1px;
    margin-bottom:0px;}
    QTabBar::tab:selected{
    color:#333333; /文字颜色/
    background-color:#FFFFFF;}
    QTabBar::tab:!selected{
    color:#B2B2B2;
    border-color:#FFFFFF;}
    QTabBar::scroller{width: 0px;}”;

    QString qss1 = "QTabBar::tab{ \
    font: 75 12pt Arial; \
    text-align:left; \
    width:184px; \
    height:32; \
    background:#FFFFFF; \
    border:2px solid #FFFFFF; \
    border-bottom-color:#FFFFFF; \
    border-top-left-radius:4px; \
    border-top-right-radius:4px; \
    padding:2px; \
    margin-top:0px; \
    margin-right:1px; \
    margin-left:1px;  \
    margin-bottom:0px;} \
    QTabBar::tab:selected{  \
        color:#333333; /*文字颜色*/  \
            background-color:#FFFFFF;} \
    QTabBar::tab:!selected{ \
        color:#B2B2B2; \
        border-color:#FFFFFF;} \
    QTabBar::scroller{width: 36px;}";
    
    tabbrowser::tabbrowser(QWidget *parent)
    QTabWidget{parent}
    {
    this->addTab(new QWidget,u8"稻壳");
    this->setUsesScrollButtons(true);//滚动鼠标可切换tab
    this->setTabsClosable(true); //显示tab右侧的关闭按钮
    this->setMovable(true);//设置可移动位置
    initTabWidget();
    setTabBarFlag(NORMAL);
    
    this->setStyleSheet(qss0);
    
    connect(this, &QTabWidget::tabCloseRequested,this, &tabbrowser::on_closeTab);
    

    }

    void tabbrowser::resizeEvent(QResizeEvent *ev)
    {
    setTabBarFlag(NORMAL);
    QTabWidget::resizeEvent(ev);
    }

    void tabbrowser::initTabWidget()
    {
    this->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this,&QTabWidget::customContextMenuRequested,this,&tabbrowser::onMenuShow);
    createTabMenu();

    m_pRightWidget = new CTabTitleWidget(this);
    
    this->setCornerWidget(m_pRightWidget, Qt::TopRightCorner);
    connect(m_pRightWidget, &CTabTitleWidget::sig_addtab, this, &tabbrowser::on_newTab);
    connect(m_pRightWidget, &CTabTitleWidget::sig_close, this, &tabbrowser::sig_close);
    

    }

    void tabbrowser::setTabBarFlag(TAB_FLAG flag)
    {
    int w = this->width();

    int tabsWidth = 0;  //所有tab的总宽度
    int tabsHeight = tabBar()->height();
    int tabs = this->count();
    
    if (flag == NEW || flag == NORMAL)
    {
        for (int i = 0; i < tabs; ++i)
        {
            tabsWidth += tabBar()->tabRect(i).width();
        }
    }
    else
    {
        for (int i = 0;i < tabs - 1;++i)
        {
            tabsWidth += tabBar()->tabRect(i).width();
        }
    }
    
    if (w > tabsWidth)
    {
        m_pRightWidget->setEmptyWidgetWidth(w - tabsWidth - 32 * 5 - 15);
        this->setStyleSheet(qss0);
    }
    else
    {
        //当所有tab的宽度大于整个tabWidget的宽时
        m_pRightWidget->setEmptyWidgetWidth(150);
        this->setStyleSheet(qss1);
    }
    

    }

    void tabbrowser::createTabMenu()
    {
    m_pTabMenu = new QMenu(this);

    QAction* pAcSave = new QAction(QIcon(":/resources/save.png"), u8"保存", m_pTabMenu);
    m_pTabMenu->addAction(pAcSave);
    
    connect(pAcSave, &QAction::triggered, [=] {
        QMessageBox::information(this, u8"提示", u8"你点击了 保存");
        });
    
    QAction* pAcSaveAs = new QAction(QString(u8"另存为"), m_pTabMenu);
    m_pTabMenu->addAction(pAcSaveAs);
    
    m_pTabMenu->addSeparator();
    
    QAction* pAcShareDoc = new QAction(QIcon(":/resources/share.png"), QString(u8"分享文档"), m_pTabMenu);
    m_pTabMenu->addAction(pAcShareDoc);
    
    QAction* pAcSendToDevice = new QAction(QString(u8"发送到设备"), m_pTabMenu);
    m_pTabMenu->addAction(pAcSendToDevice);
    
    m_pTabMenu->addSeparator();
    
    QAction* pAcNewName = new QAction(QString(u8"重命名"), m_pTabMenu);
    m_pTabMenu->addAction(pAcNewName);
    
    QAction* pAcSaveToWPSCloud = new QAction(QString(u8"保存到WPS云文档"), m_pTabMenu);
    m_pTabMenu->addAction(pAcSaveToWPSCloud);
    
    QAction* pAcCloseAll = new QAction(QString(u8"关闭所有文件"), m_pTabMenu);
    m_pTabMenu->addAction(pAcCloseAll);
    connect(pAcCloseAll, &QAction::triggered, this, &tabbrowser::on_closeAllTab);
    

    }

    void tabbrowser::on_newTab()
    {
    int nCount = count();
    QString title = QString::number(nCount);
    title = “Page” + title;

    // 这里写的有问题,应该是 insertTab
    this->addTab(new QWidget, title);
    
    if (!tabsClosable())
    {
        setTabsClosable(true);
    }
    
    setTabBarFlag(NEW);
    

    }

    void tabbrowser::on_closeTab(int index)
    {
    widget(index)->deleteLater();
    setTabBarFlag(CLOSE);

    //当只剩下1个tab时
    if (count() == 1)
    {
        setTabsClosable(false);
        setTabBarFlag(SPECIAL);
    }
    

    }

    void tabbrowser::onMenuShow(const QPoint &pos)
    {
    int index = this->tabBar()->tabAt(pos);

    #ifdef _DEBUG
    qDebug() << u8"当前tab为:" << QString::number(index);
    this->setCurrentIndex(index);
    #endif

    if (index != -1)
    {
      m_pTabMenu->exec(QCursor::pos());
    }
    

    }

    void tabbrowser::on_closeAllTab()
    {

    }

  • 相关阅读:
    【JVM】字节码文件的组成部分
    Docker入门学习(笔记1)
    WebGL模型视图投影矩阵
    kafka 伊始,架构模型,角色功能梳理
    Ultra-Light-Fast-Generic-Face-Detector-1MB-master人脸检测算法的复现过程记录
    IntelliJ IDEA-Debug断点调试 看这篇文章就够了
    多特征线性回归
    Jackson之ObjectMapper常用用法
    校园一卡通系统
    操作系统简陋复习
  • 原文地址:https://blog.csdn.net/2301_80434259/article/details/139248573