一、Qt自定义标题栏简介

QWidget及其子类窗体组件的标题栏受操作系统的控制,即标题栏的界面风格与操作系统的主题风格相同,工程实践中需要开发者自行定义,达到美化应用程序界面的目的。

二、Qt自定义标题栏实现

1、自定义标题栏的功能

自定义标题栏需要完成功能如下:

(1)自定义标题栏需要包含最小化按钮、最大化按钮、关闭按钮、标题标签、图标标签等图形元素。

(2)标题栏的拖拽。

(3)鼠标双击标题栏实现窗体的最大化、最小化。

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_startparentWidget()->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;}
}

4、标题栏双击实现最大化、最小化

鼠标双击事件处理函数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();}}
}

三、Qt自定义窗体基类示例

1、自定义窗体基类的功能

自定义窗体基类的功能如下:

(1)自定义标题栏。

(2)增加内容组件,内容组件内部的界面布局完全由具体的用户决定。

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_startparentWidget()->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 guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = 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.0SOURCES += \main.cpp \TitleBar.cpp \QWindowBase.cppHEADERS += \TitleBar.h \CommonHelper.h \QWindowBase.hRESOURCES += \TitileBarDemo.qrc

工程目录结构:

lightblue.qss:

QPalette{background:#EAF7FF;}*{outline:0px;color:#386487;}QWidget#Contents{background:#C0DEF6;
}QWidget .QLabel{min-height:30px;background:transparent;
}QWidget[titleBar="true"] .QPushButton#minimizeButton{border-style:none;border:0px solid #C0DEF6;image:url(:/images/Min.png);
}QWidget[titleBar="true"] .QPushButton#maximizeButton{border-style:none;border:0px solid #C0DEF6;image:url(:/images/Max.png);
}QWidget[titleBar="true"] .QPushButton#closeButton{border-style:none;border:0px solid #C0DEF6;image:url(:/images/Close.png);
}

3、自定义窗体基类结果展示

运行结果:

Hello Qt——Qt自定义标题栏相关推荐

  1. Qt实现自定义标题栏

    Qt实现自定义标题栏 方案思路 方案思路 1.去除自动生成的标题栏 2.添加顶部工具栏 3.在工具栏上面添加放大.缩小.关闭按钮 4.添加槽函数指定其动作,重写鼠标双击.拖动事件 实现效果 第一步 t ...

  2. Qt实战案例(42)——利用Qt实现自定义标题栏功能(自定义最大化、最小化、关闭等功能)

    目录 一.项目介绍(为什么要自自定义标题栏功能) 二.项目基本配置 三.UI界面设计 四.主程序实现 4.1 隐藏边框 4.2 设置最大化(还原),最小化,关闭按钮的样式风格 4.3 关闭按钮的实现 ...

  3. Qt 自定义标题栏,最小化、最大化、关闭窗口,双击最大化,鼠标拖动等效果实现

    文章目录 前言 效果 代码 .pro文件 widget.h widget.cpp widget.ui title.h title.cpp title.ui 前言 本次实验内容为Qt自定义标题栏,最小化 ...

  4. 【QT 5 设置自定义标题栏+学习:《QT实现鼠标拖动调整窗口大小》+基础样例】

    [QT 5 设置自定义标题栏+学习:<QT实现鼠标拖动调整窗口大小>+基础样例] 1.说明 2.实验环境 3.实验目的 4.参考文章 5.实验步骤 (1)下载代码,运行没有错误. (2)加 ...

  5. Qt在win10自定义标题栏,应用主题颜色到标题栏

    Qt在win10自定义标题栏,应用主题颜色到标题栏 前言 先看效果 关键点 QtWin 注册表获取是否应用了颜色到标题栏 代码 头文件:captionwidget.h 源文件:captionwidge ...

  6. Qt 之 自定义窗口标题栏 之 窗口拉伸

    一.简述 之前写了一篇 Qt 之 自定义窗口标题栏 ,用重写了窗口的标题栏,今天为此篇的续篇,对自定义窗口再进行拓展,因为进行了自定义窗口标题栏,去掉了窗口原有的边框,所以鼠标放置窗口边框对窗口进行拉 ...

  7. Qt第二十七章:QWidget、QMainWindow无边框自定义标题栏并自由移动、缩放、圆角

    前提:UI必須采用自适应布局.  自定义组件[直接CV]custom_components.py # 自定义组件 """ QCustomTitleBar:自定义标题 QW ...

  8. Qt 之 自定义提示信息框—迅雷风格

    一.简述 最近一直在研究迅雷9的界面,花了点时间做了几个通用的提示信息框,整体风格与迅雷9界面相同.支持模态和非模态两种模式窗口.提示框效果见下图. 我们可以根据设置不同的参数来设置提示框标题.显示内 ...

  9. Qt Creator自定义构建过程

    Qt Creator自定义构建过程 自定义构建过程 自定义构建过程 要配置项目的构建,部署和运行方式,请选择"工具" >"选项" >"构建 ...

  10. QT实现自定义3D材质

    QT实现自定义3D材质 项目简介 项目技术 项目展示 主要源码片段解析 获取完整项目源码传送门 项目简介 Qt 3D:高级自定义材质 演示在Qt3D中创建高级材料. 此示例演示如何创建高级定制材料. ...

最新文章

  1. 在java中实现滚动文字,通过线程实现文字在屏幕上不停滚动,为什么文字不显示啊,求指点...
  2. 同为 Java 开发:有了这些 Java 项目经历,面大厂稳了!
  3. 需求分析的接口需求_再谈需求分析
  4. PHP配置问题:AppServ安装discuz出错 Fatal error:
  5. 转:UCI数据集和源代码数据挖掘的数据集资源
  6. VTK:相互作用之Assembly
  7. java中循环语句_Java语法基础之循环结构语句详解
  8. java命令详解 java -D
  9. zookeeper专题:zookeeper集群搭建和客户端连接
  10. 【Java从0到架构师】Zookeeper - 系统高可用、分布式的基本概念、Zookeeper 应用场景
  11. 简说设计模式——组合模式
  12. Hadoop介绍及最新稳定版Hadoop 2.4.1下载地址及单节点安装
  13. XSS的基本概念和原理
  14. 汪华关于移动互联网兴起三大问题的解决
  15. word文档总让正文与目录分开在不同的页——分页符的使用
  16. mysql单表瓶颈_mysql单表性能瓶颈_优化系列 | 实例解析MySQL性能瓶颈排查定位-云栖社区-阿里云...
  17. Android中使用自定义的view实现圆形图片的效果
  18. DataFactory造数-前期准备工作(DF安装、myodbc32的安装与配置、Oracle客户端的安装与配置)
  19. 微信小程序Demo组件大全(对话框、指示器、五星评分,画廊,影院座位……
  20. snail mock_HTML5 2D游戏开发,Snail Bait简介

热门文章

  1. 友好的可视化工具——trelliscope
  2. Vs2008调试慢的问题
  3. 各种编码格式(非常经典)
  4. 使用python读写灰度图像
  5. 如何用golang远程控制浏览器
  6. 预言机(Oracle)
  7. 八字易经算法之用JAVA实现最简单的称骨算命法
  8. VINS-Mono 论文公式推导与代码解析
  9. 4.25 C语言练习(然后是几点:根据起始时间和流逝的时间计算出终止时间。计算当前时间经过那么多分钟后是几点,结果也表示为四位数字。)
  10. 长风破浪正其时,Python天堑变通途(3)(令人智熄的分支循环,优先级问题)