赞
踩
QWidget及其子类窗体组件的标题栏受操作系统的控制,即标题栏的界面风格与操作系统的主题风格相同,工程实践中需要开发者自行定义,达到美化应用程序界面的目的。
自定义标题栏需要完成功能如下:
(1)自定义标题栏需要包含最小化按钮、最大化按钮、关闭按钮、标题标签、图标标签等图形元素。
(2)标题栏的拖拽。
(3)鼠标双击标题栏实现窗体的最大化、最小化。
自定义标题栏的界面布局如下:
窗体的拖拽平移过程如下图:
当鼠标在窗体的标题栏按下并移动时,窗体会按照鼠标移动的轨迹进行平移。因此,窗体每次移动都是在当前位置按照鼠标移动的矢量进行移动。标题栏拖拽功能的实现需要实现mousePressEvent、mouseMoveEvent、mouseReleaseEvent三个事件处理函数。
MouseEvent中的globalPos()函数返回的是相对屏幕的位置坐标,而pos()则是返回鼠标在当前控件(即捕获该鼠标事件的控件)中的位置。
QWidget窗体的geometry().topLeft()则返回的是当前窗体的左上角在屏幕中的位置。
- startPos = event->globalPos();// 鼠标的全局初始位置,按下时记住
- curWindowPos = geometry().topleft();// 窗体的全局位置,移动时
- endPos = event->globalPos();// 鼠标按下发生移动之后的位置,移动时
- move(curWindowPos+(startPos-endPos));// 根据矢量移动方向是初始位置减去末位置,移动时
- startPos = endPos;// 将初始位置记为上次末位置,然后执行直到释放拖拽,移动时
实现代码如下:
- void TitleBar::mousePressEvent(QMouseEvent *event)
- {
- // 鼠标左键按下事件
- if (event->button() == Qt::LeftButton)
- {
- // 记录鼠标左键状态
- m_leftButtonPressed = true;
- //记录鼠标在屏幕中的位置
- m_start = event->globalPos();
- }
-
- }
-
- void TitleBar::mouseMoveEvent(QMouseEvent *event)
- {
- // 持续按住才做对应事件
- if(m_leftButtonPressed)
- {
- //将父窗体移动到父窗体原来的位置加上鼠标移动的位置:event->globalPos()-m_start
- parentWidget()->move(parentWidget()->geometry().topLeft() +
- event->globalPos() - m_start);
- //将鼠标在屏幕中的位置替换为新的位置
- m_start = event->globalPos();
- }
-
- }
-
- void TitleBar::mouseReleaseEvent(QMouseEvent *event)
- {
- // 鼠标左键释放
- if (event->button() == Qt::LeftButton)
- {
- // 记录鼠标状态
- m_leftButtonPressed = false;
- }
- }
鼠标双击事件处理函数mouseDoubleClickEvent实现如下:
- void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
- {
- m_maximizeButton->click();
- }
最大化、最小化、关闭按钮的槽函数如下:
- void TitleBar::onClicked()
- {
- QPushButton *pButton = qobject_cast<QPushButton *>(sender());
- QWidget *pWindow = this->window();
- if (pWindow->isTopLevel())
- {
- if (pButton == m_minimizeButton)
- {
- pWindow->showMinimized();
- }
- else if (pButton == m_maximizeButton)
- {
- pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();
- }
- else if (pButton == m_closeButton)
- {
- pWindow->close();
- }
- }
- }
自定义窗体基类的功能如下:
(1)自定义标题栏。
(2)增加内容组件,内容组件内部的界面布局完全由具体的用户决定。
TitleBar.h文件:
- #ifndef TITLEBAR_H
- #define TITLEBAR_H
-
- #include <QWidget>
- #include <QPushButton>
- #include <QLabel>
- #include <QHBoxLayout>
- #include <QEvent>
- #include <QMouseEvent>
- #include <QApplication>
- #include <QPoint>
- #include <QPixmap>
- #include <QString>
- /**
- * @brief 标题栏界面组件
- * @author
- */
- class TitleBar : public QWidget
- {
- Q_OBJECT
- public:
- explicit TitleBar(QWidget *parent = NULL);
- /**
- * @brief 设置标题栏标题
- * @param title,参数,设置的标题
- */
- void setWindowTitle(const QString& title);
- /**
- * @brief 设置标题栏的图标
- * @param iconPath,参数,图标的路径
- */
- void SetTitleBarIcon(const QString& iconPath);
-
- protected:
- /**
- * @brief 鼠标双击事件处理函数
- * @param event,参数,事件
- * @note 双击标题栏进行界面的最大化/还原
- */
- virtual void mouseDoubleClickEvent(QMouseEvent *event);
-
- /**
- * @brief 鼠标按下事件处理函数
- * @param event,参数,事件
- * @note 按下鼠标左键
- */
- virtual void mousePressEvent(QMouseEvent *event);
- /**
- * @brief 鼠标移动事件处理函数
- * @param event,参数,事件
- * @note 移动鼠标
- */
- virtual void mouseMoveEvent(QMouseEvent *event);
- /**
- * @brief 鼠标释放事件处理函数
- * @param event,参数,事件
- * @note 释放鼠标
- */
- virtual void mouseReleaseEvent(QMouseEvent *event);
-
- /**
- * @brief 事件过滤处理器
- * @param obj,参数
- * @param event,参数,事件
- * @return 成功返回true,失败返回false
- * @note 设置标题、图标
- */
- virtual bool eventFilter(QObject *obj, QEvent *event);
-
- /**
- * @brief 最大化/还原
- */
- void updateMaximize();
-
- protected slots:
- /**
- * @brief 最小化、最大化/还原、关闭按钮点击时响应的槽函数
- */
- void onClicked();
-
- private:
- QLabel* m_iconLabel;
- QLabel* m_titleLabel;
- QPushButton* m_minimizeButton;
- QPushButton* m_maximizeButton;
- QPushButton* m_closeButton;
- QPoint m_start;//起始点
- QPoint m_end;//结束点
- bool m_leftButtonPressed;//鼠标左键按下标记
- };
-
- #endif // TITLEBAR_H
TitleBar.cpp文件:
- #include "TitleBar.h"
-
- TitleBar::TitleBar(QWidget *parent) : QWidget(parent)
- {
- setFixedHeight(30);
- setWindowFlags(Qt::FramelessWindowHint);
- m_iconLabel = new QLabel(this);
- m_iconLabel->setFixedSize(20, 20);
- m_iconLabel->setScaledContents(true);
-
- m_titleLabel = new QLabel(this);
- m_titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-
- m_minimizeButton = new QPushButton(this);
- m_minimizeButton->setFixedSize(27, 22);
- m_minimizeButton->setObjectName("minimizeButton");
-
- m_maximizeButton = new QPushButton(this);
- m_maximizeButton->setFixedSize(27, 22);
- m_maximizeButton->setObjectName("maximizeButton");
-
- m_closeButton = new QPushButton(this);
- m_closeButton->setFixedSize(27, 22);
- m_closeButton->setObjectName("closeButton");
-
- QHBoxLayout* layout = new QHBoxLayout;
- layout->addWidget(m_iconLabel);
- layout->addStretch(1);
- layout->addWidget(m_titleLabel);
- layout->addStretch(1);
- layout->addWidget(m_minimizeButton);
- layout->addWidget(m_maximizeButton);
- layout->addWidget(m_closeButton);
- setLayout(layout);
-
- setProperty("titleBar", true);
- setObjectName("titleBar");
-
- connect(m_minimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
- connect(m_maximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
- connect(m_closeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
- }
-
- void TitleBar::setWindowTitle(const QString &title)
- {
- m_titleLabel->setAlignment(Qt::AlignCenter);
- m_titleLabel->setText(title);
- }
-
- void TitleBar::SetTitleBarIcon(const QString &iconPath)
- {
- QPixmap map(iconPath);
- m_iconLabel->setPixmap(map);
- }
-
- void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
- {
- m_maximizeButton->click();
- }
-
- void TitleBar::mousePressEvent(QMouseEvent *event)
- {
- // 鼠标左键按下事件
- if (event->button() == Qt::LeftButton)
- {
- // 记录鼠标左键状态
- m_leftButtonPressed = true;
- //记录鼠标在屏幕中的位置
- m_start = event->globalPos();
- }
-
- }
-
- void TitleBar::mouseMoveEvent(QMouseEvent *event)
- {
- // 持续按住才做对应事件
- if(m_leftButtonPressed)
- {
- //将父窗体移动到父窗体原来的位置加上鼠标移动的位置:event->globalPos()-m_start
- parentWidget()->move(parentWidget()->geometry().topLeft() +
- event->globalPos() - m_start);
- //将鼠标在屏幕中的位置替换为新的位置
- m_start = event->globalPos();
- }
-
- }
-
- void TitleBar::mouseReleaseEvent(QMouseEvent *event)
- {
- // 鼠标左键释放
- if (event->button() == Qt::LeftButton)
- {
- // 记录鼠标状态
- m_leftButtonPressed = false;
- }
- }
-
- bool TitleBar::eventFilter(QObject *obj, QEvent *event)
- {
- switch(event->type())
- {
- //设置标题
- case QEvent::WindowTitleChange:
- {
- QWidget *pWidget = qobject_cast<QWidget *>(obj);
- if (pWidget)
- {
- m_titleLabel->setText(pWidget->windowTitle());
- return true;
- }
- }
- //设置图标
- case QEvent::WindowIconChange:
- {
- QWidget *pWidget = qobject_cast<QWidget *>(obj);
- if (pWidget)
- {
- QIcon icon = pWidget->windowIcon();
- m_iconLabel->setPixmap(icon.pixmap(m_iconLabel->size()));
- return true;
- }
- }
- // 窗口状态变化、窗口大小变化
- case QEvent::WindowStateChange:
- case QEvent::Resize:
- updateMaximize();
- return true;
- }
- return QWidget::eventFilter(obj, event);
- }
-
- void TitleBar::updateMaximize()
- {
- QWidget *pWindow = this->window();
- if (pWindow->isTopLevel())
- {
- bool bMaximize = pWindow->isMaximized();
- if (bMaximize)
- {
- m_maximizeButton->setToolTip(tr("Restore"));
- m_maximizeButton->setProperty("maximizeProperty", "restore");
- }
- else
- {
- m_maximizeButton->setProperty("maximizeProperty", "maximize");
- m_maximizeButton->setToolTip(tr("Maximize"));
- }
-
- m_maximizeButton->setStyle(QApplication::style());
- }
- }
-
- void TitleBar::onClicked()
- {
- QPushButton *pButton = qobject_cast<QPushButton *>(sender());
- QWidget *pWindow = this->window();
- if (pWindow->isTopLevel())
- {
- if (pButton == m_minimizeButton)
- {
- pWindow->showMinimized();
- }
- else if (pButton == m_maximizeButton)
- {
- pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();
- }
- else if (pButton == m_closeButton)
- {
- pWindow->close();
- }
- }
- }
QWindowBase.h文件:
- #ifndef QWINDOWBASE_H
- #define QWINDOWBASE_H
-
- #include <QFrame>
- #include <QWidget>
- #include <QVBoxLayout>
- #include "TitleBar.h"
-
- /**
- * @brief 界面组件基类
- * @note QWindowBase界面组件主要用作顶层窗口,对于非顶层窗口的界面组件使用QWidget。
- */
- class QWindowBase : public QFrame
- {
- Q_OBJECT
- public:
- QWindowBase(QFrame* parent = NULL);
- /**
- * @brief 设置标题
- * @param title,输入参数,标题内容
- */
- void setWindowTitle(const QString& title);
- /**
- * @brief 设置标题栏的图标
- * @param iconPath,输入参数,图标资源路径
- */
- void SetTitleBarIcon(const QString& iconPath);
- /**
- * @brief 获取内容组件对象指针
- * @return 返回QWidget*
- */
- QWidget* contentWidget();
- /**
- * @brief 设置标题栏高度
- * @param h,输入参数,标题栏高度
- */
- void setWindowTitleHeight(int h);
-
- private:
- QWidget* m_contentWidget;//内容组件
- TitleBar* m_titleBar;//标题栏
- QVBoxLayout* m_layout;//布局管理器
- };
-
- #endif // QWINDOWBASE_H
QWindowBase.cpp文件:
- #include "QWindowBase.h"
-
- QWindowBase::QWindowBase(QFrame *parent): QFrame(parent)
- {
- setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
- m_titleBar = new TitleBar(this);
- m_contentWidget = new QWidget(this);
- m_contentWidget->setObjectName("Contents");
- m_layout = new QVBoxLayout;
- m_layout->addWidget(m_titleBar);
- m_layout->addWidget(m_contentWidget);
- m_layout->setSpacing(0);
- m_layout->setContentsMargins(0, 0, 0, 0);
-
- setLayout(m_layout);
- }
-
- void QWindowBase::setWindowTitle(const QString &title)
- {
- m_titleBar->setWindowTitle(title);
- }
-
- void QWindowBase::SetTitleBarIcon(const QString &iconPath)
- {
- m_titleBar->SetTitleBarIcon(iconPath);
- }
-
- QWidget *QWindowBase::contentWidget()
- {
- return m_contentWidget;
- }
-
- void QWindowBase::setWindowTitleHeight(int h)
- {
- m_titleBar->setFixedHeight(h);
- }
CommonHelper.h文件:
- #ifndef COMMONHELPER_H
- #define COMMONHELPER_H
-
- #include <QString>
- #include <QFile>
- #include <QApplication>
- #include <QDebug>
- #include <QColor>
- #include <QPalette>
-
- /**
- * @brief 通用功能辅助类
- */
- class CommonHelper
- {
- public:
- /**
- * @brief 为应用程序设置QSS样式表
- * @param filepath,输入参数,QSS文件路径
- */
- static void setStyleSheet(const QString& filepath)
- {
- //加载样式文件
- QFile qss(filepath);
- if(qss.open(QFile::ReadOnly))
- {
- QString stylesheet = QLatin1String(qss.readAll());
- QString paletteColor = stylesheet.mid(20, 7);
- qApp->setPalette(QPalette(QColor(paletteColor)));
- qApp->setStyleSheet(stylesheet);
- }
- }
- };
-
- #endif // COMMONHELPER_H
main.cpp文件:
- #include <QApplication>
- #include "CommonHelper.h"
- #include "QWindowBase.h"
- #include <QPushButton>
- #include <QVBoxLayout>
- #include <QHBoxLayout>
- #include <QTreeView>
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- QWindowBase w;
- w.setWindowTitle("WidgetBase");
- QPushButton* button1 = new QPushButton("OK");
- QHBoxLayout* hLayout1 = new QHBoxLayout;
- hLayout1->addStretch(1);
- hLayout1->addWidget(button1);
-
- QVBoxLayout* layout = new QVBoxLayout;
- QTreeView* treeView = new QTreeView;
- layout->addWidget(treeView);
- layout->addLayout(hLayout1);
- layout->addStretch(1);
- w.contentWidget()->setLayout(layout);
- w.setWindowTitleHeight(40);
- w.show();
- CommonHelper::setStyleSheet("://qss/lightblue.qss");
- return a.exec();
- }
工程文件:
- QT += core gui
-
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
- TARGET = TitleBarDemo
- TEMPLATE = app
-
- # The following define makes your compiler emit warnings if you use
- # any feature of Qt which has been marked as deprecated (the exact warnings
- # depend on your compiler). Please consult the documentation of the
- # deprecated API in order to know how to port your code away from it.
- DEFINES += QT_DEPRECATED_WARNINGS
-
- # You can also make your code fail to compile if you use deprecated APIs.
- # In order to do so, uncomment the following line.
- # You can also select to disable deprecated APIs only up to a certain version of Qt.
- #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
- SOURCES += \
- main.cpp \
- TitleBar.cpp \
- QWindowBase.cpp
-
- HEADERS += \
- TitleBar.h \
- CommonHelper.h \
- QWindowBase.h
-
- RESOURCES += \
- TitileBarDemo.qrc
工程目录结构:
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。