Qt自定义标题栏

第一次写博客。刚发布出来,发现格式不满意就删了,结果回来看,保存的也没了,真伤。还好有个回收箱,又复制了一遍。
话不多上,先上效果图:
在这里插入图片描述

图片效果是加上了样式与透明效果。这里只讲标题栏的创建方法,透明效果与样式我会在下一次介绍。为了让大家能够看清楚效果,上图是我以桌面作为背景。

相信大家可能已经查了很多资料,或者说刚看到我的这篇博客,不过都没关系,因为,看完我这篇,你们这个问题就可以解决了。大家每次本来把样式整的漂漂亮亮的,却因为系统的自带标题栏,导致整个程序页面的美感多了一点瑕疵。
自定义标题栏不仅可以让我们自由在标题栏上添加东西,更方便设计主题,如下面的QQ音乐页面。下面介绍自定义标题栏的三种方法,第一二种方法只介绍思路,详细会介绍第三种方法,也是我目前认为比较好的方法:
在这里插入图片描述

第一种:
1.去掉系统自带的标题栏。
2.在界面文件中,用控件在界面顶部布局一个标题栏。
这种方法优点是方便样式的设置,能更好的设置主题,而且设计起来也更简单。缺点是每次都要在新创建的工程中重新布局,还要设置变量,非常的麻烦与浪费多余宝贵的时间,如果是MainWindow窗口,这个方法就不能用了。这个方法就不多去介绍了。
在这里插入图片描述

第二种方法:
1、创建一个新的QWidget类,将这个QWidget设计成标题栏,然后再将这个QWidget类加到UI界面文件的顶部,这样每次新建工程,只需要将标题栏的.c和.h文件加到工程中,复制使用代码,就可以加入自定义的标题栏了,非常的方便。但是这个方法缺点是,UI界面的定义必须留一段空的控件放标题栏,与第一种方法有相同的限制,而且遇到MainWindow,会覆盖在菜单栏上,使用代码调整位置也效果不大。这种的负面效果图当时没保存,就不重新花时间弄一遍了。
相信大家查找资料,很多都是第一种第二种方法,而且绝大部分资料都没有考虑MainWindow工程与自己自定的标题栏能不能适用。博主当时查找资料也没有看到满意的资料,我希望能自定义一个标题栏,然后不影响工程的界面文件设计,以后新建工程的时候,能直接把标题栏文件加入工程就可以用了。后来查找资料过程中受到一句话启发,终于完美的解决了这个问题。下面介绍第三种方法。

第三种方法:
第三种方法与第二种方法非常类似。下面介绍思路:
先定义一个新的QWidget类 ,设为TitleBar,将它设计成标题栏。再定义一个新的QWidget类,设为WidgetPar,这个类作为容器,后面说到。然后在创建的工程中的构造函数中,将新建的标题栏类和工程的界面文件做一个整体布局,然后把他们添加到WidgetPar这个类容器中,这样就实现了自定义标题栏。这个方法使得添加标题栏非常方便,不影响原有的UI界面文件设计,而且对界面文件是哪个基类没有任何影响。效果图就是最开始看到的那个了。
设计标题栏就不多介绍了,就是重写事件,将标题栏的那些功能在自定义的标题栏上实现。
下面介绍代码:
在这里插入图片描述

titlebar.c和titlebar.h就是标题栏文件。
使用方法,在工程新建一个QWidget类,名字可以取上面一样的,然后将下面的代码复制上去。(类名相同可以全部替换)

titlebar.h

#ifndef TITLEBAR_H
#define TITLEBAR_H

#include <QWidget>
#include <QLabel>
#include <QPushButton>

/*
定义一个新的QWidget类,将标题栏和UI界面都放到这个类里面,定义这个类是为了方便改变主题
*/
class WidgetPar : public QWidget
{
    Q_OBJECT
public:
    explicit WidgetPar(QWidget *parent = 0);

signals:

public slots:
    //void paintEvent(QPaintEvent *event);
};

/*
自定义的标题栏类
*/
class TitleBar : public QWidget
{
    Q_OBJECT
public:
    explicit TitleBar(QWidget *parent = 0);

signals:

public slots:
    //右上角三个按钮共用一个槽函数
    void on_TiBar_Clicked();

protected:
    //重写鼠标事件
    virtual void mouseDoubleClickEvent(QMouseEvent *event);// 双击标题栏进行界面的最大化/还原
    virtual void mousePressEvent(QMouseEvent *event);// 进行鼠界面的拖动
    virtual bool eventFilter(QObject *obj, QEvent *event);// 设置界面标题与图标

    // 标题栏跑马灯效果时钟;
    //QTimer m_titleRollTimer;
private:
    void updateMaximize();// 最大化/还原

private://自定义标题栏控件
    QLabel *TiBar_pIconLabel;               //左上角图标label
    QLabel *TiBar_pTitleLabel;              //中间标题栏label
    QPushButton *TiBar_pMinimizeBtn;        //右上角缩小到底部任务栏按钮,最小化
    QPushButton *TiBar_pMaximizeBtn;        //右上角放大缩小按钮
    QPushButton *TiBar_pCloseBtn;           //右上角关闭按钮
public:


};

#endif // TITLEBAR_H

titlebar.c

#include "titlebar.h"
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QApplication>

#include <qt_windows.h>
#include <QPainter>

#include <QDebug>
TitleBar::TitleBar(QWidget *parent) :
    QWidget(parent)
{
    TiBar_pIconLabel    = new QLabel;
    TiBar_pTitleLabel   = new QLabel;
    TiBar_pMinimizeBtn  = new QPushButton;
    TiBar_pMaximizeBtn  = new QPushButton;
    TiBar_pCloseBtn     = new QPushButton;

    TiBar_pIconLabel->setFixedSize(32, 32); //设置图标固定大小
    TiBar_pIconLabel->setScaledContents(true);  //设置图片显示合适大小

    TiBar_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);//此属性保存窗口小部件的默认布局行为。

    TiBar_pMinimizeBtn->setFixedSize(32, 32);//设置三个按钮的固定大小
    TiBar_pMaximizeBtn->setFixedSize(32, 32);
    TiBar_pCloseBtn->setFixedSize(32, 32);
    TiBar_pTitleLabel->setFixedHeight(32);


    TiBar_pMinimizeBtn->setIcon(QIcon(":/image/image/small.ico"));
    TiBar_pMinimizeBtn->setIconSize(TiBar_pMinimizeBtn->size());
    TiBar_pMaximizeBtn->setIcon(QIcon(":/image/image/max.ico"));
    TiBar_pMaximizeBtn->setIconSize(TiBar_pMinimizeBtn->size());
    TiBar_pCloseBtn->setIcon(QIcon(":/image/image/close.ico"));
    TiBar_pCloseBtn->setIconSize(TiBar_pMinimizeBtn->size());
    QPixmap icon(":/image/image/lk.ico");
    TiBar_pIconLabel->setPixmap(icon);
    //TiBar_pIconLabel->resize(icon.width(),icon.height());


    TiBar_pTitleLabel->setObjectName("whiteLabel"); //此属性保存此对象的名称。
    TiBar_pMinimizeBtn->setObjectName("minimizeButton");
    TiBar_pMaximizeBtn->setObjectName("maximizeButton");
    TiBar_pCloseBtn->setObjectName("closeButton");

    TiBar_pMinimizeBtn->setToolTip("最小化"); //鼠标停留在上面的提示
    TiBar_pMaximizeBtn->setToolTip("放大/缩小");
    TiBar_pCloseBtn->setToolTip("关闭");

    QHBoxLayout *pLayout = new QHBoxLayout(this);
    pLayout->addWidget(TiBar_pIconLabel);
    //pLayout->addSpacing(5);
    pLayout->addWidget(TiBar_pTitleLabel);
    pLayout->addWidget(TiBar_pMinimizeBtn);
    pLayout->addWidget(TiBar_pMaximizeBtn);
    pLayout->addWidget(TiBar_pCloseBtn);
    pLayout->setSpacing(0);//设置控件之间的间距
    pLayout->setContentsMargins(0, 0, 0, 0);//设置左上右下的边距

    this->setLayout(pLayout);

    connect(TiBar_pMinimizeBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
    connect(TiBar_pMaximizeBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
    connect(TiBar_pCloseBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
}
/*  标题栏右上角三个按钮的槽函数*/
void TitleBar::on_TiBar_Clicked()
{
    QPushButton *pBtn = qobject_cast<QPushButton *>(sender());//如果在由信号激活的槽中调用,则返回指向发送信号的对象的指针; 否则它返回0.
    /*  返回此窗口小部件的窗口,即具有(或可能具有)窗口系统框架的下一个祖先窗口小部件。 如果窗口小部件是窗口,则返回窗口小部件本身。*/
    QWidget *pWindow = this->window();
    if (pWindow->isWindow())//如果窗口小部件是独立窗口,则返回true,否则返回false。
    {
        if (pBtn == TiBar_pMinimizeBtn)
        {
            pWindow->showMinimized();//最小化窗口小部件,作为图标。调用此函数仅影响窗口。
        }
        else if (pBtn == TiBar_pMaximizeBtn)
        {
            pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();//放大缩小
        }
        else if (pBtn == TiBar_pCloseBtn)
        {
            pWindow->close();//关闭窗口
        }
    }
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    emit TiBar_pMaximizeBtn->clicked();
}

void TitleBar::mousePressEvent(QMouseEvent *event)
{
    if (ReleaseCapture())
    {
        QWidget *pWindow = this->window();
        if (pWindow->isWindow())
        {
           SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
        }
    }
    event->ignore();
}

bool TitleBar::eventFilter(QObject *obj, QEvent *event)
{
    switch (event->type())
    {
        case QEvent::WindowTitleChange:
        {
            QWidget *pWidget = qobject_cast<QWidget *>(obj);
            if (pWidget)
            {
                TiBar_pTitleLabel->setText(pWidget->windowTitle());
                return true;
            }
        }
        case QEvent::WindowIconChange:
        {
            QWidget *pWidget = qobject_cast<QWidget *>(obj);
            if (pWidget)
            {
                QIcon icon = pWidget->windowIcon();
                TiBar_pIconLabel->setPixmap(icon.pixmap(TiBar_pIconLabel->size()));
                return true;
            }
        }
        case QEvent::WindowStateChange:
        case QEvent::Resize:
            //updateMaximize();
            return true;
        default:
            return false;
    }
    return QWidget::eventFilter(obj, event);
}
//窗口大小发生改变
void TitleBar::updateMaximize()
{
    QWidget *pWindow = this->window();
    if (pWindow->isTopLevel())
    {
        bool bMaximize = pWindow->isMaximized();
        if (bMaximize)
        {
            TiBar_pMaximizeBtn->setToolTip(tr("Restore"));
            TiBar_pMaximizeBtn->setProperty("maximizeProperty", "restore");
        }
        else
        {
            TiBar_pMaximizeBtn->setProperty("maximizeProperty", "maximize");
            TiBar_pMaximizeBtn->setToolTip(tr("Maximize"));
        }
        TiBar_pMaximizeBtn->setStyle(QApplication::style());
    }
}

WidgetPar::WidgetPar(QWidget *parent) :
    QWidget(parent)
{

}


mainwindow.cpp

#include <QGridLayout>
#include "titlebar.h"

ui->setupUi(this);

        WidgetPar *selMainWidget = new WidgetPar; //创建一个QWidget容器
        selMainWidget->setWindowFlags(Qt::FramelessWindowHint);//将这个QWidget的边框去掉

        this->setParent(selMainWidget);//重新设置这个UI界面的父对象为QWidget
        TitleBar *pTitleBar = new TitleBar(selMainWidget); //定义一个标题栏类


        //设置控件样式
        //selMainWidget->setStyleSheet("background-color:#AFFFFF00");

        this->installEventFilter(pTitleBar);//安装事件过滤器
        QGridLayout *pLayout = new QGridLayout();//创建一个整体布局器
        pLayout->addWidget(pTitleBar);  //添加标题栏
        pLayout->addWidget(this);       //添加UI界面
        pLayout->setSpacing(0);         //布局之间的距离
        pLayout->setContentsMargins(0, 0, 0,0); //布局器的四周边距
        selMainWidget->setLayout(pLayout);  //将这个布局器设置在QWidget上
        selMainWidget->setAttribute(Qt::WA_TranslucentBackground, true);
        selMainWidget->setSizePolicy(this->sizePolicy());
        selMainWidget->setMaximumSize(this->maximumSize());
        selMainWidget->setMaximumSize(this->maximumSize());
        this->setWindowTitle("自定义标题栏成功  -----By DS_LK");

        selMainWidget->show();//显示QWidge 最后添加

大家按照这个方法基本没问题了。QT版本是用的qt5.3的。

参考资料:一去丶二三里


版权声明:本文为qq_41311950原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。