QT快速开发自定义标题栏

前言

大家在用QT进行客户端开发的时候,难免都会觉得原生的QT窗口标题栏很丑,希望能自绘漂亮的标题栏,实现方法其实也比较简单,网上资料也挺多,方法基本都差不多,不过我觉得不够简洁,对此我特地封装总结了一个最高效快捷的方法,3分钟实现一个自绘制标题栏,包含:左上角图标、标题、按钮、双击标题栏、最大化时候拖拽缩小、菜单栏等功能。

效果

方法

1、目标窗口添加标题栏、最大化最小化关闭按钮(该步最好每次使用时,从模板程序中直接复制)

2、窗口基类从QDialog改为QFramelessDialog,如果是QWidget的话,请参考QFramelessDialog自行编写QFramelessWidget即可,非常简单,只需要将QDialog改成QWidget即可,至于为什么我写程序更喜欢用QDialog而不是QWidget,主要原因是QDialog默认自带外边框,设置外边框更简单,而QWidget设置外边框比较麻烦,必须在ui中将边框宽度pad预留出来。

3、窗口构造函数中,调用无边框窗体初始化函数,头文件中已经写好几个宏函数直接调用即可,使用宏的情况下,必须保证标题栏、按钮对象名称一致,注意调用初始化函数一定要在ui.setupUi(this);后面。

核心初始化函数

	void Init(QWidget *widget_title, 		//标题栏对象
			  QPushButton *menuButton_Close,//关闭按钮 
			  QPushButton *menuButton_Max,	//最大化按钮
			  QPushButton *menuButton_Min,	//最小化按钮
			  bool bResize,					//窗体支持resize
			  bool bMinHide,				//点击close按钮时隐藏窗口,通常用在主窗口中
			  bool bConnectClose);			//当bMinHide为true时,是否自动处理隐藏

宏解释:

FRAMELESS_DIALOG_INIT    模态对话框(只有关闭按钮)

FRAMELESS_MAIN_DIALOG_INIT   常用主窗口(包含最大化 、最小化、关闭按钮、可resize)

关于Demo中qss样式、编辑可参考作者早期博文《QT-智能QSS设计器》

https://blog.csdn.net/redchairman/article/details/82012984

代码

#ifndef QFRAMELESSDIALOG_H
#define QFRAMELESSDIALOG_H

#include <QDialog>

class QFramelessDialog : public QDialog
{
	Q_OBJECT

public:
	QFramelessDialog(QWidget *parent);
	~QFramelessDialog();

	void Init(QWidget *widget_title, 
			  QPushButton *menuButton_Close, 
			  QPushButton *menuButton_Max,
			  QPushButton *menuButton_Min,
			  bool bResize,
			  bool bMinClose,
			  bool bConnectClose);

	void setResizeable(bool resizeable);
	virtual void CloseDialog();
private:
	bool m_bMaximized;
	bool m_bMoveable;
	QPoint dragPosition;
	QRect m_rcNormal;

protected:
	void mouseMoveEvent(QMouseEvent *e);
	void mousePressEvent(QMouseEvent *e);
	void mouseReleaseEvent(QMouseEvent *);
	void mouseDoubleClickEvent(QMouseEvent *event);

	bool nativeEvent(const QByteArray & eventType, void * message, long * result);

	void paintEvent(QPaintEvent *event);

	void keyPressEvent(QKeyEvent* e);

public slots:
/*	void sltCloseClick();*/
	void sltClickMin();
	void sltClickMaxRestore();
	void sltCloseDialog();

public:
	bool m_bResize;
	QPushButton *m_menuButton_Close;
	QPushButton *m_menuButton_Max;
	QPushButton *m_menuButton_Min;
	QWidget *m_widget_title;
	bool m_bMinClose;
	bool m_bConnectClose;
};

#define FRAMELESS_DIALOG_INIT() Init(ui.widget_title, ui.menuButton_Close, nullptr, nullptr, false, false, true)
#define FRAMELESS_MAIN_DIALOG_INIT() Init(ui.widget_title, ui.menuButton_Close, ui.menuButton_Max, ui.menuButton_Min, true, true, true)
#define FRAMELESS_MAIN_DIALOG_NOCLOSE_INIT() Init(ui.widget_title, ui.menuButton_Close, ui.menuButton_Max, ui.menuButton_Min, true, true, false)

#define FRAMELESS_DIALOG_INIT2() Init(ui->widget_title, ui->menuButton_Close, nullptr, nullptr, false, false, true)
#define FRAMELESS_MAIN_DIALOG_INIT2() Init(ui->widget_title, ui->menuButton_Close, ui->menuButton_Max, ui->menuButton_Min, true, true, true)
#define FRAMELESS_MAIN_DIALOG_NOCLOSE_INIT2() Init(ui->widget_title, ui->menuButton_Close, ui->menuButton_Max, ui->menuButton_Min, true, true, false)




#endif // QFRAMELESSDIALOG_H

 

#include "stdafx.h"
#include "QFramelessDialog.h"
#include "QIconHelper.hpp"

QFramelessDialog::QFramelessDialog(QWidget *parent)
	: QDialog(parent)
	, m_bMaximized(false)
	, m_bMoveable(false)
	, m_bResize(false)
	, m_menuButton_Close(nullptr)
	, m_menuButton_Max(nullptr)
	, m_menuButton_Min(nullptr)
	, m_widget_title(nullptr)
	, m_bMinClose(false)
{
/*	setAttribute(Qt::WA_TranslucentBackground);*/
	setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog | Qt::WindowMinMaxButtonsHint);
	setWindowModality(Qt::WindowModal);
	setFocusPolicy(Qt::ClickFocus);
}

QFramelessDialog::~QFramelessDialog()
{

}

void QFramelessDialog::Init(QWidget *widget_title, 
							QPushButton *menuButton_Close, 
							QPushButton *menuButton_Max,
							QPushButton *menuButton_Min,
							bool bResize,
							bool bMinClose,
							bool bConnectClose)
{
	m_bResize = bResize;
	m_bMinClose = bMinClose;
	m_bConnectClose = bConnectClose;
	m_menuButton_Min = menuButton_Min;
	m_menuButton_Max = menuButton_Max;
	m_menuButton_Close = menuButton_Close;
	m_widget_title = widget_title;
	
	if (m_menuButton_Close)
	{
		m_menuButton_Close->setFocusPolicy(Qt::ClickFocus);
		QIconHelper::SetIcon(m_menuButton_Close, QChar(0xf00d), 12);
		if (m_bMinClose)
		{
			if (m_bConnectClose)
			{
				connect(m_menuButton_Close, SIGNAL(clicked()), this, SLOT(hide()));
			}
		}
		else
		{
			connect(m_menuButton_Close, SIGNAL(clicked()), this, SLOT(sltCloseDialog()));
		}
	}
	if (m_menuButton_Max)
	{
		m_menuButton_Max->setFocusPolicy(Qt::ClickFocus);
		QIconHelper::SetIcon(m_menuButton_Max, QChar(0xf096), 12);
		connect(m_menuButton_Max, SIGNAL(clicked()), this, SLOT(sltClickMaxRestore()));
	}
	if (m_menuButton_Min)
	{
		m_menuButton_Min->setFocusPolicy(Qt::ClickFocus);
		QIconHelper::SetIcon(m_menuButton_Min, QChar(0xf068), 12);
		connect(m_menuButton_Min, SIGNAL(clicked()), this, SLOT(sltClickMin()));
	}

	return;
}

void QFramelessDialog::CloseDialog()
{
	close();
}

void QFramelessDialog::sltCloseDialog()
{
	CloseDialog();
}

void QFramelessDialog::mousePressEvent(QMouseEvent *event)
{
	if (isFullScreen())
	{
		return;
	}

    if (event->button() == Qt::LeftButton && m_widget_title)
	{
		dragPosition = event->globalPos() - frameGeometry().topLeft();

		QRect rect = m_widget_title->rect();
		if (rect.contains(event->pos()))
		{
			m_bMoveable = true;
		}
	}
	event->accept();
}

void QFramelessDialog::mouseMoveEvent(QMouseEvent *event)
{
	if (isFullScreen())
	{
		return;
	}

	if (event->buttons() & Qt::LeftButton && m_bMoveable)
	{
		if (isMaximized())
		{
			int nWidth = m_rcNormal.width();
			int nHeight = m_rcNormal.height();

			float fx = (float)event->pos().x() / (float)rect().width();
			//屏幕大小
			int old_x = m_rcNormal.width() * fx + m_rcNormal.left();
			int old_y = m_rcNormal.top() + event->pos().y();

			QPoint pt_new(m_rcNormal.left() + event->globalPos().x() - old_x, m_rcNormal.top() + event->globalPos().y() - old_y);
			m_rcNormal.moveTopLeft(pt_new);
			sltClickMaxRestore();
			//m_rcNormal
			dragPosition = event->globalPos() - frameGeometry().topLeft();
		}
		else
		{
			move(event->globalPos() - dragPosition);
		}
	}
	event->accept();

}

void QFramelessDialog::mouseReleaseEvent(QMouseEvent *event)
{
	if (isFullScreen())
	{
		return;
	}
	if (m_bMoveable)
	{
		m_bMoveable = false;
	}
	event->accept();
}

void QFramelessDialog::mouseDoubleClickEvent(QMouseEvent *event)
{
	if (m_bResize == false)
	{
		return;
	}
	if (m_menuButton_Max == nullptr || m_menuButton_Min == nullptr)
	{
		return;
	}
	if (isFullScreen())
	{
		return;
	}
    if (event->buttons() & Qt::LeftButton && m_widget_title)
	{
		QRect rect = m_widget_title->rect();
		if (rect.contains(event->pos()))
		{
			sltClickMaxRestore();
		}
	}
	event->accept();
}

void QFramelessDialog::sltClickMin()
{
	showMinimized();
}

void QFramelessDialog::sltClickMaxRestore()
{
	if (isMaximized())
	{
		showNormal();
		setGeometry(m_rcNormal);
		qDebug() << m_rcNormal;

		QIconHelper::SetIcon(m_menuButton_Max, QChar(0xf096), 10);
		m_menuButton_Max->setToolTip(QStringLiteral("最大化"));
	}
	else
	{
		m_rcNormal = geometry();
		showMaximized();

		QIconHelper::SetIcon(m_menuButton_Max, QChar(0xf079), 10);
		m_menuButton_Max->setToolTip(QStringLiteral("还原"));
	}
}

bool QFramelessDialog::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
	Q_UNUSED(eventType);
	const int HIT_BORDER = 4;
	const MSG *msg = static_cast<MSG*>(message);

	if (msg->message == WM_NCCALCSIZE)
	{
		*result = 0;
		return true;
	}
	else if (msg->message == WM_NCHITTEST)
	{
		if (m_bResize == false || m_widget_title == nullptr)
		{
			return QDialog::nativeEvent(eventType, message, result);
		}

		if (isMaximized())
		{
			return false;
		}
		int xPos = ((int)(short)LOWORD(msg->lParam)) - this->frameGeometry().x();
		int yPos = ((int)(short)HIWORD(msg->lParam)) - this->frameGeometry().y();

		if (xPos >= 0 && xPos < HIT_BORDER && yPos >= 0 && yPos < HIT_BORDER) {
			*result = HTTOPLEFT;
			return true;
		}
		if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {
			*result = HTTOPRIGHT;
			return true;
		}
		if (xPos > 0 && xPos < HIT_BORDER && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
			*result = HTBOTTOMLEFT;
			return true;
		}
		if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
			*result = HTBOTTOMRIGHT;
			return true;
		}
		if (xPos >= 0 && xPos < HIT_BORDER) {
			*result = HTLEFT;
			return true;
		}
		if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {
			*result = HTRIGHT;
			return true;
		}
		if (yPos >= 0 && yPos < HIT_BORDER) {
			*result = HTTOP;
			return true;
		}
		if (yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
			*result = HTBOTTOM;
			return true;
		}
		if (m_widget_title->geometry().contains(QPoint(xPos, yPos)))
		{
			*result = HTCAPTION;
			return false;
		}
		return false;
	}
	return false;
}

#define SHADOW_BORDER 6
void QFramelessDialog::paintEvent(QPaintEvent *event)
{
	return QDialog::paintEvent(event);
// 
// 	QPainterPath path;
// 	path.setFillRule(Qt::WindingFill);
// 	path.addRect(SHADOW_BORDER, SHADOW_BORDER, this->width()-2*SHADOW_BORDER, this->height()-2*SHADOW_BORDER);
// 
// 	QPainter painter(this);
// 	painter.setRenderHint(QPainter::Antialiasing, true);
// 	painter.fillPath(path, QBrush(Qt::white));
// 
// 	QColor color(0, 0, 0, 60);
// 	for(int i=0; i<SHADOW_BORDER; i++)
// 	{
// 		QPainterPath path;
// 		path.setFillRule(Qt::WindingFill);
// 		path.addRect(SHADOW_BORDER-1-i, SHADOW_BORDER-1-i, this->width()-(SHADOW_BORDER-i)*2, this->height()-(SHADOW_BORDER-i)*2);
// 		color.setAlpha(40 - i * 7);
// 		painter.setPen(color);
// 		painter.drawPath(path);
// 	}
}

void QFramelessDialog::keyPressEvent(QKeyEvent* e)
{
	qDebug()<<e->key();
	switch (e->key())
	{
	case Qt::Key_Return:
		break;
	case Qt::Key_Enter:
		break;
	case Qt::Key_Escape:
		{
			if (m_bMinClose)
				break;
		}
	default:
		QDialog::keyPressEvent(e);
	}
}

调用示例:

#include <QDialog>
#include "ui_QSubDialog.h"
#include "QFramelessDialog.h"

class QSubDialog : public QFramelessDialog
{
	Q_OBJECT

public:
	QSubDialog(QWidget *parent = 0);
	~QSubDialog();

private:
	Ui::QSubDialog ui;
};
#include "stdafx.h"
#include "QSubDialog.h"

QSubDialog::QSubDialog(QWidget *parent)
	: QFramelessDialog(parent)
{
	ui.setupUi(this);
	FRAMELESS_DIALOG_INIT();
}

QSubDialog::~QSubDialog()
{

}

源代码下载

https://download.csdn.net/download/redchairman/12914480

QT实战派交流群

群号码:1149411109

群名称:Qt实战派学习群

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值