1 头文件
#ifndef TITLEBAR_H #define TITLEBAR_H #include <QLabel> #include <QPushButton> #include "ui_TitleBar.h" class TitleBar : public QWidget { Q_OBJECT public: explicit TitleBar(QWidget *parent = nullptr); ~TitleBar(); void setMiniBtnIcon(const QIcon& icon); void setMaxiBtnIcon(const QIcon& icon); void setCloseBtnIcon(const QIcon& icon); protected: //鼠标双击事件 virtual void mouseDoubleClickEvent(QMouseEvent *event); //鼠标按下事件 virtual void mousePressEvent(QMouseEvent *event); //鼠标释放事件 virtual void mouseReleaseEvent(QMouseEvent *event); //鼠标移动事件 virtual void mouseMoveEvent(QMouseEvent *event); //设置界面标题与图标 virtual bool eventFilter(QObject *obj, QEvent *event); private slots: //进行最小化、最大化/还原、关闭操作 void onClicked(); private: //最大化/还原 void updateMaximize(); private: Ui::TitleBar ui; QPoint pos; //鼠标当前点击坐标 bool mouse_press; //鼠标按下 }; #endif // TitleBar_H
2 cpp文件
#include <QLabel> #include <QPushButton> #include <QHBoxLayout> #include <QEvent> #include <QMouseEvent> #include <QApplication> #include "TitleBar.h" //调用WIN API #ifdef Q_OS_WIN #include <qt_windows.h> #endif TitleBar::TitleBar(QWidget *parent) : QWidget(parent) { ui.setupUi(this); mouse_press = false; //setFixedHeight(30); // 设置窗口背景透明; //setAttribute(Qt::WA_TranslucentBackground); //给按钮设置静态tooltip,当鼠标移上去时显示tooltip ui.btnMinimize->setToolTip(tr("Minimize")); ui.btnMaximize->setToolTip(tr("Maximize")); ui.btnClose->setToolTip(tr("Close")); QPalette pal(palette()); pal.setColor(QPalette::Background, QColor(150, 150, 150)); setAutoFillBackground(true); setPalette(pal); connect(ui.btnMinimize, SIGNAL(clicked(bool)), this, SLOT(onClicked())); connect(ui.btnMaximize, SIGNAL(clicked(bool)), this, SLOT(onClicked())); connect(ui.btnClose, SIGNAL(clicked(bool)), this, SLOT(onClicked())); //隐藏更换皮肤按钮 ui.btnSkin->setVisible(false); setAttribute(Qt::WA_StyledBackground); } TitleBar::~TitleBar() { } //双击标题栏进行界面的最大化/还原 void TitleBar::mouseDoubleClickEvent(QMouseEvent *event) { Q_UNUSED(event); emit ui.btnMaximize->clicked(); } void TitleBar::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { mouse_press = true; pos = event->globalPos(); } event->ignore(); } void TitleBar::mouseMoveEvent(QMouseEvent *event) { //若鼠标左键被按下 if (mouse_press) { QPoint move_pos = event->globalPos()-pos; //鼠标现在位置-原来位置 //移动主窗体 window()->move(window()->pos() + move_pos);//窗口位置+鼠标移动距离 pos = event->globalPos(); //更新位置 } event->ignore(); } void TitleBar::mouseReleaseEvent(QMouseEvent *event) { //设置鼠标为未被按下 mouse_press = false; event->ignore(); } //使用事件过滤器监听标题栏所在的窗体,所以当窗体标题、图标等信息发生改变时,标题栏也应该随之改变 bool TitleBar::eventFilter(QObject *obj, QEvent *event) { switch (event->type()) { //判断发生事件的类型 case QEvent::WindowTitleChange: { //窗口标题改变事件 QWidget *pWidget = qobject_cast<QWidget *> (obj); //获得发生事件的窗口对象 if (pWidget) { //窗体标题改变,则标题栏标题也随之改变 ui.labelTitle->setText(pWidget->windowTitle()); return true; } } break; case QEvent::WindowIconChange: { //窗口图标改变事件 QWidget *pWidget = qobject_cast<QWidget *>(obj); if (pWidget) { //窗体图标改变,则标题栏图标也随之改变 QIcon icon = pWidget->windowIcon(); // ui.labelIcon->setPixmap(icon.pixmap(ui.labelIcon->size())); return true; } } break; case QEvent::Resize: updateMaximize(); //最大化/还原 return true; default: return QWidget::eventFilter(obj, event); } return QWidget::eventFilter(obj, event); } //进行最小化、最大化/还原、关闭操作 void TitleBar::onClicked() { QPushButton *pButton = qobject_cast<QPushButton *>(sender()); QWidget *pWindow = this->window(); //获得标题栏所在的窗口 if (pWindow->isTopLevel()) { if (pButton == ui.btnMinimize) { pWindow->showMinimized(); //窗口最小化显示 } else if (pButton == ui.btnMaximize) { pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized(); //窗口最大化/还原显示 } else if (pButton == ui.btnClose) { pWindow->close(); //窗口关闭 } } } //最大化/还原 void TitleBar::updateMaximize() { QWidget *pWindow = this->window(); //获得标题栏所在的窗口 if (pWindow->isTopLevel()) { bool bMaximize = pWindow->isMaximized(); //判断窗口是不是最大化状态,是则返回true,否则返回false if (bMaximize) { //目前窗口是最大化状态,则最大化/还原的toolTip设置为"Restore" ui.btnMaximize->setToolTip(tr("Restore")); //设置按钮的属性名为"maximizeProperty" ui.btnMaximize->setProperty("maximizeProperty", "restore"); } else { //目前窗口是还原状态,则最大化/还原的toolTip设置为"Maximize" ui.btnMaximize->setToolTip(tr("Maximize")); //设置按钮的属性名为"maximizeProperty" ui.btnMaximize->setProperty("maximizeProperty", "maximize"); } ui.btnMaximize->setStyle(QApplication::style()); } } void TitleBar::setMiniBtnIcon(const QIcon& icon) { ui.btnMinimize->setIcon(icon.pixmap(ui.btnMinimize->size())); } void TitleBar::setMaxiBtnIcon(const QIcon& icon) { ui.btnMaximize->setIcon(icon.pixmap(ui.btnMaximize->size())); } void TitleBar::setCloseBtnIcon(const QIcon& icon) { ui.btnClose->setIcon(icon.pixmap(ui.btnClose->size())); }
3 使用说明
自定义标题栏使用说明(包含TitleBar.h,TitleBar.cpp,TitleBar.ui三个文件): 1主窗体类中添加头文件: //调用WIN API需要用到的头文件 [实现缩放] #ifdef Q_OS_WIN #include <qt_windows.h> #include <Windowsx.h> #endif 2主窗体类中 添加成员变量: int m_nBorderWidth;//表示鼠标位于边框缩放范围的宽度 添加成员函数: //nativeEvent主要用于进程间通信-消息传递,使用这种方式后来实现窗体的缩放 bool xxx::nativeEvent(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(eventType) MSG *param = static_cast<MSG *>(message); switch (param->message) { case WM_NCHITTEST: { int nX = GET_X_LPARAM(param->lParam) - this->geometry().x(); int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y(); // 如果鼠标位于子控件上,则不进行处理 if (childAt(nX, nY) != nullptr) return QWidget::nativeEvent(eventType, message, result); *result = HTCAPTION; // 鼠标区域位于窗体边框,进行缩放 if ((nX > 0) && (nX < m_nBorderWidth)) *result = HTLEFT; if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())) *result = HTRIGHT; if ((nY > 0) && (nY < m_nBorderWidth)) *result = HTTOP; if ((nY > this->height() - m_nBorderWidth) && (nY < this->height())) *result = HTBOTTOM; if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0) && (nY < m_nBorderWidth)) *result = HTTOPLEFT; if ((nX > this->width() - m_nBorderWidth) && (nX < this->width()) && (nY > 0) && (nY < m_nBorderWidth)) *result = HTTOPRIGHT; if ((nX > 0) && (nX < m_nBorderWidth) && (nY > this->height() - m_nBorderWidth) && (nY < this->height())) *result = HTBOTTOMLEFT; if ((nX > this->width() - m_nBorderWidth) && (nX < this->width()) && (nY > this->height() - m_nBorderWidth) && (nY < this->height())) *result = HTBOTTOMRIGHT; return true; } } return QWidget::nativeEvent(eventType, message, result); } 3 在widget中应用自定义标题栏 (1)在需要添加自定义标题栏的widget的ui文件中,拖动一个widget加入到当前widget布局的最上方,然后提升控件类为TitleBar (2)主窗体类的构造函数中添加如下代码: //Qt::FramelessWindowHint设置窗口标志为无边框,而Qt::WindowStaysOnTopHint使窗口位于所有界面之上 setWindowFlags(Qt::FramelessWindowHint); //ui中提升控件 installEventFilter(ui.widget);//ui.widget 为布局中提升的自定义标题控件 //设置标题栏标题 图标 按钮图标,可在ui文件中直接修改,也可在代码中修改 setWindowTitle("Custom Window"); setWindowIcon(QIcon("")); ui.widget->setMiniBtnIcon(QIcon("")); ui.widget->setMaxiBtnIcon(QIcon("")); ui.widget->setCloseBtnIcon(QIcon("")); m_nBorderWidth= 5; 4 在mainwindow中应用自定义标题栏 (1)新建一个widget,拖动一个子widget到当前widget布局的最上放,提升控件为TitleBar (2) 在当前widget的类中添加头文件,成员变量和成员函数,同上 (3)在当前widget的构造函数中添加如下代码 //Qt::FramelessWindowHint设置窗口标志为无边框,而Qt::WindowStaysOnTopHint使窗口位于所有界面之上 setWindowFlags(Qt::FramelessWindowHint); //ui中提升控件 installEventFilter(ui.widget);//ui.widget 为布局中提升的自定义标题控件 //设置标题栏标题 图标 按钮图标,可在ui文件中直接修改,也可在代码中修改 /* setWindowTitle("Custom Window"); setWindowIcon(QIcon("")); ui.widget->setMiniBtnIcon(QIcon("")); ui.widget->setMaxiBtnIcon(QIcon("")); ui.widget->setCloseBtnIcon(QIcon("")); */ m_nBorderWidth= 5; //MainWindow为需要添加自定义标题栏的主界面类 MainWindow *maindow = new MainWindow(this); maindow->setWindowFlags(Qt::FramelessWindowHint); /* QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addWidget(ui.titlebar_widget_); QString path = QStringLiteral(":/png/最小化.png"); QIcon minicon(path); ui.titlebar_widget_->setMiniBtnIcon(minicon); path = QStringLiteral(":/png/窗口.png"); QIcon maxicon(path); ui.titlebar_widget_->setMaxiBtnIcon(maxicon); path = QStringLiteral(":/png/关 闭.png"); QIcon closeicon(path); ui.titlebar_widget_->setCloseBtnIcon(closeicon); QString filestyle = QStringLiteral("background-image: url(:/png/标题栏-背景.png);"); ui.titlebar_widget_->setStyleSheet(filestyle); */ QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addWidget(ui.titlebar_widget_); vlayout->addWidget(maindow); //设置布局距离上下左右的距离,根据需要设置,也可在ui中修改 vlayout->setContentsMargins(2,1,2,1); setLayout(vlayout); (4)在显示主界面的时候,在main函数中将MainWindow类换为新加的widget,即可显示自定义标题栏
4 ui文件见上传文件