在企业开发中,当做一款软件时,肯定会接触到标题栏的设计。在Qt中QWidget以及QMainWindow或者QDialog虽然有自带的标题栏,但是都不美观。如果想自定义美观的标题栏,我们需要自己重写标题栏,话不多说,上视频。以下就是我们自己定义的标题栏,现在我来教一下如何实现这个界面。 这个标题栏可以用在自己的企业开发中。
testBaseTitleBarDemo
以下是源代码文件,我来给大家介绍一下每一个文件的作用:
CFrameLessWidgetBase 该类为基类
CFrameLessWidgetBase .h
/*
无边框窗口基类
可拉伸
其它窗口派生于该类即可
*/
#pragma once
#include <QWidget>
class CFrameLessWidgetBase : public QWidget
{
public:
CFrameLessWidgetBase(QWidget* parent = nullptr);
~CFrameLessWidgetBase();
protected:
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
private:
int mouse_margin = 5;
};
CFrameLessWidgetBase .cpp
#include "CFrameLessWidgetBase.h"
#ifdef Q_OS_WIN
#include <qt_windows.h>
#include <Windows.h>
#include <windowsx.h>
#endif
#pragma comment(lib, "user32.lib")
#pragma comment(lib,"dwmapi.lib")
CFrameLessWidgetBase::CFrameLessWidgetBase(QWidget* parent)
{
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
setAttribute(Qt::WA_Hover);
}
CFrameLessWidgetBase::~CFrameLessWidgetBase()
{
}
bool CFrameLessWidgetBase::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
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 (nX > mouse_margin && nX < width() - mouse_margin &&
nY > mouse_margin && nY < this->height() - mouse_margin)
{
if (childAt(nX, nY) != nullptr)
return QWidget::nativeEvent(eventType, message, result);
}
// 鼠标区域位于窗体边框,进行缩放
if ((nX > 0) && (nX < mouse_margin))
*result = HTLEFT;
if ((nX > this->width() - mouse_margin) && (nX < this->width()))
*result = HTRIGHT;
if ((nY > 0) && (nY < mouse_margin))
*result = HTTOP;
if ((nY > this->height() - mouse_margin) && (nY < this->height()))
*result = HTBOTTOM;
if ((nX > 0) && (nX < mouse_margin) && (nY > 0)
&& (nY < mouse_margin))
*result = HTTOPLEFT;
if ((nX > this->width() - mouse_margin) && (nX < this->width())
&& (nY > 0) && (nY < mouse_margin))
*result = HTTOPRIGHT;
if ((nX > 0) && (nX < mouse_margin)
&& (nY > this->height() - mouse_margin) && (nY < this->height()))
*result = HTBOTTOMLEFT;
if ((nX > this->width() - mouse_margin) && (nX < this->width())
&& (nY > this->height() - mouse_margin) && (nY < this->height()))
*result = HTBOTTOMRIGHT;
return true;
}
}
return QWidget::nativeEvent(eventType, message, result);
}
CTitleBar 重点类(参考以下源码)
CTitleBar .h
#pragma once
#include <QWidget>
#include "ui_CTitleBar.h"
class CTitleBar : public QWidget
{
Q_OBJECT
public:
CTitleBar(QWidget *parent = Q_NULLPTR);
~CTitleBar();
protected:
void paintEvent(QPaintEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent* event) override;
signals:
void sig_close();
void sig_max(bool isMax);
private slots:
void on_Clicked();
private:
Ui::CTitleBar ui;
};
CTitleBar.cpp
#include "CTitleBar.h"
#include <QMouseEvent>
#include <QStyleOption>
#include <QPushButton>
#include <QPainter>
#include <qt_windows.h>
#pragma comment(lib, "user32.lib")
CTitleBar::CTitleBar(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//禁止父窗口影响子窗口样式
setAttribute(Qt::WA_StyledBackground);
//左上,右上圆角10;左下,右下圆角0
this->setStyleSheet("QWidget{background-color:rgb(54,54,54); \
border-top-left-radius:10px; \
border-top-right-radius:10px; \
border-bottom-left-radius:0px; \
border-bottom-right-radius:0px;}");
ui.label_title->setText(u8"我是标题");
ui.label_title->setStyleSheet("QLabel{font-family: Microsoft YaHei; \
font-size:18px; \
color:#BDC8E2;background-color:rgb(54,54,54);}");
ui.btnSet->setFixedSize(32, 32);
ui.btnSet->setText("");
ui.btnSet->setFlat(true);
ui.btnSet->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/set.svg);border:none}" \
"QPushButton:hover{" \
"background-color:rgb(99, 99, 99);" \
"background-image:url(:/titlebar/resource/titlebar/set_hover.svg);border:none;}");
ui.btnMin->setFixedSize(32, 32);
ui.btnMin->setText("");
ui.btnMin->setFlat(true);
ui.btnMin->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/min.svg);border:none}" \
"QPushButton:hover{" \
"background-color:rgb(99, 99, 99);" \
"background-image:url(:/titlebar/resource/titlebar/min_hover.svg);border:none;}");
ui.btnMax->setFixedSize(35, 35);
ui.btnMax->setFlat(true);
ui.btnMax->setText("");
ui.btnMax->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/normal.svg);border:none; \
background-position:center; \
background-repeat:no-repeat;} \
QPushButton:hover{ \
background-color:rgb(99, 99, 99); \
background-image:url(:/titlebar/resource/titlebar/normal_hover.svg);border:none;}");
ui.btnClose->setFixedSize(32, 32);
ui.btnClose->setFlat(true);
ui.btnClose->setText("");
ui.btnClose->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/close.svg);border:none}" \
"QPushButton:hover{" \
"background-color:rgb(99, 99, 99);" \
"background-image:url(:/titlebar/resource/titlebar/close_hover.svg);border:none;}");
connect(ui.btnMin, SIGNAL(clicked(bool)), this, SLOT(on_Clicked()));
connect(ui.btnMax, SIGNAL(clicked(bool)), this, SLOT(on_Clicked()));
connect(ui.btnClose, SIGNAL(clicked(bool)), this, SLOT(on_Clicked()));
}
CTitleBar::~CTitleBar()
{
}
void CTitleBar::paintEvent(QPaintEvent* event)
{
//决定样式表是否起作用
/*QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(event);*/
}
void CTitleBar::on_Clicked()
{
QPushButton* pButton = qobject_cast<QPushButton*>(sender());
QWidget* pWindow = this->window();
if (pWindow->isTopLevel())
{
if (pButton == ui.btnMin)
{
pWindow->showMinimized();
}
else if (pButton == ui.btnMax)
{
if (pWindow->isMaximized())
{
pWindow->showNormal();
ui.btnMax->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/normal.svg);border:none; \
background-position:center; \
background-repeat:no-repeat;} \
QPushButton:hover{ \
background-color:rgb(99, 99, 99); \
background-image:url(:/titlebar/resource/titlebar/normal_hover.svg);border:none;}");
emit sig_max(false);
}
else
{
pWindow->showMaximized();
ui.btnMax->setStyleSheet("QPushButton{background-image:url(:/titlebar/resource/titlebar/max.svg);border:none; \
background-position:center; \
background-repeat:no-repeat;} \
QPushButton:hover{ \
background-color:rgb(99, 99, 99); \
background-image:url(:/titlebar/resource/titlebar/max_hover.svg);border:none;}");
emit sig_max(true);
}
}
else if (pButton == ui.btnClose)
{
emit sig_close();
}
}
}
void CTitleBar::mousePressEvent(QMouseEvent* event)
{
if (ReleaseCapture())
{
QWidget* pWindow = this->window();
if (pWindow->isTopLevel())
{
SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
}
event->ignore();
}
void CTitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
emit ui.btnMax->clicked();
}
CTopWidget.h
#pragma once
#include <QWidget>
class CTopWidget : public QWidget
{
Q_OBJECT
public:
CTopWidget(QWidget* p = nullptr);
~CTopWidget();
signals:
void sig_close();
void sig_max(bool isMax);
};
CTopWidget.cpp
#include "CTopWidget.h"
#include "CTitleBar.h"
#include <QVBoxLayout>
CTopWidget::CTopWidget(QWidget* p)
:QWidget(p)
{
setAttribute(Qt::WA_StyledBackground);
this->setStyleSheet("QWidget{background-color:rgb(255, 254, 253);border-radius:10px;}");
/*this->setStyleSheet("QWidget{background-color:rgb(255, 254, 253); \
border-bottom-left-radius:15px; \
border-bottom-right-radius:15px;}");*/
QVBoxLayout* pVLay = new QVBoxLayout(this);
CTitleBar* pTitle = new CTitleBar(this);
QWidget* pWidget = new QWidget(this);
//需要指定pWidget最小尺寸,或最大尺寸
pWidget->setMinimumSize(1200, 800);
pVLay->addWidget(pTitle);
pVLay->addWidget(pWidget);
pVLay->setContentsMargins(0, 0, 0, 0);
setLayout(pVLay);
connect(pTitle, &CTitleBar::sig_close, this, &CTopWidget::sig_close);
connect(pTitle, &CTitleBar::sig_max, this, &CTopWidget::sig_max);
}
CTopWidget::~CTopWidget()
{
}
MainWidget.h
#pragma once
#include <QtWidgets/QWidget>
#include "CFrameLessWidgetBase.h"
#include "CTopWidget.h"
#include <QVBoxLayout>
#include <QGraphicsDropShadowEffect>
//派生于CFrameLessWidgetBase
class MainWidget : public CFrameLessWidgetBase
{
Q_OBJECT
public:
MainWidget(QWidget *parent = Q_NULLPTR);
private slots:
void onClose();
void onDoMax(bool isMax);
private:
QVBoxLayout* m_pMainVLay = nullptr;
CTopWidget* m_pTopWidget = nullptr;
QGraphicsDropShadowEffect* m_pShadow = nullptr;
};
MainWidget.cpp
#include "MainWidget.h"
MainWidget::MainWidget(QWidget *parent)
: CFrameLessWidgetBase(parent)
{
//设置窗体透明
this->setAttribute(Qt::WA_TranslucentBackground, true);
m_pMainVLay = new QVBoxLayout(this);
m_pTopWidget = new CTopWidget(this);
m_pMainVLay->addWidget(m_pTopWidget);
int shadow_width = 30;
m_pMainVLay->setContentsMargins(shadow_width, shadow_width, shadow_width, shadow_width);
setLayout(m_pMainVLay);
//给顶层widget设置背景颜色,不然看不见,因为底层widget已经透明了
m_pTopWidget->setStyleSheet("background-color:rgb(255, 254, 253)");
m_pShadow = new QGraphicsDropShadowEffect(this);
//设置阴影距离
m_pShadow->setOffset(0, 0);
//设置阴影颜色 686868
m_pShadow->setColor(QColor("#0000FF"));
//设置阴影区域
m_pShadow->setBlurRadius(shadow_width - 5);
//给顶层QWidget设置阴影
m_pTopWidget->setGraphicsEffect(m_pShadow);
connect(m_pTopWidget, &CTopWidget::sig_close, this, &MainWidget::onClose);
connect(m_pTopWidget, &CTopWidget::sig_max, this, &MainWidget::onDoMax);
}
void MainWidget::onClose()
{
close();
}
void MainWidget::onDoMax(bool isMax)
{
int shadow_width = 25;
if (isMax)
{
shadow_width = 0;
}
else
{
}
m_pMainVLay->setContentsMargins(shadow_width, shadow_width, shadow_width, shadow_width);
//设置阴影区域
m_pShadow->setBlurRadius(shadow_width);
//给顶层QWidget设置阴影
m_pTopWidget->setGraphicsEffect(m_pShadow);
}
最后,main.cpp
#include "MainWidget.h"
#include <QtWidgets/QApplication>
//#pragma comment(lib, "User32.lib")
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}