欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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
}
  • 效果
    Qt自定义标题栏
  • 资源文件
    png格式
    Qt自定义标题栏
    Qt自定义标题栏
    Qt自定义标题栏
    Qt自定义标题栏
    Qt自定义标题栏
    稍加整理方便大家参考,如有错误请指正,谢谢!