赞
踩
记录下Qt的自定义标题栏。
提示:以下是本篇文章正文内容,下面案例可供参考
自定义标题栏演示
:
#ifndef TITLEBAR_H #define TITLEBAR_H #include <QLabel> #include <QFrame> #include <QMovie> #include <QFont> #include <QIcon> #include <QStyle> #include <QDebug> #include <QFrame> #include <QTimer> #include <QObject> #include <QListView> #include <QShortcut> #include <QComboBox> #include <QPushButton> #include <QHBoxLayout> #include <QMouseEvent> #include <QVBoxLayout> #include <QMessageBox> #include <QApplication> #include <QDesktopWidget> #include <QPropertyAnimation> #include <QParallelAnimationGroup> #include <QGraphicsDropShadowEffect> #include "windows.h" #define PADDING 5 #ifndef SAFEDELETE #define SAFEDELETE(pointer) \ { \ if(pointer) \ { \ delete pointer; \ } \ pointer = NULL; \ } #endif namespace TITLEBAR { enum WIDGETBYTTONTYPE { MAXWIDGET, //去掉最大化按钮 MINWIDGET, //去掉最小化按钮 CloseWIDGET, //去掉关闭按钮 ALLWIDGET, //去掉除关闭按钮外的所有按钮 NOBUTTON, //去除所有按钮 }; } class TitleBar : public QFrame { Q_OBJECT public: explicit TitleBar(QWidget *parentWidget = nullptr); enum Direction { UP = 0, LEFT, RIGHT, LEFTTOP, RIGHTTOP, NONE }; void initData(); void initBotton(); //初始化按钮 void initConnect(); //初始化值 void setWindowTitle(const QString &title); //设置标题 void setWindowIcon(const QString &icon); //设置图标(为空时隐藏图标) void subWindowButton(const int &type); //设置按钮 void Shadow_Warning(); //设置阴影 void RemoveMaxMinButton(); //移除最大最小按钮 void Set_MaximizeFlag(); //设置双击标题栏是否可以最大、最小化 void Set_MouseShapeFlag(bool MouseShape); //设置标题栏是否可以改变大小 bool FileIsExist(QString strFile); //文件是否存在 void SetTitleLabelTextColor(int R,int G,int B); //修改标题显示文字颜色 const static int TITLEBARHEIGHT = 30; //标题栏高度 const static int CONTROLWIDTH = 30; //控件宽度 QRectF boundingRect() const; QRectF leftBorder() const; QRectF rightBorder() const; QRectF topBorder() const; QRectF bottomBorder() const; void setMousePressCursorShape(const QPointF& pt, bool isShow = true); public slots: void showMax(); //最大化窗口 void showMin(); //最小化窗口 void showClose(); //关闭窗口 void set_ChildWindowColor(int R,int G,int B); //设置标题栏背景色 void ModifyTitleBarTip(); //修改标题栏按钮提示语言 signals: void send_close(); //发送关闭信号 void send_showToolbar(); //发送显示/隐藏工具栏信号 private slots: private: QPushButton *maxButton; //最大化按钮 QPushButton *minButton; //最小化按钮 QPushButton *closeButton; //关闭按钮 QLabel *imgLabel; //图片框 QLabel *titleLabel; //标题名 QWidget *parentWidget; //父窗口 bool mousePress; //按钮点击标志位 QPoint movePoint; //鼠标移动需要记住的点 int switchFlag; int MaximizeFlag; //双击是否最大化 int IsShow_Toolbar; //显示隐藏工具栏 int Original_window_x; //窗口x坐标 int Original_window_y; //窗口y坐标 int Original_window_Mywidth; //窗口宽度 int Original_window_Myheight; //窗口高度 bool isTitleBarResize; //标题栏是否可以改变大小 bool isLeftPressDown; //判断左键是否按下 Direction dir; //窗口大小改变时,记录改变方向 private: void mousePressEvent(QMouseEvent * event); //鼠标点击事件 void mouseReleaseEvent(QMouseEvent *event); //鼠标释放事件 void mouseMoveEvent(QMouseEvent * event); //鼠标移动事件 void mouseDoubleClickEvent(QMouseEvent *event); //鼠标双击事件 bool eventFilter(QObject *obj, QEvent *event); void paintEvent(QPaintEvent *event); //绘制事件 }; #endif // TITLEBAR_H
代码如下(示例):
#include "titlebar.h" #include <QSizeGrip> /*************************** 构造函数 ***************************/ TitleBar::TitleBar(QWidget *parent) : QFrame(parent) { //设置父类窗口 parentWidget = parent; //初始化参数 initData(); //初始化按钮 initBotton(); //初始化 initConnect(); //设置标题栏背景色 set_ChildWindowColor(70, 70, 70); //设置标题栏显示文字颜色 SetTitleLabelTextColor(255, 255, 255); //重置窗口大小 resize(parent->width(), TITLEBARHEIGHT); setFixedHeight(TITLEBARHEIGHT); //设置阴影 //Shadow_Warning(); } void TitleBar::initData() { switchFlag = 1; MaximizeFlag = 0; isTitleBarResize = true; IsShow_Toolbar = 1; this->setMouseTracking(true); this->setAttribute(Qt::WA_Hover, true); this->installEventFilter(this); isLeftPressDown = false; this->dir = NONE; } void TitleBar::initBotton() { //最大化按钮设置图标 maxButton = new QPushButton(this); maxButton->setFocusPolicy(Qt::NoFocus); maxButton->setIcon(QPixmap("style/icons/max.png")); //最小化按钮设置图标 minButton = new QPushButton(this); minButton->setFocusPolicy(Qt::NoFocus); minButton->setIcon(QPixmap("style/icons/min.png")); //关闭按钮设置图标 closeButton = new QPushButton(this); closeButton->setShortcut(tr("Ctrl+w")); closeButton->setFocusPolicy(Qt::NoFocus); closeButton->setIcon(QPixmap("style/icons/close.png")); //设置标签 imgLabel = new QLabel(this); titleLabel = new QLabel(this); titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //设置控件大小 imgLabel->setFixedSize(CONTROLWIDTH - 5, CONTROLWIDTH - 5); imgLabel->setScaledContents(true); titleLabel->setMinimumSize(120, TITLEBARHEIGHT); minButton->setFixedSize(CONTROLWIDTH, CONTROLWIDTH); maxButton->setFixedSize(CONTROLWIDTH, CONTROLWIDTH); closeButton->setFixedSize(CONTROLWIDTH, CONTROLWIDTH); //设置控件图标大小 minButton->setIconSize(QSize(CONTROLWIDTH, CONTROLWIDTH)); maxButton->setIconSize(QSize(CONTROLWIDTH, CONTROLWIDTH)); closeButton->setIconSize(QSize(CONTROLWIDTH, CONTROLWIDTH)); //设置鼠标移至按钮上的提示信息 ModifyTitleBarTip(); //设置布局 QHBoxLayout *hBoxLayout = new QHBoxLayout; hBoxLayout->addSpacing(5); hBoxLayout->addWidget(imgLabel); hBoxLayout->addSpacing(5); hBoxLayout->addWidget(titleLabel); hBoxLayout->addStretch(); hBoxLayout->addSpacing(5); hBoxLayout->addWidget(minButton); hBoxLayout->addWidget(maxButton); hBoxLayout->addWidget(closeButton); hBoxLayout->setSpacing(0); hBoxLayout->setContentsMargins(0, 0, 2, 0); this->setLayout(hBoxLayout); } /*************************** 设置标题 ***************************/ void TitleBar::setWindowTitle(const QString &title) { QFont myFont; //设置文字大小 myFont.setPointSize(12); //设置文字字体 myFont.setFamily(qApp->font().family()); titleLabel->setFont(myFont); titleLabel->setText(title); } /*************************** 设置图标 ***************************/ void TitleBar::setWindowIcon(const QString &icon) { if (icon.isEmpty()) imgLabel->hide(); else imgLabel->setPixmap(QPixmap(icon)); } /*************************** 设置标题栏不需要显示的按钮 ***************************/ void TitleBar::subWindowButton(const int &type) { if(type == TITLEBAR::MINWIDGET) { SAFEDELETE(minButton); } else if(type == TITLEBAR::MAXWIDGET) { SAFEDELETE(maxButton); } else if(type == TITLEBAR::CloseWIDGET) { SAFEDELETE(closeButton); } else if(type == TITLEBAR::ALLWIDGET) { SAFEDELETE(minButton); SAFEDELETE(maxButton); } else if (type == TITLEBAR::NOBUTTON) { SAFEDELETE(minButton); SAFEDELETE(maxButton); SAFEDELETE(closeButton); } } void TitleBar::Shadow_Warning() { //窗口添加阴影效果 QGraphicsDropShadowEffect *shadow_effect = new QGraphicsDropShadowEffect; shadow_effect->setOffset(0, 4); shadow_effect->setColor(Qt::gray); shadow_effect->setBlurRadius(6); this->setGraphicsEffect(shadow_effect); #if 0 //实现毛玻璃效果 QGraphicsBlurEffect* ef = new QGraphicsBlurEffect; ef->setBlurRadius(1.5); ef->setBlurHints(QGraphicsBlurEffect::AnimationHint); this->setGraphicsEffect(ef); #endif } //移除最大最小按钮 void TitleBar::RemoveMaxMinButton() { subWindowButton(TITLEBAR::ALLWIDGET); } //设置双击标题栏是否可以最大、最小化 void TitleBar::Set_MaximizeFlag() { MaximizeFlag = 1; } //文件是否存在 bool TitleBar::FileIsExist(QString strFile) { QFile tempFile(strFile); return tempFile.exists(); } //修改标题显示文字颜色 void TitleBar::SetTitleLabelTextColor(int R,int G,int B) { titleLabel->setStyleSheet(QString("QLabel{background-color:transparent;color:rgb(%1,%2,%3);outline: none;border:none;qproperty-alignment: 'AlignVCenter | AlignLeft';}").arg(R).arg(G).arg(B)); } /*************************** 初始化 ***************************/ void TitleBar::initConnect() { //设置样式表 minButton->setStyleSheet("QPushButton{background-color:transparent;outline: none;border:none;}QPushButton:hover{padding-left:6px;padding-top:6px;}"); maxButton->setStyleSheet("QPushButton{background-color:transparent;outline: none;border:none;}QPushButton:hover{padding-left:6px;padding-top:6px;}"); closeButton->setStyleSheet("QPushButton{background-color:transparent;outline: none;border:none;border-radius: 0px;}QPushButton:hover{padding-left:6px;padding-top:6px;background-color:rgb(237,28,36);}"); //连接信号与槽 connect(minButton, SIGNAL(clicked(bool)), this, SLOT(showMin())); connect(maxButton, SIGNAL(clicked(bool)), this, SLOT(showMax())); connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(showClose())); } /*************************** 最大化 ***************************/ void TitleBar::showMax() { if(parentWidget->geometry() == QApplication::desktop()->availableGeometry()) //判断是否是全屏 { maxButton->setIcon(QPixmap("style/icons/max.png")); //退出全屏时设置为原窗口的坐标位置和尺寸大小 parentWidget->setGeometry(Original_window_x, Original_window_y, Original_window_Mywidth, Original_window_Myheight); } else { //但不是全屏时获取原窗口的坐标和尺寸 Original_window_x = parentWidget->geometry().x(); Original_window_y = parentWidget->geometry().y(); Original_window_Mywidth = parentWidget->geometry().width(); Original_window_Myheight = parentWidget->geometry().height(); maxButton->setIcon(QPixmap("style/icons/normal.png")); parentWidget->setGeometry(QApplication::desktop()->availableGeometry()); //这种设置不会全屏遮挡任务栏 } } /*************************** 最小化 ***************************/ void TitleBar::showMin() { parentWidget->showMinimized(); } /*************************** 发送关闭信号给主窗口 ***************************/ void TitleBar::showClose() { emit send_close(); } void TitleBar::set_ChildWindowColor(int R,int G,int B) { //设置背景色 setStyleSheet(QString("QFrame{background-color:rgb(%1,%2,%3);outline: none;border:none;}").arg(R).arg(G).arg(B)); } //修改标题栏按钮提示语言 void TitleBar::ModifyTitleBarTip() { //设置鼠标移至按钮上的提示信息 minButton->setToolTip(tr(u8"最小化")); maxButton->setToolTip(tr(u8"最大化")); closeButton->setToolTip(tr(u8"关闭")); } /*************************** 鼠标点击 ***************************/ void TitleBar::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { isLeftPressDown = true; if (isTitleBarResize) setMousePressCursorShape(event->pos()); if (dir != NONE) { this->mouseGrabber(); } else { movePoint = event->globalPos() - parentWidget->pos(); } } } /************************** 鼠标释放 ***************************/ void TitleBar::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { isLeftPressDown = false; if (dir != NONE) { dir = NONE; this->releaseMouse(); this->setCursor(QCursor(Qt::ArrowCursor)); } } } /************************** 鼠标移动 **************************/ void TitleBar::mouseMoveEvent(QMouseEvent *event) { if(parentWidget->geometry() == QApplication::desktop()->availableGeometry()) { //判断当前是全屏就不允许拖动窗口 } else { //当前不是全屏可以拖动窗口 QPoint gloPoint = event->globalPos(); QRect rect = parentWidget->rect(); QPoint tl = mapToGlobal(rect.topLeft()); QPoint rb = mapToGlobal(rect.bottomRight()); if (!isLeftPressDown) { if (isTitleBarResize) setMousePressCursorShape(gloPoint); } else { if (dir != NONE) { QRect rMove(tl, rb); switch (dir) { case LEFT: if (rb.x() - gloPoint.x() <= parentWidget->minimumWidth()) rMove.setX(tl.x()); else rMove.setX(gloPoint.x()); break; case RIGHT: rMove.setWidth(gloPoint.x() - tl.x()); break; case UP: if (rb.y() - gloPoint.y() <= parentWidget->minimumHeight()) rMove.setY(tl.y()); else rMove.setY(gloPoint.y()); break; case LEFTTOP: if (rb.x() - gloPoint.x() <= parentWidget->minimumWidth()) rMove.setX(tl.x()); else rMove.setX(gloPoint.x()); if (rb.y() - gloPoint.y() <= parentWidget->minimumHeight()) rMove.setY(tl.y()); else rMove.setY(gloPoint.y()); break; case RIGHTTOP: rMove.setWidth(gloPoint.x() - tl.x()); if (rb.y() - gloPoint.y() <= parentWidget->minimumHeight()) rMove.setY(tl.y()); else rMove.setY(gloPoint.y()); break; default: break; } parentWidget->setGeometry(rMove); } else { QPoint movePos = event->globalPos(); parentWidget->move(movePos - movePoint); if(parentWidget->pos().y() <= 0) parentWidget->move(parentWidget->x(), 0); if(parentWidget->pos().y() + this->height() >= QApplication::desktop()->availableGeometry().height()) parentWidget->move(parentWidget->x(), QApplication::desktop()->availableGeometry().height() - this->height()); event->accept(); } } } } /************************** 鼠标双击 **************************/ void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { if(MaximizeFlag == 1) { int x = event->x(); int y = event->y(); if((x > 0 && x < parentWidget->width()) && (y > 0 && y < TITLEBARHEIGHT)) //如果双击的范围在标题栏的范围之内 { showMax(); //调用全屏、退出全屏函数 } } } } bool TitleBar::eventFilter(QObject * obj, QEvent * event) { if (obj == this) { if (event->type() == QMouseEvent::HoverEnter) { QMouseEvent *_mouseEvent = static_cast<QMouseEvent *>(event); if (isTitleBarResize) setMousePressCursorShape(_mouseEvent->pos(), false); } if (event->type() == QMouseEvent::HoverMove) { QMouseEvent *_mouseEvent = static_cast<QMouseEvent *>(event); if (!isLeftPressDown) { if (isTitleBarResize) setMousePressCursorShape(_mouseEvent->pos(), false); } } if (event->type() == QMouseEvent::HoverLeave) { if (isTitleBarResize) unsetCursor(); } } return QFrame::eventFilter(obj, event); } void TitleBar::Set_MouseShapeFlag(bool MouseShape) { isTitleBarResize = MouseShape; } QRectF TitleBar::boundingRect() const { return QRectF(QPointF(0, 0), geometry().size()); } QRectF TitleBar::leftBorder() const { return QRectF(0, 0, PADDING, boundingRect().height()); } QRectF TitleBar::rightBorder() const { return QRectF(boundingRect().width() - PADDING, 0, PADDING, boundingRect().height()); } QRectF TitleBar::topBorder() const { return QRectF(0, 0, boundingRect().width(), PADDING); } QRectF TitleBar::bottomBorder() const { return QRectF(0, boundingRect().height() - PADDING, boundingRect().width(), PADDING); } void TitleBar::setMousePressCursorShape(const QPointF& pt, bool isShow) { QCursor cursor = Qt::ArrowCursor; if (rightBorder().contains(pt) && topBorder().contains(pt)) // 右上角 { if(isShow) dir = RIGHTTOP; this->setCursor(QCursor(Qt::SizeBDiagCursor)); } else if (leftBorder().contains(pt) && topBorder().contains(pt)) // 左上角 { if (isShow) dir = LEFTTOP; this->setCursor(QCursor(Qt::SizeFDiagCursor)); } else if (rightBorder().contains(pt)) // 右边 { if (isShow) dir = RIGHT; this->setCursor(QCursor(Qt::SizeHorCursor)); } else if (leftBorder().contains(pt)) // 左边 { if (isShow) dir = LEFT; this->setCursor(QCursor(Qt::SizeHorCursor)); } else if (topBorder().contains(pt)) // 上边 { if (isShow) dir = UP; this->setCursor(QCursor(Qt::SizeVerCursor)); } else { if (isShow) dir = NONE; this->setCursor(QCursor(isLeftPressDown ? Qt::SizeAllCursor : Qt::ArrowCursor)); } } // 绘制事件中设置标题栏宽度跟随父窗口宽度变化尺寸 void TitleBar::paintEvent(QPaintEvent *event) { if (this->width() != parentWidget->width()) { this->setFixedWidth(parentWidget->width()); } QFrame::paintEvent(event); }
//自定义标题栏 { Main_InterfaceTitleBar = new TitleBar(this); //在.h头文件中TitleBar *Main_InterfaceTitleBar setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint| Qt::WindowMaximizeButtonHint); //设置为无边框 connect(Main_InterfaceTitleBar, &TitleBar::send_close, this, [=]() {close();}); //一般窗口就是关闭,主界面或登录界面就是退出软件 Main_InterfaceTitleBar->Set_MaximizeFlag(); //设置是否有最大最小化按钮 Main_InterfaceTitleBar->setFixedHeight(40); //设置标题栏高度 Main_InterfaceTitleBar->Set_MouseShapeFlag(true); //设置是否可以改变窗口大小 Main_InterfaceTitleBar->setWindowIcon(":/trayIcon.png"); //这里根据自己的图标路径填写 Main_InterfaceTitleBar->setWindowTitle(tr("图像拼接处理器")); //设置标题栏标题 } //布局情况很多种,标题栏只是显示在父窗口最上面的位置,具体怎么调整根据自己的布局来设置 QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addWidget(LargeScreenTitleBar); vlayout->addLayout(...); vlayout->addWidget(...); vlayout->addWidget(...); vLayout->setContentsMargins(0, 0, 0, 0); setLayout(vlayout);
去掉标题栏和边框后是比较方便,但是却失去了系统标题栏自带的属性,下面是网上找的使用nativeEventFilter函数捕获截取系统消息实现窗口移动缩放,还带有贴边等效果。原文链接QT无边框窗体——拦截windows消息实现 。
#ifndef WINMSGFILTER_H #define WINMSGFILTER_H #include <QAbstractNativeEventFilter> #include <QDebug> #include <Windows.h> #pragma comment(lib, "dwmapi") #pragma comment(lib,"user32.lib") #include <dwmapi.h> #include <windowsx.h> class WinMsgFilter :public QAbstractNativeEventFilter { public: //过滤掉消息返回true,否则返回false bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override { int boundarySize = 7; MSG* pMsg = reinterpret_cast<MSG*>(message); switch (pMsg->message) { //去掉边框(这样比较setWindowFlags(Qt::Window | Qt::FramelessWindowHint)去掉标题栏好一些,但是高DPI下显示会有虚线) case WM_NCCALCSIZE: { *result = 0; return true; break; } //阴影 case WM_ACTIVATE: { MARGINS margins = { 1,1,1,1 }; HRESULT hr = S_OK; hr = DwmExtendFrameIntoClientArea(pMsg->hwnd, &margins); *result = hr; return true; } case WM_NCHITTEST: { //处理resize //标记只处理resize bool isResize = false; //鼠标点击的坐标 POINT ptMouse = { GET_X_LPARAM(pMsg->lParam), GET_Y_LPARAM(pMsg->lParam) }; //窗口矩形 RECT rcWindow; GetWindowRect(pMsg->hwnd, &rcWindow); RECT rcFrame = { 0,0,0,0 }; AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL); USHORT uRow = 1; USHORT uCol = 1; bool fOnResizeBorder = false; //确认鼠标指针是否在top或者bottom,顺带说一下屏幕坐标原点是左上角,窗体坐标原点也是左上角 if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + boundarySize) { fOnResizeBorder = (ptMouse.y < (rcWindow.top - rcFrame.top)); uRow = 0; isResize = true; } else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - boundarySize) { uRow = 2; isResize = true; } //确认鼠标指针是否在left或者right if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + boundarySize) { uCol = 0; // left side isResize = true; } else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - boundarySize) { uCol = 2; // right side isResize = true; } int interval = 217; //检测是不是在标题栏上,右边预留出了217的宽度,是留给关闭按钮、最大化、最小化和自定义按钮的宽度。 //这个范围设置为HTCAPTION后,鼠标按在这个区域内只会执行标题栏功能,高DPI下坐标会变, //可能会导致区域覆盖部分自定义按钮,导致按钮按下无法响应。 if (ptMouse.x >= rcWindow.left + boundarySize && ptMouse.x <= rcWindow.right - interval && ptMouse.y > rcWindow.top + boundarySize && ptMouse.y <= rcWindow.top+40) { *result = HTCAPTION; return true; } LRESULT hitTests[3][3] = { { HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT }, { HTLEFT, HTNOWHERE, HTRIGHT }, { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT }, }; if (isResize == true) { *result = hitTests[uRow][uCol]; return true; } else { return false; } } } //这里一定要返回false,否则是屏蔽所有消息了 return false; } }; #endif // WINMSGFILTER_H
可以在main.cpp中注册使用也可以单独在窗口类中重写这个nativeEventFilter函数
#include "mainwindow.h"
#include "winmsgfilter.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
WinMsgFilter wmf;
QCoreApplication::instance()->installNativeEventFilter(&wmf);
MainWindow w;
w.show();
return a.exec();
}
可根据自己需求添加删除按钮,调整标题栏大小。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。