Qt系列:自定义标题栏

QSS系列:语法规则

  • 概述
    以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系列:自定义标题栏_第1张图片
  • 资源文件
    png格式
    Qt系列:自定义标题栏_第2张图片
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    稍加整理方便大家参考,如有错误请指正,谢谢!

你可能感兴趣的:(Qt,Qt,自定义标题栏)