简述

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

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

效果

自定义标题栏

实现

title_bar.h

  1. #ifndef TITLE_BAR
  2. #define TITLE_BAR
  3. #include <QWidget>
  4. class QLabel;
  5. class QPushButton;
  6. class TitleBar : public QWidget
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit TitleBar(QWidget *parent = 0);
  11. ~TitleBar();
  12. protected:
  13. // 双击标题栏进行界面的最大化/还原
  14. virtual void mouseDoubleClickEvent(QMouseEvent *event);
  15. // 进行鼠界面的拖动
  16. virtual void mousePressEvent(QMouseEvent *event);
  17. // 设置界面标题与图标
  18. virtual bool eventFilter(QObject *obj, QEvent *event);
  19. private slots:
  20. // 进行最小化、最大化/还原、关闭操作
  21. void onClicked();
  22. private:
  23. // 最大化/还原
  24. void updateMaximize();
  25. private:
  26. QLabel *m_pIconLabel;
  27. QLabel *m_pTitleLabel;
  28. QPushButton *m_pMinimizeButton;
  29. QPushButton *m_pMaximizeButton;
  30. QPushButton *m_pCloseButton;
  31. };
  32. #endif // TITLE_BAR

title_bar.cpp

  1. #include <QLabel>
  2. #include <QPushButton>
  3. #include <QHBoxLayout>
  4. #include <QEvent>
  5. #include <QMouseEvent>
  6. #include <QApplication>
  7. #include "title_bar.h"
  8. #ifdef Q_OS_WIN
  9. #pragma comment(lib, "user32.lib")
  10. #include <qt_windows.h>
  11. #endif
  12. TitleBar::TitleBar(QWidget *parent)
  13. : QWidget(parent)
  14. {
  15. setFixedHeight(30);
  16. m_pIconLabel = new QLabel(this);
  17. m_pTitleLabel = new QLabel(this);
  18. m_pMinimizeButton = new QPushButton(this);
  19. m_pMaximizeButton = new QPushButton(this);
  20. m_pCloseButton = new QPushButton(this);
  21. m_pIconLabel->setFixedSize(20, 20);
  22. m_pIconLabel->setScaledContents(true);
  23. m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  24. m_pMinimizeButton->setFixedSize(27, 22);
  25. m_pMaximizeButton->setFixedSize(27, 22);
  26. m_pCloseButton->setFixedSize(27, 22);
  27. m_pTitleLabel->setObjectName("whiteLabel");
  28. m_pMinimizeButton->setObjectName("minimizeButton");
  29. m_pMaximizeButton->setObjectName("maximizeButton");
  30. m_pCloseButton->setObjectName("closeButton");
  31. m_pMinimizeButton->setToolTip("Minimize");
  32. m_pMaximizeButton->setToolTip("Maximize");
  33. m_pCloseButton->setToolTip("Close");
  34. QHBoxLayout *pLayout = new QHBoxLayout(this);
  35. pLayout->addWidget(m_pIconLabel);
  36. pLayout->addSpacing(5);
  37. pLayout->addWidget(m_pTitleLabel);
  38. pLayout->addWidget(m_pMinimizeButton);
  39. pLayout->addWidget(m_pMaximizeButton);
  40. pLayout->addWidget(m_pCloseButton);
  41. pLayout->setSpacing(0);
  42. pLayout->setContentsMargins(5, 0, 5, 0);
  43. setLayout(pLayout);
  44. connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
  45. connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
  46. connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
  47. }
  48. TitleBar::~TitleBar()
  49. {
  50. }
  51. void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
  52. {
  53. Q_UNUSED(event);
  54. emit m_pMaximizeButton->clicked();
  55. }
  56. void TitleBar::mousePressEvent(QMouseEvent *event)
  57. {
  58. #ifdef Q_OS_WIN
  59. if (ReleaseCapture())
  60. {
  61. QWidget *pWindow = this->window();
  62. if (pWindow->isTopLevel())
  63. {
  64. SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
  65. }
  66. }
  67. event->ignore();
  68. #else
  69. #endif
  70. }
  71. bool TitleBar::eventFilter(QObject *obj, QEvent *event)
  72. {
  73. switch (event->type())
  74. {
  75. case QEvent::WindowTitleChange:
  76. {
  77. QWidget *pWidget = qobject_cast<QWidget *>(obj);
  78. if (pWidget)
  79. {
  80. m_pTitleLabel->setText(pWidget->windowTitle());
  81. return true;
  82. }
  83. }
  84. case QEvent::WindowIconChange:
  85. {
  86. QWidget *pWidget = qobject_cast<QWidget *>(obj);
  87. if (pWidget)
  88. {
  89. QIcon icon = pWidget->windowIcon();
  90. m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size()));
  91. return true;
  92. }
  93. }
  94. case QEvent::WindowStateChange:
  95. case QEvent::Resize:
  96. updateMaximize();
  97. return true;
  98. }
  99. return QWidget::eventFilter(obj, event);
  100. }
  101. void TitleBar::onClicked()
  102. {
  103. QPushButton *pButton = qobject_cast<QPushButton *>(sender());
  104. QWidget *pWindow = this->window();
  105. if (pWindow->isTopLevel())
  106. {
  107. if (pButton == m_pMinimizeButton)
  108. {
  109. pWindow->showMinimized();
  110. }
  111. else if (pButton == m_pMaximizeButton)
  112. {
  113. pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();
  114. }
  115. else if (pButton == m_pCloseButton)
  116. {
  117. pWindow->close();
  118. }
  119. }
  120. }
  121. void TitleBar::updateMaximize()
  122. {
  123. QWidget *pWindow = this->window();
  124. if (pWindow->isTopLevel())
  125. {
  126. bool bMaximize = pWindow->isMaximized();
  127. if (bMaximize)
  128. {
  129. m_pMaximizeButton->setToolTip(tr("Restore"));
  130. m_pMaximizeButton->setProperty("maximizeProperty", "restore");
  131. }
  132. else
  133. {
  134. m_pMaximizeButton->setProperty("maximizeProperty", "maximize");
  135. m_pMaximizeButton->setToolTip(tr("Maximize"));
  136. }
  137. m_pMaximizeButton->setStyle(QApplication::style());
  138. }
  139. }

接口说明

  • mousePressEvent

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

  • mouseDoubleClickEvent

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

  • eventFilter

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

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

  • updateMaximize

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

使用方式

  1. Widget::Widget(QWidget *parent)
  2. : QWidget(parent)
  3. {
  4. setWindowFlags(Qt::FramelessWindowHint | windowFlags());
  5. TitleBar *pTitleBar = new TitleBar(this);
  6. installEventFilter(pTitleBar);
  7. resize(400, 300);
  8. setWindowTitle("Custom Window");
  9. setWindowIcon(QIcon(":/Images/logo"));
  10. QPalette pal(palette());
  11. pal.setColor(QPalette::Background, QColor(50, 50, 50));
  12. setAutoFillBackground(true);
  13. setPalette(pal);
  14. QVBoxLayout *pLayout = new QVBoxLayout();
  15. pLayout->addWidget(pTitleBar);
  16. pLayout->addStretch();
  17. pLayout->setSpacing(0);
  18. pLayout->setContentsMargins(0, 0, 0, 0);
  19. setLayout(pLayout);
  20. }

注意

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

Qt之自定义界面(添加自定义标题栏)的更多相关文章

  1. paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制

    源地址:http://blog.csdn.net/attilax/article/details/12343625 paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制 效果图: ...

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

    简述 通过上节内容,我们实现了自定义窗体的移动,但是我们缺少一个标题栏来显示窗体的图标.标题,以及控制窗体最小化.最大化.关闭的按钮. 自定义标题栏后,所有的控件我们都可以定制,比如:在标题栏中添加换 ...

  3. 【Qt】Qt之自定义界面(窗体缩放-跨平台终极版)【转】

    简述 通过上一节内容,我们实现了窗体的缩放,功能很不错,但是很遗憾-不支持跨平台!如果对于多平台来说,这是一个硬伤,所以,我们急需要一个能够支持跨平台的实现方案. 在网上看到过很多不同的实现方式,多多 ...

  4. Qt之自定义界面(窗体缩放-跨平台终极版)

    简述 通过上一节内容,我们实现了窗体的缩放,功能很不错,但是很遗憾-不支持跨平台!如果对于多平台来说,这是一个硬伤,所以,我们急需要一个能够支持跨平台的实现方案. 在网上看到过很多不同的实现方式,多多 ...

  5. Qt之自定义界面(窗体缩放)

    简述 通过前两节内容,我们实现了自定义窗体的移动,以及自定义标题栏-用来显示窗体的图标.标题,以及控制窗体最小化.最大化.关闭. 在这之后,我们还缺少窗体的缩放-当鼠标移动到窗体的边框-左.上.右.下 ...

  6. Qt::QWidget 无默认标题栏边框的拖拽修改大小方式

    开发环境:win10+vs2015+qt5.9.1 背景:开发过程中,一般很少会使用系统提供的标题栏和边框:往往都是自定义一个自己设计的方案.这时候在QWidget中需要加上flag:Qt::Fram ...

  7. Qt::WindowFlags枚举类型(Qt::Widget是独立窗口和子窗口两用的,Qt::Window会有标题栏)

    Qt::Widget : QWidget构造函数的默认值,如新的窗口部件没有父窗口部件,则它是一个独立的窗口,否则就是一个子窗口部件. Qt::Window : 无论是否有父窗口部件,新窗口部件都是一 ...

  8. 【Qt】Qt之自定义界面(QMessageBox)【转】

    简述 通过前几节的自定义窗体的学习,我们可以很容易的写出一套属于自己风格的界面框架,通用于各种窗体,比如:QWidget.QDialog.QMainWindow. 大多数窗体的实现都是采用控件堆积来完 ...

  9. 【Qt】Qt之自定义界面(窗体缩放)【转】

    简述 通过前两节内容,我们实现了自定义窗体的移动,以及自定义标题栏-用来显示窗体的图标.标题,以及控制窗体最小化.最大化.关闭. 在这之后,我们还缺少窗体的缩放-当鼠标移动到窗体的边框-左.上.右.下 ...

随机推荐

  1. Could not find file '..\bin\hibernate.cfg.xml'解决方法:

    web.config: 解决方法:

  2. Android SDK Android NDK 官方下载地址

    Android NDK r6b Windows http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip Mac OS X(intel) ...

  3. Codeforces Round #328 (Div. 2) D. Super M

    题目链接: http://codeforces.com/contest/592/problem/D 题意: 给你一颗树,树上有一些必须访问的节点,你可以任选一个起点,依次访问所有的必须访问的节点,使总 ...

  4. win8 任务栏不合并隐藏标题

    让win8任务栏不合并,并且隐藏标题的办法: 效果如下: 首先让win8不合并任务栏 1.任务栏上点鼠标右键 -- "属性" 2."任务栏按钮"选择" ...

  5. [nowCoder] 子数组最大乘积

    给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积.例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以 ...

  6. httpsClient抓取证书

    在执行webservice的过程中,出现如下异常: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorExcep ...

  7. ElasticSearch小操之Marvel,Sense

    慢慢弄弄,说不好马上就要用呢,,, 嘿嘿 参考网址: http://es.xiaoleilu.com/ Elasticsearch 权威指南(中文版) 阅读地址:Elasticsearch权威指南(中 ...

  8. hdu 4497 GCD and LCM

    思路:易知L不能整除G时为0: 将L/G质因数分解,对于其中的因子p,个数为cnt,则至少有一个包含p^cnt,至少有一个数不包含p: 只有一个数包含p^cnt时,有C(3,1); 有2个数包含p^c ...

  9. Android 调节当前Activity的屏幕亮度

    调节的关键代码: WindowManager.LayoutParams layoutParams = getWindow().getAttributes(); layoutParams.screenB ...

  10. ccflow学习下载网址

    1.ccflow下载:http://ccflow.org/download.aspx 2.说明:http://ccbpm.mydoc.io/ 3.各种文档:bbs.ccflow.org/showtop ...