Qt 自定義標題欄

1 頭文件windows

#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文件less

#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文件見上傳文件佈局

相關文章
相關標籤/搜索