Qt 自定义标题栏

Posted luckcoder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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文件见上传文件

以上是关于Qt 自定义标题栏的主要内容,如果未能解决你的问题,请参考以下文章

标题栏自定义,文件名显示

ActionBarSherlock - 带有分隔线的操作栏自定义背景

iPad导航栏自定义高度

如何减少iOS导航栏自定义视图的左右间隙

IOS/Objective-C:导航栏自定义Segue效果对比Show Segue

无法执行单击导航栏自定义按钮