最终效果
白色背景
红色阴影
灰色标题栏
全透明
接口与功能预览
// 设置标题栏背景色
void setTitleBarColor(const QColor &color);
// 设置标题文字颜色
void setTitleTextColor(const QColor &color);
// 设置标题文字字体
void setTitleTextFont(const QFont &font);
// 设置标题
void setTitleText(const QString &text);
// 设置标题栏图标
void setTitleIcon(const QString &path);
// 设置标题栏图标
void setTitleIcon(const QPixmap &icon);
// 设置窗口颜色
void setBackgroundColor(const QColor &color);
// 设置边框圆角半径
void setRadius(const uint &r);
// 设置边框阴影颜色
void setShadowColor(const QColor &color);
// 设置边框阴影范围
void setBlurRadius(const uint &r);
// 设置隐藏标题栏最小化按扭
void setHiddenMin(const bool &is);
// 设置隐藏标题栏最大化按扭
void setHiddenMax(const bool &is);
// 设置隐藏标题栏
void setHiddenTitleBar(const bool &is);
// 设置标题栏高度
void setTitleBarHeight(const uint &h);
// 设置标题栏最小化图标
void setMinIcon(const QIcon &icon);
// 设置标题栏最大化图标
void setMaxIcon(const QIcon &icon);
// 设置标题栏关闭图标
void setCloseIcon(const QIcon &icon);
// 设置标题栏最小化按钮鼠标悬浮时背景色
void setHoverColorMin(const QColor &color);
// 设置标题栏最大化按钮鼠标悬浮时背景色
void setHoverColorMax(const QColor &color);
// 设置标题栏关闭按钮鼠标悬浮时背景色
void setHoverColorClose(const QColor &color);
// 设置标题栏最小化按钮鼠标按下时背景色
void setPressedColorMin(const QColor &color);
// 设置标题栏最大化按钮鼠标按下时背景色
void setPressedColorMax(const QColor &color);
// 设置标题栏关闭按钮鼠标按下时背景色
void setPressedColorClose(const QColor &color);
// 向标题后面添加控件
void addWidgetToTitleBar(QWidget *w);
// 向标题后面添加控件
void addLayoutToTitleBar(QLayout *layout);
下载地址
github:https://github.com/yibobunengyuntian/FrameWgt
百度网盘:链接:https://pan.baidu.com/s/1dw4DUNJCfD9Q6iHje-mLQA?pwd=1008 提取码:1008
前话
qt窗口的默认边框样式都是根据操作系统固定的,在写项目的时候,总会自己隐藏边框然后重新实现关闭、最小化等相关功能; 在网上找一些无边框窗口的解决方案,大都不怎么如意,且不太适合复用,自由度低;所以 工作之余花了一些时间自己实现了一个高复用且自由度高的方案;当然,此方案也并不完美。
完全自定义解决方案; QWidget 自定义边框、标题栏样式;自定义最小化、最大化、关闭图标及样式;可移动、拉伸、缩放;自定义窗口阴影、圆角且不影响窗口最大化。
项目分析
阴影的实现开始用的QGraphicsDropShadowEffect方案, 结果发现这个方案在某些情况下cpu占用较大, 性能下降严重(特别表现在程序使用QGraphics的时候);所以采取了重写paintEvent自己绘制阴影效果。
使用方式
pro文件引入
include($$PWD/FrameWgt/FrameWgt.pri)
#include "framewgt.h" // 头文件引入
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *w = new QWidget; // 假设此窗口为你的窗口
int r = 10; // 圆角半径
// 你的窗口需要有背景色和你需要的圆角,否则会背景透明
w->setStyleSheet(QString("QWidget{background-color: white;border-bottom-left-radius: %1px;border-bottom-right-radius: %1px;}").arg(r));
FrameWgt *pFrameWgt = new FrameWgt(w); // 将你的窗口加入边框
pFrameWgt->setTitleIcon("D:/test/Ui_test/res/widget.png"); //设置标题栏图标
pFrameWgt->setTitleText("无边框窗口"); // 设置标题文字
pFrameWgt->setShadowColor(QColor(255, 0, 0, 100)); // 设置阴影颜色
pFrameWgt->setBlurRadius(10); // 设置阴影范围
pFrameWgt->setRadius(r); // 设置边框圆角
pFrameWgt->setBackgroundColor(Qt::white); // 设置背景色
// QPushButton *btn = new QPushButton("自定义按钮");
// pFrameWgt->addWidgetToTitleBar(btn);
//其他设置...
pFrameWgt->show();
return a.exec();
}
主要代码
framewgt.h
此文件就是所提供的全部接口
#ifndef FRAMEWGT_H
#define FRAMEWGT_H
#include <QWidget>
#include <QGridLayout>
#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include "titlebar.h"
class FrameWgt : public QWidget
{
Q_OBJECT
public:
explicit FrameWgt(QWidget *centerWidget);
~FrameWgt();
// 设置标题栏背景色
void setTitleBarColor(const QColor &color);
// 设置标题文字颜色
void setTitleTextColor(const QColor &color);
// 设置标题文字字体
void setTitleTextFont(const QFont &font);
// 设置标题
void setTitleText(const QString &text);
// 设置标题栏图标
void setTitleIcon(const QString &path);
// 设置标题栏图标
void setTitleIcon(const QPixmap &icon);
// 设置窗口颜色
void setBackgroundColor(const QColor &color);
// 设置边框圆角半径
void setRadius(const uint &r);
// 设置边框阴影颜色
void setShadowColor(const QColor &color);
// 设置边框阴影范围
void setBlurRadius(const uint &r);
// 设置隐藏标题栏最小化按扭
void setHiddenMin(const bool &is);
// 设置隐藏标题栏最大化按扭
void setHiddenMax(const bool &is);
// 设置隐藏标题栏
void setHiddenTitleBar(const bool &is);
// 设置标题栏高度
void setTitleBarHeight(const uint &h);
// 设置标题栏最小化图标
void setMinIcon(const QIcon &icon);
// 设置标题栏最大化图标
void setMaxIcon(const QIcon &icon);
// 设置标题栏关闭图标
void setCloseIcon(const QIcon &icon);
// 设置标题栏最小化按钮鼠标悬浮时背景色
void setHoverColorMin(const QColor &color);
// 设置标题栏最大化按钮鼠标悬浮时背景色
void setHoverColorMax(const QColor &color);
// 设置标题栏关闭按钮鼠标悬浮时背景色
void setHoverColorClose(const QColor &color);
// 设置标题栏最小化按钮鼠标按下时背景色
void setPressedColorMin(const QColor &color);
// 设置标题栏最大化按钮鼠标按下时背景色
void setPressedColorMax(const QColor &color);
// 设置标题栏关闭按钮鼠标按下时背景色
void setPressedColorClose(const QColor &color);
// 向标题后面添加控件
void addWidgetToTitleBar(QWidget *w);
// 向标题后面添加控件
void addLayoutToTitleBar(QLayout *layout);
protected:
enum OpFlag
{
NONE = -1,
Top,
Bottom,
Left,
Right,
TL,
TR,
BL,
BR
};
void initialize();
void calculateOpflag(QPoint pos);
void updateRadius(const uint &r);
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void changeEvent(QEvent *event) override;
private:
QWidget *m_pCenter_widget = nullptr; // 用户所提供的中间窗口
QWidget *m_pBorder = nullptr; // 模拟边框的窗口
TitleBar *m_pTitleBar = nullptr; // 标题栏
QGridLayout *m_pGridLayout = nullptr;
int m_opFlag = OpFlag::NONE; // 窗口移动、拉伸控制
bool m_isOp = false; // 是否能移动、拉伸
QPointF m_lastPos; // 上一次的鼠标位置
QColor m_shadowColor = QColor(91, 91, 91, 90); // 边框阴影颜色
int m_blurRadius = 10; // 边框阴影范围
int m_radius = 10; // 边框圆角半径
QColor m_bgColor = QColor(0, 0, 0, 0);
};
#endif // FRAMEWGT_H
framewgt.cpp
#include "framewgt.h"
FrameWgt::FrameWgt(QWidget *centerWidget)
{
m_pCenter_widget = centerWidget;
initialize();
}
FrameWgt::~FrameWgt()
{
}
void FrameWgt::setTitleBarColor(const QColor &color)
{
m_pTitleBar->setBackgroundColor(color);
}
void FrameWgt::setTitleTextColor(const QColor &color)
{
m_pTitleBar->setTextColor(color);
}
void FrameWgt::setTitleText(const QString &text)
{
m_pTitleBar->setTitleText(text);
}
void FrameWgt::setTitleIcon(const QString &path)
{
m_pTitleBar->setTitleIcon(path);
}
void FrameWgt::setTitleIcon(const QPixmap &icon)
{
m_pTitleBar->setTitleIcon(icon);
}
void FrameWgt::setBackgroundColor(const QColor &color)
{
m_bgColor = color;
if(this->isMaximized() || this->isFullScreen())
{
updateRadius(0);
}
else
{
updateRadius(m_radius);
}
}
void FrameWgt::setRadius(const uint &r)
{
m_radius = r;
updateRadius(m_radius);
}
void FrameWgt::setShadowColor(const QColor &color)
{
m_shadowColor = color;
update();
}
void FrameWgt::setBlurRadius(const uint &r)
{
m_blurRadius = r;
if(this->isMaximized() || this->isFullScreen())
{
m_pGridLayout->setContentsMargins(0, 0, 0, 0);
return;
}
else
{
// 给出阴影绘制区域
m_pGridLayout->setContentsMargins(m_blurRadius, m_blurRadius, m_blurRadius, m_blurRadius);
}
}
void FrameWgt::setHiddenMin(const bool &is)
{
m_pTitleBar->setHiddenMin(is);
}
void FrameWgt::setHiddenMax(const bool &is)
{
m_pTitleBar->setHiddenMax(is);
}
void FrameWgt::setHiddenTitleBar(const bool &is)
{
m_pTitleBar->setHidden(is);
updateRadius(m_radius);
}
void FrameWgt::setTitleBarHeight(const uint &h)
{
m_pTitleBar->setHeight(h);
}
void FrameWgt::setMinIcon(const QIcon &icon)
{
m_pTitleBar->setMinIcon(icon);
}
void FrameWgt::setMaxIcon(const QIcon &icon)
{
m_pTitleBar->setMaxIcon(icon);
}
void FrameWgt::setCloseIcon(const QIcon &icon)
{
m_pTitleBar->setCloseIcon(icon);
}
void FrameWgt::setTitleTextFont(const QFont &font)
{
m_pTitleBar->setTitleTextFont(font);
}
void FrameWgt::addWidgetToTitleBar(QWidget *w)
{
m_pTitleBar->addWidget(w);
}
void FrameWgt::addLayoutToTitleBar(QLayout *layout)
{
m_pTitleBar->addLayout(layout);
}
void FrameWgt::initialize()
{
this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); // 隐藏默认边框
this->setAttribute(Qt::WA_TranslucentBackground, true); // 设置透明背景
setMouseTracking(true); // 启用鼠标追踪
this->resize(400, 300);
m_pBorder = new QWidget;
m_pBorder->setCursor(Qt::ArrowCursor);
m_pTitleBar = new TitleBar(m_pBorder);
QVBoxLayout *pCenterLayout = new QVBoxLayout;
pCenterLayout->setContentsMargins(0, 0,0 ,0);
pCenterLayout->setSpacing(0);
pCenterLayout->setAlignment(Qt::AlignTop);
pCenterLayout->addWidget(m_pTitleBar);
if(m_pCenter_widget){
this->setTitleText(m_pCenter_widget->windowTitle());
this->setTitleIcon(m_pCenter_widget->windowIcon().pixmap(64, 64));
pCenterLayout->addWidget(m_pCenter_widget);
pCenterLayout->setStretch(1, 1);
m_pBorder->setCursor(m_pCenter_widget->cursor());
}
m_pBorder->setLayout(pCenterLayout);
m_pGridLayout = new QGridLayout;
m_pGridLayout->setContentsMargins(m_blurRadius, m_blurRadius, m_blurRadius, m_blurRadius); // 给边框阴影预留位置
m_pGridLayout->addWidget(m_pBorder);
this->setLayout(m_pGridLayout);
setTitleBarColor(Qt::white);
setRadius(m_radius);
connect(m_pTitleBar, SIGNAL(closed()), this, SLOT(close()));
}
void FrameWgt::calculateOpflag(QPoint pos)
{
QCursor cursor = Qt::ArrowCursor;
m_opFlag = NONE;
if(pos.x() < m_blurRadius)
{
if(pos.y() < m_blurRadius + m_radius)
{
m_opFlag = OpFlag::TL;
cursor = Qt::SizeFDiagCursor;
}
else if(pos.y() > this->height() - m_blurRadius - m_radius)
{
m_opFlag = OpFlag::BL;
cursor = Qt::SizeBDiagCursor;
}
else
{
m_opFlag = OpFlag::Left;
cursor = Qt::SizeHorCursor;
}
}
else if(pos.x() > this->width() - m_blurRadius)
{
if(pos.y() < m_blurRadius + m_radius)
{
m_opFlag = OpFlag::TR;
cursor = Qt::SizeBDiagCursor;
}
else if(pos.y() > this->height() - m_blurRadius - m_radius)
{
m_opFlag = OpFlag::BR;
cursor = Qt::SizeFDiagCursor;
}
else
{
m_opFlag = OpFlag::Right;
cursor = Qt::SizeHorCursor;
}
}
else
{
if(pos.y() < m_blurRadius)
{
m_opFlag = OpFlag::Top;
cursor = Qt::SizeVerCursor;
}
else if(pos.y() > this->height() - m_blurRadius)
{
m_opFlag = OpFlag::Bottom;
cursor = Qt::SizeVerCursor;
}
else
{
m_opFlag = OpFlag::NONE;
cursor = Qt::ArrowCursor;
}
}
this->setCursor(cursor);
}
void FrameWgt::updateRadius(const uint &r)
{
m_pBorder->setObjectName("Border");
QString cr = QString::number(m_bgColor.red()); // 获取红色分量
QString cg = QString::number(m_bgColor.green()); // 获取绿色分量
QString cb = QString::number(m_bgColor.blue()); // 获取蓝色分量
QString ca = QString::number(m_bgColor.alpha()); // 获取透明度分量
m_pBorder->setStyleSheet(QString("QWidget#Border{border-radius: %1px;background-color: rgba(%2, %3, %4, %5);}").arg(QString::number(r), cr, cg, cb, ca));
m_pTitleBar->setRadius(r);
update();
}
void FrameWgt::mousePressEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
if(m_pBorder->geometry().contains(pos))
{
event->ignore();
return;
}
if(m_opFlag != -1)
{
m_isOp = true;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_lastPos = event->globalPos();
#else
m_lastPos = event->globalPosition();
#endif
}
}
void FrameWgt::mouseMoveEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
if(!m_isOp)
{
calculateOpflag(pos);
}
//获取鼠标拖动的位置,
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPointF currPos = event->globalPos();
#else
QPointF currPos = event->globalPosition();
#endif
// 计算鼠标按下并拖动的的位移
QPointF ptemp = currPos - m_lastPos ;
//保存当前鼠标拖动的位置,用于下一次计算拖动位移
m_lastPos = currPos;
event->ignore();
if(m_isOp)
{
if(this->isMaximized()) return;
int x = 0,y = 0,w = 0,h = 0;
// 根据拖动的那一条边框,确定拉伸还是缩小窗口。
switch (m_opFlag) {
// 左边框被拉伸
case Left:
x = this->pos().x() + ptemp.x();
y = this->pos().y();
w = this->size().width() - ptemp.x();
h = this->size().height();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x());
}
break;
// 右边框被拉伸
case Right:
x = this->pos().x();
y = this->pos().y();
w = this->size().width() + ptemp.x();
h = this->size().height();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x() + this->width());
}
break;
// 上边框被拉伸
case Top:
x = this->pos().x();
y = this->pos().y() + ptemp.y();
w = this->size().width() ;
h = this->size().height() - ptemp.y();
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y());
}
break;
// 下边框被拉伸
case Bottom:
x = this->pos().x();
y = this->pos().y();
w = this->size().width() ;
h = this->size().height() + ptemp.y();
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y() + this->height());
}
break;
//右上角被拉伸
case TR:
x = this->pos().x();
y = this->pos().y() + ptemp.y();
w = this->size().width() + ptemp.x() ;
h = this->size().height() - ptemp.y();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x() + this->width());
}
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y());
}
break;
//左上角被拉伸
case TL:
x = this->pos().x() + ptemp.x();
y = this->pos().y() + ptemp.y();
w = this->size().width() - ptemp.x() ;
h = this->size().height() - ptemp.y();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x());
}
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y());
}
break;
// 右下角被拉伸
case BR:
x = this->pos().x();
y = this->pos().y();
w = this->size().width() + ptemp.x() ;
h = this->size().height() + ptemp.y();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x() + this->width());
}
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y() + this->height());
}
break;
// 左下角被拉伸
case BL:
x = this->pos().x() + ptemp.x();
y = this->pos().y();
w = this->size().width() - ptemp.x() ;
h = this->size().height() + ptemp.y();
if(w < this->minimumWidth())
{
m_lastPos.setX(this->pos().x());
}
if(h < this->minimumHeight())
{
m_lastPos.setY(this->pos().y() + this->height());
}
break;
default:
return;
}
// 改变窗口的大小和位置。
if(w < this->minimumWidth())
{
x = this->pos().x();
w = this->size().width();
}
if(h < this->minimumHeight())
{
y = this->pos().y();
h = this->size().height();
}
this->setGeometry(x,y,w,h);
}
}
void FrameWgt::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
m_isOp = false;
}
void FrameWgt::paintEvent(QPaintEvent *event)
{
if(this->isMaximized() || this->isFullScreen())
{
m_pGridLayout->setContentsMargins(0, 0, 0, 0);
return;
}
else
{
// 给出阴影绘制区域
m_pGridLayout->setContentsMargins(m_blurRadius, m_blurRadius, m_blurRadius, m_blurRadius);
}
int radius = m_blurRadius + m_radius;
int width = this->width();
int height = this->height();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true); //抗锯齿
painter.setPen(Qt::NoPen);
QPainterPath rectPath;
rectPath.addRect(this->rect());
QRect borderRect(m_blurRadius, m_blurRadius, m_pBorder->width(), m_pBorder->height());
// 创建圆角矩形的路径
QPainterPath clipPath;
clipPath.addRoundedRect(borderRect, m_radius, m_radius);
// 限制绘制范围
painter.setClipPath(rectPath - clipPath);
//线性渐变
QLinearGradient linearGradient;
linearGradient.setColorAt(0, m_shadowColor);
linearGradient.setColorAt(m_radius*1.0/radius, m_shadowColor);
QColor color = m_shadowColor;
color.setAlpha(0);
linearGradient.setColorAt(1, color);
//圆形渐变
QRadialGradient radialGradient;
radialGradient.setColorAt(0, m_shadowColor);
radialGradient.setColorAt(m_radius*1.0/radius, m_shadowColor);
radialGradient.setColorAt(1, color);
//左上角
radialGradient.setCenter(radius, radius); //中心点
radialGradient.setRadius(radius); //半径
radialGradient.setFocalPoint(radius, radius); //焦点
painter.setBrush(radialGradient);
QRectF rectf(0, 0, radius*2, radius*2);
QPainterPath path;
path.moveTo(radius, radius);//移动圆心
path.arcTo(rectf, 90, 90);
painter.drawPath(path); //画路径(扇形)
//左边
linearGradient.setStart(radius, height/2);
linearGradient.setFinalStop(0, height/2);
painter.setBrush(linearGradient);
path.clear();
path.addRect(0, radius, radius, height - radius*2);
painter.drawPath(path);
//左下角
radialGradient.setCenter(radius, height - radius); //中心点
radialGradient.setRadius(radius); //半径
radialGradient.setFocalPoint(radius, height - radius); //焦点
painter.setBrush(radialGradient);
path.clear();
path.moveTo(radius, height - radius);//移动圆心
rectf.setRect(0, height - radius*2, radius*2, radius*2);
path.arcTo(rectf, 180, 90);
painter.drawPath(path); //画路径(扇形)
//下边
linearGradient.setStart(width/2, height - radius);
linearGradient.setFinalStop(width/2, height);
painter.setBrush(linearGradient);
path.clear();
path.addRect(radius, height - radius, width - radius*2, radius);
painter.drawPath(path);
//右下角
radialGradient.setCenter(width - radius, height - radius); //中心点
radialGradient.setRadius(radius); //半径
radialGradient.setFocalPoint(width - radius, height - radius); //焦点
painter.setBrush(radialGradient);
path.clear();
path.moveTo(width - radius, height - radius);//移动圆心
rectf.setRect(width - radius*2, height - radius*2, radius*2, radius*2);
path.arcTo(rectf, 270, 90);
painter.drawPath(path); //画路径(扇形)
//右边
linearGradient.setStart(width - radius, height/2);
linearGradient.setFinalStop(width, height/2);
painter.setBrush(linearGradient);
path.clear();
path.addRect(width - radius, radius, radius, height - radius*2);
painter.drawPath(path);
//右上角
radialGradient.setCenter(width - radius, radius); //中心点
radialGradient.setRadius(radius); //半径
radialGradient.setFocalPoint(width - radius, radius); //焦点
painter.setBrush(radialGradient);
path.clear();
path.moveTo(width - radius, radius);//移动圆心
rectf.setRect(width - radius*2, 0, radius*2, radius*2);
path.arcTo(rectf, 0, 90);
painter.drawPath(path); //画路径(扇形)
//上边
linearGradient.setStart(height/2, radius);
linearGradient.setFinalStop(height/2, 0);
painter.setBrush(linearGradient);
path.clear();
path.addRect(radius, 0, width - radius*2, radius);
painter.drawPath(path);
}
void FrameWgt::changeEvent(QEvent *event)
{
if (event->type() == QEvent::WindowStateChange) {
QWindowStateChangeEvent *stateChangeEvent = static_cast<QWindowStateChangeEvent *>(event);
Qt::WindowStates oldState = stateChangeEvent->oldState();
Qt::WindowStates newState = windowState();
if (newState == Qt::WindowMaximized || newState == Qt::WindowFullScreen) {
// 窗口被最大化
updateRadius(0);
} else if (newState == Qt::WindowMinimized) {
// 窗口被最小化
updateRadius(m_radius);
} else if(oldState == Qt::WindowMaximized || oldState == Qt::WindowMinimized || oldState == Qt::WindowFullScreen)
{
// 窗口被还原
updateRadius(m_radius);
}
}
QWidget::changeEvent(event);
}
titlebar.h
此为标题栏(看上面那个文件的接口注释就行)
#ifndef TITLEBAR_H
#define TITLEBAR_H
#include <QWidget>
#include <QPushButton>
#include <QLabel>
#include <QMouseEvent>
#include <QHBoxLayout>
#include <QStyle>
class TitleBar : public QWidget
{
Q_OBJECT
public:
explicit TitleBar(QWidget *parent = nullptr);
~TitleBar();
void setTitleText(const QString &text);
void setTitleIcon(const QString &path);
void setTitleIcon(const QPixmap &icon);
void setBackgroundColor(const QColor &color);
void setTextColor(const QColor &color);
void setHeight(const uint &h);
void setMinIcon(const QIcon &icon);
void setMaxIcon(const QIcon &icon);
void setCloseIcon(const QIcon &icon);
void setTitleTextFont(const QFont &font);
void setHiddenMin(const bool &is);
void setHiddenMax(const bool &is);
void addWidget(QWidget *w);
void addLayout(QLayout *layout);
void setHoverColorMin(const QColor &color);
void setHoverColorMax(const QColor &color);
void setHoverColorClose(const QColor &color);
void setPressedColorMin(const QColor &color);
void setPressedColorMax(const QColor &color);
void setPressedColorClose(const QColor &color);
void showFull(const bool &isFull);
void setMoveEnable(const bool &moveEnable);
void setRadius(const uint &radius);
public slots:
void onMax();
void onMin();
signals:
void closed();
void movePos(QPointF movePoint);
void maxChange(bool is);
protected:
void initialize();
void updateStyle();
void moveTopParent(QWidget *pWgt, QPoint movePoint);
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
private:
QHBoxLayout *m_pMainLayout = nullptr;
QHBoxLayout *m_pCustomLayout = nullptr;
QPushButton *m_pBtnClose = nullptr;
QPushButton *m_pBtnMax = nullptr;
QPushButton *m_pBtnMin = nullptr;
QLabel *m_pLabIcon = nullptr;
QLabel *m_pLabTitle = nullptr;
bool m_isPressed = false;
bool m_moveEnable = true;
QPointF m_alof_win_mousePos = QPoint(0,0);
uint m_height = 30;
QColor m_bgColor = Qt::white;
QColor m_textColor = Qt::black;
uint m_radius = 10;
QColor m_minHoverColor = QColor(240, 240, 240);
QColor m_maxHoverColor = QColor(240, 240, 240);
QColor m_closeHoverColor = QColor(255, 123, 123);
QColor m_minPressedColor = QColor(220, 220, 220);
QColor m_maxPressedColor = QColor(220, 220, 220);
QColor m_closePressedColor = QColor(255, 103, 103);
};
#endif // TITLEBAR_H
titlebar.cpp
#include "titlebar.h"
TitleBar::TitleBar(QWidget *parent) : QWidget(parent)
{
initialize();
}
TitleBar::~TitleBar()
{
}
void TitleBar::setTitleText(const QString &text)
{
m_pLabTitle->setText(text);
this->window()->setWindowTitle(text);
}
void TitleBar::setTitleIcon(const QString &path)
{
QPixmap pix(path);
this->setTitleIcon(pix);
}
void TitleBar::setTitleIcon(const QPixmap &icon)
{
if(icon.isNull()){
return;
}
m_pLabIcon->setHidden(false);
QPixmap pix = icon.scaledToHeight(m_height - 10, Qt::SmoothTransformation);
m_pLabIcon->setPixmap(pix);
this->window()->setWindowIcon(pix);
}
void TitleBar::setBackgroundColor(const QColor &color)
{
m_bgColor = color;
updateStyle();
}
void TitleBar::setTextColor(const QColor &color)
{
m_textColor = color;
updateStyle();
}
void TitleBar::setHeight(const uint &h)
{
m_height = h;
updateStyle();
}
void TitleBar::setMinIcon(const QIcon &icon)
{
m_pBtnMin->setIcon(icon);
}
void TitleBar::setMaxIcon(const QIcon &icon)
{
m_pBtnMax->setIcon(icon);
}
void TitleBar::setCloseIcon(const QIcon &icon)
{
m_pBtnClose->setIcon(icon);
}
void TitleBar::setTitleTextFont(const QFont &font)
{
m_pLabTitle->setFont(font);
}
void TitleBar::setHiddenMin(const bool &is)
{
m_pBtnMin->setHidden(is);
}
void TitleBar::setHiddenMax(const bool &is)
{
m_pBtnMax->setHidden(is);
}
void TitleBar::addWidget(QWidget *w)
{
m_pCustomLayout->addWidget(w);
}
void TitleBar::addLayout(QLayout *layout)
{
m_pCustomLayout->addLayout(layout);
}
void TitleBar::setHoverColorMin(const QColor &color)
{
m_minHoverColor = color;
updateStyle();
}
void TitleBar::setHoverColorMax(const QColor &color)
{
m_maxHoverColor = color;
updateStyle();
}
void TitleBar::setHoverColorClose(const QColor &color)
{
m_closeHoverColor = color;
updateStyle();
}
void TitleBar::setPressedColorMin(const QColor &color)
{
m_minPressedColor = color;
updateStyle();
}
void TitleBar::setPressedColorMax(const QColor &color)
{
m_maxPressedColor = color;
updateStyle();
}
void TitleBar::setPressedColorClose(const QColor &color)
{
m_closePressedColor = color;
updateStyle();
}
void TitleBar::showFull(const bool &isFull)
{
QWidget *p = window();
if(isFull){
p->showFullScreen();
}else{
p->showMaximized();
}
}
void TitleBar::setMoveEnable(const bool &moveEnable)
{
m_moveEnable = moveEnable;
}
void TitleBar::setRadius(const uint &radius)
{
m_radius = radius;
updateStyle();
}
void TitleBar::onMax()
{
QWidget *p = this->window();
if(p->isMaximized()){
p->showNormal();
emit maxChange(false);
}else{
p->showMaximized();
emit maxChange(true);
}
}
void TitleBar::onMin()
{
this->window()->showMinimized();
}
void TitleBar::initialize()
{
this->setFocusPolicy(Qt::NoFocus);
this->setFixedHeight(m_height);
m_pBtnClose = new QPushButton(this);
m_pBtnMax = new QPushButton(this);
m_pBtnMin = new QPushButton(this);
m_pLabIcon = new QLabel(this);
m_pLabTitle = new QLabel(this);
m_pBtnClose->setFixedSize(m_height * 2, m_height);
m_pBtnMin->setFixedSize(m_height * 2, m_height);
m_pBtnMax->setFixedSize(m_height * 2, m_height);
m_pLabTitle->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
m_pLabTitle->setContentsMargins(5, 0, 0, 0);
m_pLabIcon->setScaledContents(true);
m_pLabIcon->setHidden(true);
m_pLabIcon->setFixedHeight(m_height - 10);
m_pBtnClose->setIcon(QIcon(":/res/close.png"));
m_pBtnMin->setIcon(QIcon(":/res/min.png"));
m_pBtnMax->setIcon(QIcon(":/res/max.png"));
this->setAttribute(Qt::WA_StyledBackground);
m_pMainLayout = new QHBoxLayout;
m_pCustomLayout = new QHBoxLayout;
m_pMainLayout->addWidget(m_pLabIcon);
m_pMainLayout->addWidget(m_pLabTitle);
m_pMainLayout->addLayout(m_pCustomLayout);
m_pMainLayout->addStretch();
m_pMainLayout->addWidget(m_pBtnMin);
m_pMainLayout->addWidget(m_pBtnMax);
m_pMainLayout->addWidget(m_pBtnClose);
m_pMainLayout->setContentsMargins(10, 0, 0, 0);
m_pMainLayout->setSpacing(2);
m_pCustomLayout->setContentsMargins(0, 0, 0, 0);
m_pCustomLayout->setSpacing(0);
this->setLayout(m_pMainLayout);
m_pBtnClose->setFocusPolicy(Qt::NoFocus);
m_pBtnMin->setFocusPolicy(Qt::NoFocus);
m_pBtnMax->setFocusPolicy(Qt::NoFocus);
connect(m_pBtnMin,SIGNAL(clicked(bool)),this,SLOT(onMin()));
connect(m_pBtnMax,SIGNAL(clicked(bool)),this,SLOT(onMax()));
connect(m_pBtnClose,SIGNAL(clicked(bool)),this,SIGNAL(closed()));
}
void TitleBar::updateStyle()
{
QString styleMin = "QPushButton{border: 0px;}QPushButton:hover{background-color: hoverColor;border-radius: 0px;}QPushButton:pressed{background-color: pressedColor;border-radius: 0px;}";
QString styleMax = "QPushButton{border: 0px;}QPushButton:hover{background-color: hoverColor;border-radius: 0px;}QPushButton:pressed{background-color: pressedColor;border-radius: 0px;}";
QString styleClose = "QPushButton{border: 0px;}QPushButton:hover{background-color: hoverColor;borderRadius}QPushButton:pressed{background-color: pressedColor;borderRadius}";
this->setObjectName("titleBar");
QString cr = QString::number(m_bgColor.red()); // 获取红色分量
QString cg = QString::number(m_bgColor.green()); // 获取绿色分量
QString cb = QString::number(m_bgColor.blue()); // 获取蓝色分量
QString ca = QString::number(m_bgColor.alpha()); // 获取透明度分量
this->setStyleSheet(QString("QWidget#titleBar{border-top-left-radius: %1px;"
"border-top-right-radius: %1px;"
"border-bottom-left-radius: 0px;"
"border-bottom-right-radius: 0px;"
"background-color: rgba(%2, %3, %4, %5);}").arg(QString::number(m_radius), cr, cg, cb, ca));
m_pLabTitle->setStyleSheet(QString("color: %1;").arg(m_textColor.name()));
QString borderRadius = QString("border-top-left-radius: 0px;border-top-right-radius: %1px;").arg(QString::number(m_radius));
m_pBtnClose->setStyleSheet(styleClose.replace("hoverColor", m_closeHoverColor.name()).replace("pressedColor", m_closePressedColor.name()).replace("borderRadius", borderRadius));
m_pBtnMax->setStyleSheet(styleMax.replace("hoverColor", m_maxHoverColor.name()).replace("pressedColor", m_maxPressedColor.name()));
m_pBtnMin->setStyleSheet(styleMin.replace("hoverColor", m_minHoverColor.name()).replace("pressedColor", m_minPressedColor.name()));
m_pLabIcon->setStyleSheet(QString("border-top-left-radius: %1px;").arg(QString::number(m_radius)));
m_pLabIcon->setAttribute(Qt::WA_TranslucentBackground, true);
m_pLabTitle->setAttribute(Qt::WA_TranslucentBackground, true);
this->setFixedHeight(m_height);
m_pBtnClose->setFixedSize(m_height * 2, m_height);
m_pBtnMin->setFixedSize(m_height * 2, m_height);
m_pBtnMax->setFixedSize(m_height * 2, m_height);
m_pLabIcon->setFixedHeight(m_height - 10);
}
void TitleBar::moveTopParent(QWidget *pWgt,QPoint movePoint)
{
if(nullptr == pWgt){
return;
}
if(pWgt->parentWidget()){
moveTopParent(pWgt->parentWidget(),movePoint);
return;
}
QPoint widgetPos = pWgt->pos();
pWgt->move(widgetPos.x() + movePoint.x(), widgetPos.y() + movePoint.y());
}
void TitleBar::mousePressEvent(QMouseEvent *event)
{
m_isPressed = true;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_alof_win_mousePos = event->globalPos();
#else
m_alof_win_mousePos = event->globalPosition();
#endif
QWidget::mousePressEvent(event);
}
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
if(!m_moveEnable){
return;
}
if (m_isPressed && !this->window()->isMaximized() && !this->window()->isFullScreen())
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPointF movePoint = event->globalPos() - m_alof_win_mousePos;
m_alof_win_mousePos = event->globalPos();
#else
QPointF movePoint = event->globalPosition() - m_alof_win_mousePos;
m_alof_win_mousePos = event->globalPosition();
#endif
this->window()->move(this->window()->pos() + movePoint.toPoint());
emit movePos(movePoint);
}
QWidget::mouseMoveEvent(event);
}
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
{
m_isPressed = false;
QWidget::mouseReleaseEvent(event);
}
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
if(!m_pBtnMax->isVisible() || event->button() != Qt::MouseButton::LeftButton){
return;
}
onMax();
QWidget::mouseDoubleClickEvent(event);
}
结语
代码中已经敲了大致注释, 欢迎提问和反馈。
国际站点:https://github.com/yibobunengyuntian
QQ:2947467985