QWidget及其子类窗体组件的标题栏受操作系统的控制,即标题栏的界面风格与操作系统的主题风格相同,工程实践中需要开发者自行定一,达到美化应用程序界面的目的。 一、Qt自定义标题栏实现 1、自定义标题栏的功能 自定义标题栏需要完成功能如下: (1)自定义标题栏需要包含最小化按钮、最大化按钮、关闭按钮、标题标签、图标标签等图形元素。 (2)标题栏的拖拽。 (3)鼠标双击标题栏实现窗体的最大化、最小化。 2、自定义标题栏的界面布局 自定义标题栏的界面布局如下: 3、标题栏拖拽功能的实现 窗体的拖拽平移过程如下图: 当鼠标在窗体的标题栏按下并移动时,窗体会按照鼠标移动的轨迹进行平移。因此,窗体每次移动都是在当前位置按照鼠标移动的矢量进行移动。标题栏拖拽功能的实现需要实现mousePressEvent、mouseMoveEvent、mouseReleaseEvent三个事件处理函数。 MouseEvent中的globalPos()函数返回的是相对屏幕的位置坐标,而pos()则是返回鼠标在当前控件(即捕获该鼠标事件的控件)中的位置。QWidget窗体的geometry()。topLeft()则返回的是当前窗体的左上角在屏幕中的位置。startPoseventglobalPos();鼠标的全局初始位置,按下时记住curWindowPosgeometry()。topleft();窗体的全部位置,移动时endPoseventglobalPos();鼠标按下发生移动之后的位置,移动时move(curWindowPos(startPosendPos));根据矢量移动方向是初始位置减去末位置,移动时startPosendPos;将初始位置记为上次末位置,然后执行直到释放拖拽,移动时 实现代码如下:voidTitleBar::mousePressEvent(QMouseEventevent){鼠标左键按下事件if(eventbutton()Qt::LeftButton){记录鼠标左键状态mleftButtonPressedtrue;记录鼠标在屏幕中的位置mstarteventglobalPos();}}voidTitleBar::mouseMoveEvent(QMouseEventevent){持续按住才做对应事件if(mleftButtonPressed){将父窗体移动到父窗体原来的位置加上鼠标移动的位置:eventglobalPos()mstartparentWidget()move(parentWidget()geometry()。topLeft()eventglobalPos()mstart);将鼠标在屏幕中的位置替换为新的位置mstarteventglobalPos();}}voidTitleBar::mouseReleaseEvent(QMouseEventevent){鼠标左键释放if(eventbutton()Qt::LeftButton){记录鼠标状态mleftButtonPressedfalse;}} 4、标题栏双击实现最大化、最小化 鼠标双击事件处理函数mouseDoubleClickEvent实现如下:voidTitleBar::mouseDoubleClickEvent(QMouseEventevent){mmaximizeButtonclick();} 最大化、最小化、关闭按钮的槽函数如下:voidTitleBar::onClicked(){QPushButtonpButtonqobjectcastQPushButton(sender());QWidgetpWindowthiswindow();if(pWindowisTopLevel()){if(pButtonmminimizeButton){pWindowshowMinimized();}elseif(pButtonmmaximizeButton){pWindowisMaximized()?pWindowshowNormal():pWindowshowMaximized();}elseif(pButtonmcloseButton){pWindowclose();}}} 二、Qt自定义窗体基类示例 1、自定义窗体基类的功能 自定义窗体基类的功能如下: (1)自定义标题栏。 (2)增加内容组件,内容组件内部的界面布局完全由具体的用户决定。 2、自定义窗体基类的实现 TitleBar。h文件:ifndefTITLEBARHdefineTITLEBARHincludeQWidgetincludeQPushButtonincludeQLabelincludeQHBoxLayoutincludeQEventincludeQMouseEventincludeQApplicationincludeQPointincludeQPixmapincludeQStringbrief标题栏界面组件authorclassTitleBar:publicQWidget{QOBJECTpublic:explicitTitleBar(QWidgetparentNULL);brief设置标题栏标题paramtitle,参数,设置的标题voidsetWindowTitle(constQStringtitle);brief设置标题栏的图标paramiconPath,参数,图标的路径voidSetTitleBarIcon(constQStringiconPath);protected:brief鼠标双击事件处理函数paramevent,参数,事件note双击标题栏进行界面的最大化还原virtualvoidmouseDoubleClickEvent(QMouseEventevent);brief鼠标按下事件处理函数paramevent,参数,事件note按下鼠标左键virtualvoidmousePressEvent(QMouseEventevent);brief鼠标移动事件处理函数paramevent,参数,事件note移动鼠标virtualvoidmouseMoveEvent(QMouseEventevent);brief鼠标释放事件处理函数paramevent,参数,事件note释放鼠标virtualvoidmouseReleaseEvent(QMouseEventevent);brief事件过滤处理器paramobj,参数paramevent,参数,事件return成功返回true,失败返回falsenote设置标题、图标virtualbooleventFilter(QObjectobj,QEventevent);brief最大化还原voidupdateMaximize();protectedslots:brief最小化、最大化还原、关闭按钮点击时响应的槽函数voidonClicked();private:QLabelmiconLabel;QLabelmtitleLabel;QPushButtonmminimizeButton;QPushButtonmmaximizeButton;QPushButtonmcloseButton;QPointmstart;起始点QPointmend;结束点boolmleftButtonPressed;鼠标左键按下标记};endifTITLEBARH TitleBar。cpp文件:includeTitleBar。hTitleBar::TitleBar(QWidgetparent):QWidget(parent){setFixedHeight(30);setWindowFlags(Qt::FramelessWindowHint);miconLabelnewQLabel(this);miconLabelsetFixedSize(20,20);miconLabelsetScaledContents(true);mtitleLabelnewQLabel(this);mtitleLabelsetSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);mminimizeButtonnewQPushButton(this);mminimizeButtonsetFixedSize(27,22);mminimizeButtonsetObjectName(minimizeButton);mmaximizeButtonnewQPushButton(this);mmaximizeButtonsetFixedSize(27,22);mmaximizeButtonsetObjectName(maximizeButton);mcloseButtonnewQPushButton(this);mcloseButtonsetFixedSize(27,22);mcloseButtonsetObjectName(closeButton);QHBoxLayoutlayoutnewQHBoxLayout;layoutaddWidget(miconLabel);layoutaddStretch(1);layoutaddWidget(mtitleLabel);layoutaddStretch(1);layoutaddWidget(mminimizeButton);layoutaddWidget(mmaximizeButton);layoutaddWidget(mcloseButton);setLayout(layout);setProperty(titleBar,true);setObjectName(titleBar);connect(mminimizeButton,SIGNAL(clicked(bool)),this,SLOT(onClicked()));connect(mmaximizeButton,SIGNAL(clicked(bool)),this,SLOT(onClicked()));connect(mcloseButton,SIGNAL(clicked(bool)),this,SLOT(onClicked()));}voidTitleBar::setWindowTitle(constQStringtitle){mtitleLabelsetAlignment(Qt::AlignCenter);mtitleLabelsetText(title);}voidTitleBar::SetTitleBarIcon(constQStringiconPath){QPixmapmap(iconPath);miconLabelsetPixmap(map);}voidTitleBar::mouseDoubleClickEvent(QMouseEventevent){mmaximizeButtonclick();}voidTitleBar::mousePressEvent(QMouseEventevent){鼠标左键按下事件if(eventbutton()Qt::LeftButton){记录鼠标左键状态mleftButtonPressedtrue;记录鼠标在屏幕中的位置mstarteventglobalPos();}}voidTitleBar::mouseMoveEvent(QMouseEventevent){持续按住才做对应事件if(mleftButtonPressed){将父窗体移动到父窗体原来的位置加上鼠标移动的位置:eventglobalPos()mstartparentWidget()move(parentWidget()geometry()。topLeft()eventglobalPos()mstart);将鼠标在屏幕中的位置替换为新的位置mstarteventglobalPos();}}voidTitleBar::mouseReleaseEvent(QMouseEventevent){鼠标左键释放if(eventbutton()Qt::LeftButton){记录鼠标状态mleftButtonPressedfalse;}}boolTitleBar::eventFilter(QObjectobj,QEventevent){switch(eventtype()){设置标题caseQEvent::WindowTitleChange:{QWidgetpWidgetqobjectcastQWidget(obj);if(pWidget){mtitleLabelsetText(pWidgetwindowTitle());returntrue;}}设置图标caseQEvent::WindowIconChange:{QWidgetpWidgetqobjectcastQWidget(obj);if(pWidget){QIconiconpWidgetwindowIcon();miconLabelsetPixmap(icon。pixmap(miconLabelsize()));returntrue;}}窗口状态变化、窗口大小变化caseQEvent::WindowStateChange:caseQEvent::Resize:updateMaximize();returntrue;}returnQWidget::eventFilter(obj,event);}voidTitleBar::updateMaximize(){QWidgetpWindowthiswindow();if(pWindowisTopLevel()){boolbMaximizepWindowisMaximized();if(bMaximize){mmaximizeButtonsetToolTip(tr(Restore));mmaximizeButtonsetProperty(maximizeProperty,restore);}else{mmaximizeButtonsetProperty(maximizeProperty,maximize);mmaximizeButtonsetToolTip(tr(Maximize));}mmaximizeButtonsetStyle(QApplication::style());}}voidTitleBar::onClicked(){QPushButtonpButtonqobjectcastQPushButton(sender());QWidgetpWindowthiswindow();if(pWindowisTopLevel()){if(pButtonmminimizeButton){pWindowshowMinimized();}elseif(pButtonmmaximizeButton){pWindowisMaximized()?pWindowshowNormal():pWindowshowMaximized();}elseif(pButtonmcloseButton){pWindowclose();}}} QWindowBase。h文件:ifndefQWINDOWBASEHdefineQWINDOWBASEHincludeQFrameincludeQWidgetincludeQVBoxLayoutincludeTitleBar。hbrief界面组件基类noteQWindowBase界面组件主要用作顶层窗口,对于非顶层窗口的界面组件使用QWidget。classQWindowBase:publicQFrame{QOBJECTpublic:QWindowBase(QFrameparentNULL);brief设置标题paramtitle,输入参数,标题内容voidsetWindowTitle(constQStringtitle);brief设置标题栏的图标paramiconPath,输入参数,图标资源路径voidSetTitleBarIcon(constQStringiconPath);brief获取内容组件对象指针return返回QWidgetQWidgetcontentWidget();brief设置标题栏高度paramh,输入参数,标题栏高度voidsetWindowTitleHeight(inth);private:QWidgetmcontentWidget;内容组件TitleBarmtitleBar;标题栏QVBoxLayoutmlayout;布局管理器};endifQWINDOWBASEH QWindowBase。cpp文件:includeQWindowBase。hQWindowBase::QWindowBase(QFrameparent):QFrame(parent){setWindowFlags(windowFlags()Qt::FramelessWindowHint);mtitleBarnewTitleBar(this);mcontentWidgetnewQWidget(this);mcontentWidgetsetObjectName(Contents);mlayoutnewQVBoxLayout;mlayoutaddWidget(mtitleBar);mlayoutaddWidget(mcontentWidget);mlayoutsetSpacing(0);mlayoutsetContentsMargins(0,0,0,0);setLayout(mlayout);}voidQWindowBase::setWindowTitle(constQStringtitle){mtitleBarsetWindowTitle(title);}voidQWindowBase::SetTitleBarIcon(constQStringiconPath){mtitleBarSetTitleBarIcon(iconPath);}QWidgetQWindowBase::contentWidget(){returnmcontentWidget;}voidQWindowBase::setWindowTitleHeight(inth){mtitleBarsetFixedHeight(h);} CommonHelper。h文件:ifndefCOMMONHELPERHdefineCOMMONHELPERHincludeQStringincludeQFileincludeQApplicationincludeQDebugincludeQColorincludeQPalettebrief通用功能辅助类classCommonHelper{public:brief为应用程序设置QSS样式表paramfilepath,输入参数,QSS文件路径staticvoidsetStyleSheet(constQStringfilepath){加载样式文件QFileqss(filepath);if(qss。open(QFile::ReadOnly)){QStringstylesheetQLatin1String(qss。readAll());QStringpaletteColorstylesheet。mid(20,7);qAppsetPalette(QPalette(QColor(paletteColor)));qAppsetStyleSheet(stylesheet);}}};endifCOMMONHELPERH 点击领取Qt学习资料视频教程链接 main。cpp文件:includeQApplicationincludeCommonHelper。hincludeQWindowBase。hincludeQPushButtonincludeQVBoxLayoutincludeQHBoxLayoutincludeQTreeViewintmain(intargc,charargv〔〕){QApplicationa(argc,argv);QWindowBasew;w。setWindowTitle(WidgetBase);QPushButtonbutton1newQPushButton(OK);QHBoxLayouthLayout1newQHBoxLayout;hLayout1addStretch(1);hLayout1addWidget(button1);QVBoxLayoutlayoutnewQVBoxLayout;QTreeViewtreeViewnewQTreeView;layoutaddWidget(treeView);layoutaddLayout(hLayout1);layoutaddStretch(1);w。contentWidget()setLayout(layout);w。setWindowTitleHeight(40);w。show();CommonHelper::setStyleSheet(:qsslightblue。qss);returna。exec();} 工程文件:QTcoreguigreaterThan(QTMAJORVERSION,4):QTwidgetsTARGETTitleBarDemoTEMPLATEappThefollowingdefinemakesyourcompileremitwarningsifyouuseanyfeatureofQtwhichhasbeenmarkedasdeprecated(theexactwarningsdependonyourcompiler)。PleaseconsultthedocumentationofthedeprecatedAPIinordertoknowhowtoportyourcodeawayfromit。DEFINESQTDEPRECATEDWARNINGSYoucanalsomakeyourcodefailtocompileifyouusedeprecatedAPIs。Inordertodoso,uncommentthefollowingline。YoucanalsoselecttodisabledeprecatedAPIsonlyuptoacertainversionofQt。DEFINESQTDISABLEDEPRECATEDBEFORE0x060000disablesalltheAPIsdeprecatedbeforeQt6。0。0SOURCESmain。cppTitleBar。cppQWindowBase。cppHEADERSTitleBar。hCommonHelper。hQWindowBase。hRESOURCESTitileBarDemo。qrc 工程目录结构: 3、自定义窗体基类结果展示 运行结果: