Qt自定义标题栏
程序员文章站
2024-02-05 11:39:34
...
- 概述
以QWidget作为基类,派生出自定义标题栏类DlgTitle,DlgTitle类可用于QMainWindow和QDialog窗口。同时使用QSS进行资源加载和简单界面美化。 - 开发环境
Qt5.4.2 + VS2013 + QT VS TOOLS - 代码
自定义标题栏类DlgTitle.h如下:
#ifndef DLGTITLE_H
#define DLGTITLE_H
#include <QtWidgets>
enum ButtonType
{
MINI_BUTTON, //最小化按钮和关闭按钮
MINI_MAX_BUTTON, //最小化、最大化、还原和关闭按钮
ONLY_CLOSE_BUTTON //关闭按钮
};
class DlgTitle : public QWidget
{
Q_OBJECT
public:
explicit DlgTitle(QWidget* parent = 0);
~DlgTitle();
void init(); //初始化
void setButtonType(ButtonType buttontype); //设置按钮类型
void setDlgIcon(const QString& fileName); //设置标题栏Icon
void setDlgTitle(const QString& title); //设置标题栏标题
private:
void setButtonStyle(); //设置按钮样式
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
private slots:
void miniButtonClicked();
void restoreButtonClicked();
void maxButtonClicked();
void closeButtonClicked();
private:
QLabel *m_pIconLabel; //表示标题栏Icon
QLabel *m_pTitleLabel; //表示标题栏标题
QPushButton *m_pMiniButton; //表示最小化按钮
QPushButton *m_pMaxButton; //表示最大化按钮
QPushButton *m_pRestoreButton; //表示还原按钮
QPushButton *m_pCloseButton; //表示关闭按钮
bool m_isPressed; //鼠标按下flag
QPoint m_startMovePos; //鼠标移动的初始位置
ButtonType m_buttonType; //按钮类型
};
#endif //DLGTITLE_H
自定义标题栏类DlgTitle.cpp如下:
#include "DlgTitle.h"
#define BUTTON_WIDTH 42 //按钮宽度
#define BUTTON_HEIGHT 32 //按钮高度
#define TITLE_HEIGHT 40 //标题栏高度
DlgTitle::DlgTitle(QWidget* parent)
: QWidget(parent)
, m_isPressed(false)
{
init();
}
DlgTitle::~DlgTitle()
{
}
void DlgTitle::init()
{
m_pIconLabel = new QLabel;
m_pTitleLabel = new QLabel;
m_pTitleLabel->setContentsMargins(5, 0, 0, 0);
m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); //标题宽度可扩展
m_pMiniButton = new QPushButton;
m_pMaxButton = new QPushButton;
m_pRestoreButton = new QPushButton;
m_pCloseButton = new QPushButton;
//按钮大小固定
m_pMiniButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
m_pMaxButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
m_pRestoreButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
m_pCloseButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
setButtonStyle();
//对Icon、标题和按钮使用水平布局
QHBoxLayout *pHLayout = new QHBoxLayout;
pHLayout->addWidget(m_pIconLabel);
pHLayout->addWidget(m_pTitleLabel);
pHLayout->addWidget(m_pMiniButton);
pHLayout->addWidget(m_pMaxButton);
pHLayout->addWidget(m_pRestoreButton);
pHLayout->addWidget(m_pCloseButton);
pHLayout->setContentsMargins(5, 1, 1, 6); //TITLE_HEIGHT-BUTTON_HEIGHT-1为6
pHLayout->setSpacing(0);
this->setLayout(pHLayout);
this->setFixedHeight(TITLE_HEIGHT); //标题栏高度固定
//按钮的信号槽连接
connect(m_pMiniButton, SIGNAL(clicked()), this, SLOT(miniButtonClicked()));
connect(m_pMaxButton, SIGNAL(clicked()), this, SLOT(maxButtonClicked()));
connect(m_pRestoreButton, SIGNAL(clicked()), this, SLOT(restoreButtonClicked()));
connect(m_pCloseButton, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
}
void DlgTitle::setButtonType(ButtonType buttontype)
{
m_buttonType = buttontype;
switch (buttontype)
{
case MINI_BUTTON:
m_pMaxButton->setVisible(false);
m_pRestoreButton->setVisible(false);
break;
case MINI_MAX_BUTTON:
m_pRestoreButton->setVisible(false);
break;
case ONLY_CLOSE_BUTTON:
m_pMiniButton->setVisible(false);
m_pMaxButton->setVisible(false);
m_pRestoreButton->setVisible(false);
break;
default:
break;
}
}
//使用QSS设置按钮样式,鼠标样式仿照VS2013的最小化、最大化、还原和关闭按钮
void DlgTitle::setButtonStyle()
{
m_pMiniButton->setStyleSheet("QPushButton{border: transparent; border-radius: none; background-color:none;}"
"QPushButton{border-image:url(./Resources/Minimize.png) 0 84 0 0;}"
"QPushButton:hover{border-image:url(./Resources/Minimize.png) 0 42 0 42;}"
"QPushButton:pressed{border-image:url(./Resources/Minimize.png) 0 0 0 84;}");
m_pMaxButton->setStyleSheet("QPushButton{border: transparent; border-radius: none; background-color:none;}"
"QPushButton{border-image:url(./Resources/Maximize.png) 0 84 0 0;}"
"QPushButton:hover{border-image:url(./Resources/Maximize.png) 0 42 0 42;}"
"QPushButton:pressed{border-image:url(./Resources/Maximize.png) 0 0 0 84;}");
m_pRestoreButton->setStyleSheet("QPushButton{border: transparent; border-radius: none; background-color:none;}"
"QPushButton{border-image:url(./Resources/Restore.png) 0 84 0 0;}"
"QPushButton:hover{border-image:url(./Resources/Restore.png) 0 42 0 42;}"
"QPushButton:pressed{border-image:url(./Resources/Restore.png) 0 0 0 84;}");
m_pCloseButton->setStyleSheet("QPushButton{border: transparent; border-radius: none; background-color:none;}"
"QPushButton{border-image:url(./Resources/Close.png) 0 84 0 0;}"
"QPushButton:hover{border-image:url(./Resources/Close.png) 0 42 0 42;}"
"QPushButton:pressed{border-image:url(./Resources/Close.png) 0 0 0 84;}");
}
void DlgTitle::setDlgIcon(const QString& fileName)
{
QPixmap pixmap(fileName);
m_pIconLabel->setPixmap(pixmap.scaled(24, 24));
}
void DlgTitle::setDlgTitle(const QString& title)
{
m_pTitleLabel->setText(title);
m_pTitleLabel->setStyleSheet("QLabel{color: black; background-color: none; font-size: 10pt; font-family: Microsoft YaHei;}");
}
void DlgTitle::mousePressEvent(QMouseEvent *event)
{
if (MINI_MAX_BUTTON == m_buttonType)
{
if (m_pMaxButton->isVisible()) //窗口处于非最大化状态时
{
m_isPressed = true;
m_startMovePos = event->globalPos();
}
}
else
{
m_isPressed = true;
m_startMovePos = event->globalPos();
}
return QWidget::mousePressEvent(event);
}
void DlgTitle::mouseReleaseEvent(QMouseEvent *event)
{
m_isPressed = false;
return QWidget::mouseReleaseEvent(event);
}
void DlgTitle::mouseDoubleClickEvent(QMouseEvent *event)
{
if (MINI_MAX_BUTTON == m_buttonType)
{
if (m_pMaxButton->isVisible())
{
maxButtonClicked();
}
else
{
restoreButtonClicked();
}
}
return QWidget::mouseDoubleClickEvent(event);
}
void DlgTitle::mouseMoveEvent(QMouseEvent *event)
{
if (m_isPressed)
{
QPoint moveOffset = event->globalPos() - m_startMovePos;
QPoint widgetPos = this->parentWidget()->pos();
m_startMovePos = event->globalPos();
this->parentWidget()->move(widgetPos.x() + moveOffset.x(), widgetPos.y() + moveOffset.y());
}
}
void DlgTitle::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPainterPath pathBack;
pathBack.setFillRule(Qt::WindingFill);
pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()), 0, 0);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillPath(pathBack, QBrush(QColor(255, 255, 255, 0)));
if (this->width() != this->parentWidget()->width())
{
this->setFixedWidth(this->parentWidget()->width());
}
update();
return QWidget::paintEvent(event);
}
void DlgTitle::miniButtonClicked()
{
window()->showMinimized();
}
void DlgTitle::restoreButtonClicked()
{
window()->showNormal();
m_pRestoreButton->setVisible(false);
m_pMaxButton->setVisible(true);
}
void DlgTitle::maxButtonClicked()
{
window()->showMaximized();
m_pMaxButton->setVisible(false);
m_pRestoreButton->setVisible(true);
}
void DlgTitle::closeButtonClicked()
{
window()->close();
}
主窗口使用自定义标题栏类DlgTitle如下:
#include "CustomTitle.h"
#include "DlgTitle.h"
CustomTitle::CustomTitle(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
init();
}
void CustomTitle::init()
{
setWindowIcon(QIcon("./Resources/logo.png"));
setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint);
//实际使用时,需要在.ui文件中给DlgTitle留出TITLE_HEIGHT高度的位置
DlgTitle *pTitle = new DlgTitle(this);
pTitle->setDlgIcon("./Resources/logo.png");
pTitle->setButtonType(MINI_MAX_BUTTON);
pTitle->setDlgTitle("MainWindow");
//仿照VS2013,在QSS中使用border-image就可以设置主窗口背景及边界图像
setStyleSheet("QMainWindow{border: 40 2 2px; border-image: url(./Resources/DlgBkgnd.png);}");
//需要注意的是DlgBkgnd.png属于标题栏位置的图像高度为TITLE_HEIGHT
}
- 效果
- 资源文件
png格式
稍加整理方便大家参考,如有错误请指正,谢谢!