【Qt】Qt之自定义界面(添加自定义标题栏)【转】

来源:互联网 发布:jquery javascript 编辑:程序博客网 时间:2024/05/21 06:42

简述

通过上节内容,我们实现了自定义窗体的移动,但是我们缺少一个标题栏来显示窗体的图标、标题,以及控制窗体最小化、最大化、关闭的按钮。

自定义标题栏后,所有的控件我们都可以定制,比如:在标题栏中添加换肤、设置按钮以及其他控件。

  • 简述
  • 效果
  • 自定义标题栏
    • 实现
    • 接口说明
    • 使用方式

效果

这里写图片描述

自定义标题栏

实现

title_bar.h

#ifndef TITLE_BAR#define TITLE_BAR#include <QWidget>class QLabel;class QPushButton;class TitleBar : public QWidget{    Q_OBJECTpublic:    explicit TitleBar(QWidget *parent = 0);    ~TitleBar();protected:    // 双击标题栏进行界面的最大化/还原    virtual void mouseDoubleClickEvent(QMouseEvent *event);    // 进行鼠界面的拖动    virtual void mousePressEvent(QMouseEvent *event);    // 设置界面标题与图标    virtual bool eventFilter(QObject *obj, QEvent *event);private slots:    // 进行最小化、最大化/还原、关闭操作    void onClicked();private:    // 最大化/还原    void updateMaximize();private:    QLabel *m_pIconLabel;    QLabel *m_pTitleLabel;    QPushButton *m_pMinimizeButton;    QPushButton *m_pMaximizeButton;    QPushButton *m_pCloseButton;};#endif // TITLE_BAR

title_bar.cpp

#include <QLabel>#include <QPushButton>#include <QHBoxLayout>#include <QEvent>#include <QMouseEvent>#include <QApplication>#include "title_bar.h"#ifdef Q_OS_WIN#pragma comment(lib, "user32.lib")#include <qt_windows.h>#endifTitleBar::TitleBar(QWidget *parent)    : QWidget(parent){    setFixedHeight(30);    m_pIconLabel = new QLabel(this);    m_pTitleLabel = new QLabel(this);    m_pMinimizeButton = new QPushButton(this);    m_pMaximizeButton = new QPushButton(this);    m_pCloseButton = new QPushButton(this);    m_pIconLabel->setFixedSize(20, 20);    m_pIconLabel->setScaledContents(true);    m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);    m_pMinimizeButton->setFixedSize(27, 22);    m_pMaximizeButton->setFixedSize(27, 22);    m_pCloseButton->setFixedSize(27, 22);    m_pTitleLabel->setObjectName("whiteLabel");    m_pMinimizeButton->setObjectName("minimizeButton");    m_pMaximizeButton->setObjectName("maximizeButton");    m_pCloseButton->setObjectName("closeButton");    m_pMinimizeButton->setToolTip("Minimize");    m_pMaximizeButton->setToolTip("Maximize");    m_pCloseButton->setToolTip("Close");    QHBoxLayout *pLayout = new QHBoxLayout(this);    pLayout->addWidget(m_pIconLabel);    pLayout->addSpacing(5);    pLayout->addWidget(m_pTitleLabel);    pLayout->addWidget(m_pMinimizeButton);    pLayout->addWidget(m_pMaximizeButton);    pLayout->addWidget(m_pCloseButton);    pLayout->setSpacing(0);    pLayout->setContentsMargins(5, 0, 5, 0);    setLayout(pLayout);    connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));    connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));    connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));}TitleBar::~TitleBar(){}void TitleBar::mouseDoubleClickEvent(QMouseEvent *event){    Q_UNUSED(event);    emit m_pMaximizeButton->clicked();}void TitleBar::mousePressEvent(QMouseEvent *event){#ifdef Q_OS_WIN    if (ReleaseCapture())    {        QWidget *pWindow = this->window();        if (pWindow->isTopLevel())        {           SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);        }    }       event->ignore();#else#endif}bool TitleBar::eventFilter(QObject *obj, QEvent *event){    switch (event->type())    {    case QEvent::WindowTitleChange:    {        QWidget *pWidget = qobject_cast<QWidget *>(obj);        if (pWidget)        {            m_pTitleLabel->setText(pWidget->windowTitle());            return true;        }    }    case QEvent::WindowIconChange:    {        QWidget *pWidget = qobject_cast<QWidget *>(obj);        if (pWidget)        {            QIcon icon = pWidget->windowIcon();            m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size()));            return true;        }    }    case QEvent::WindowStateChange:    case QEvent::Resize:        updateMaximize();        return true;    }    return QWidget::eventFilter(obj, event);}void TitleBar::onClicked(){    QPushButton *pButton = qobject_cast<QPushButton *>(sender());    QWidget *pWindow = this->window();    if (pWindow->isTopLevel())    {        if (pButton == m_pMinimizeButton)        {            pWindow->showMinimized();        }        else if (pButton == m_pMaximizeButton)        {            pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();        }        else if (pButton == m_pCloseButton)        {            pWindow->close();        }    }}void TitleBar::updateMaximize(){    QWidget *pWindow = this->window();    if (pWindow->isTopLevel())    {        bool bMaximize = pWindow->isMaximized();        if (bMaximize)        {            m_pMaximizeButton->setToolTip(tr("Restore"));            m_pMaximizeButton->setProperty("maximizeProperty", "restore");        }        else        {            m_pMaximizeButton->setProperty("maximizeProperty", "maximize");            m_pMaximizeButton->setToolTip(tr("Maximize"));        }        m_pMaximizeButton->setStyle(QApplication::style());    }}

接口说明

  • mousePressEvent

之前,我们将界面移动的事件写在主界面里面,这会有一个问题,一般情况下,是界面随着标题栏的移动而移动,而并非界面中的所有位置都可以进行拖动,所以我们将事件写在标题栏中比较合理。

  • mouseDoubleClickEvent

双击标题栏会进行窗体的最大化/还原,所以我们需要重写此事件进行控制。

  • eventFilter

    1. 事件过滤器,这里被监听的窗体为标题栏所在的窗体,所以当窗体标题、图标等信息发生改变时,标题栏也应该随之改变。

    2. 最好不要通过直接调用接口的形式来操作对应的行为,比如:TitleBar中定义一个public函数来专门修改标题与图标,这样会造成不必要的麻烦,因为Qt本身就是基于事件的,所以此处采用过滤器的方式。

  • updateMaximize

因为窗体大小发生变化的时候,最大化的图标、提示应该对应的发生变化,所以在eventFilter中事件触发时调用。

使用方式

Widget::Widget(QWidget *parent)    : QWidget(parent){    setWindowFlags(Qt::FramelessWindowHint | windowFlags());    TitleBar *pTitleBar = new TitleBar(this);    installEventFilter(pTitleBar);    resize(400, 300);    setWindowTitle("Custom Window");    setWindowIcon(QIcon(":/Images/logo"));    QPalette pal(palette());    pal.setColor(QPalette::Background, QColor(50, 50, 50));    setAutoFillBackground(true);    setPalette(pal);    QVBoxLayout *pLayout = new QVBoxLayout();    pLayout->addWidget(pTitleBar);    pLayout->addStretch();    pLayout->setSpacing(0);    pLayout->setContentsMargins(0, 0, 0, 0);    setLayout(pLayout);}

注意

installEventFilter必须在setWindowTitle、setWindowIcon之前调用,因为必须先安装事件过滤器,相应事件触发时,才会进入标题栏的eventFilter事件中。


原文作者:一去丶二三里作者博客:去作者博客空间
0 0