赞
踩
通过上节内容,我们实现了自定义窗体的移动,但是我们缺少一个标题栏来显示窗体的图标、标题,以及控制窗体最小化、最大化、关闭的按钮。
自定义标题栏后,所有的控件我们都可以定制,比如:在标题栏中添加换肤、设置按钮以及其他控件。
title_bar.h
- #ifndef TITLE_BAR
- #define TITLE_BAR
-
- #include <QWidget>
-
- class QLabel;
- class QPushButton;
-
- class TitleBar : public QWidget
- {
- Q_OBJECT
-
- public:
- 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>
- #endif
-
- TitleBar::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());
- }
- }

之前,我们将界面移动的事件写在主界面里面,这会有一个问题,一般情况下,是界面随着标题栏的移动而移动,而并非界面中的所有位置都可以进行拖动,所以我们将事件写在标题栏中比较合理。
双击标题栏会进行窗体的最大化/还原,所以我们需要重写此事件进行控制。
eventFilter
事件过滤器,这里被监听的窗体为标题栏所在的窗体,所以当窗体标题、图标等信息发生改变时,标题栏也应该随之改变。
最好不要通过直接调用接口的形式来操作对应的行为,比如: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事件中。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。