Qt实现自定义标题头

描述

在很多时候都需要自定义标题头的样式。在Qt里面。如果去掉了系统自带的标题头。那么很多属性也就会消失。例如没法拖拽窗体。没法通过鼠标拉伸窗体。

大致实现思路

添加一个水平布局。里面分别有两个QLabel以及三个QPushButton。两个QLabel用来显示图标和窗体标题。三个QPushButton分别对应着隐藏。最大化以及关闭按钮。
然后鼠标在靠近窗体的边缘的时候需要更改鼠标光标的形状。且可以拉伸窗体。同时鼠标按在标题上可以进行拖拽。此标题头内部维护了QWidget* _ownerWidget.其实就是这个标题头的拥有窗体。然后通过事件过滤器eventFilter来监测鼠标事件等事件。
实现代码

void FCustomTitleWidget::setUpConnection()
{
	connect(_buttonHide, &QPushButton::clicked, this, &FCustomTitleWidget::onTargetWidgetHide);//隐藏按钮
	connect(_buttonMinOrMax, &QPushButton::clicked, this, &FCustomTitleWidget::onTargetWidgetMinOrMax);//最大化最小化按钮
	connect(_buttonClose, &QPushButton::clicked, this, &FCustomTitleWidget::onTargetWidgetClose);//关闭按钮
}

void FCustomTitleWidget::initUi()
{
	_layoutMain = new QHBoxLayout;
	_layoutMain->setContentsMargins(0, 0, 0, 0);
	_layoutMain->setSpacing(5);
	_labelIcon = new QLabel(this);
	_labelIcon->setObjectName("labelIcon");
	_labelTitle = new QLabel(this);
	_labelTitle->setObjectName("labelTitle");
	_buttonHide = new QPushButton(this);
	_buttonHide->setObjectName("buttonHide");
	_buttonMinOrMax = new QPushButton(this);
	_buttonMinOrMax->setObjectName("buttonMinOrMax");
	_buttonClose = new QPushButton(this);
	_buttonClose->setObjectName("buttonClose");
	_layoutMain->addWidget(_labelIcon);
	_layoutMain->addWidget(_labelTitle);
	_layoutMain->addStretch();
	_layoutMain->addWidget(_buttonHide);
	_layoutMain->addWidget(_buttonMinOrMax);
	_layoutMain->addWidget(_buttonClose);
	this->setLayout(_layoutMain);
}
void FCustomTitleWidget::setOwnerWidget(QWidget * target)//设置拥有窗体
{
	assert(target);
	if (_ownerWidget != target)
	{
		if (_ownerWidget)
		{
			_ownerWidget->removeEventFilter(this);
		}
		_ownerWidget = target;
		_ownerWidget->setAttribute(Qt::WA_Hover);//hover属性
		_ownerWidget->installEventFilter(this);//安装事件过滤器
		
	}
}

拖拽的实现

在鼠标按下的时候。记录下鼠标按下的位置。然后在鼠标拖拽移动的时候记录下和上一次位置的差值。然后更改窗体的位置即可。
实现代码

		case QEvent::MouseButtonPress:
		{
			if (mouseEvent)
			{
				_mousePressedPoint = mouseEvent->pos();//记录下开始的位置
				_dragDir = getDragDirByMousePos(_mousePressedPoint);
				_lastMousePoint = mouseEvent->globalPos();
			}
		}
			break;
		case QEvent::MouseMove:
		{
			if (mouseEvent)
			{
				updateWidgetSizeByDragDir(_dragDir, mouseEvent->globalPos());//更改窗体大小或者位置
				_lastMousePoint = mouseEvent->globalPos();
			}
		}
			break;

更改鼠标光标

设置**_ownerWidget的属性_ownerWidget->setAttribute(Qt::WA_Hover);可以检测到鼠标悬浮移动事件。然后判断鼠标在_ownerWidget**的位置。若是在四周就根据所在的方向更改鼠标光标形状。
实现代码

Qt::CursorShape FCustomTitleWidget::getCursorShapeByDragDir(DragDir dir)
{
	Qt::CursorShape shape = Qt::ArrowCursor;
	switch (dir)
	{
	case 	DragDirMove:
	{
		shape = Qt::ArrowCursor;
	}
	break;
	case	DragDirLeftUp:
	case	DragDirRightBottom:
	{
		shape = Qt::SizeFDiagCursor;
	}
	 break;
	case	DragDirUp:
	case	DragDirBottom:
	{
		shape = Qt::SizeVerCursor;
	}
	break;
	case	DragDirRightUp:
	case	DragDirLeftBottom:
	{
		shape = Qt::SizeBDiagCursor;
	}
	break;
	case	DragDirLeft:
	case	DragDirRight:
	{
		shape = Qt::SizeHorCursor;
	}
	 break;
	default:
		break;
	}
	return shape;
}

鼠标拉伸窗体

首先根据鼠标拖拽的方向来确定如何更改窗体的位置或者大小。如果鼠标没有在四周,但是是在此标题头中。那么就是移动窗体的位置。如果在四周。就需要更改窗体的位置以及大小。由于笔者没有GIF制作工具。就不贴效果图了。具体的效果可以看看visual studio。将鼠标放在visual studio的四周。可以发现光标发生改变。若是按在上面的标题头,拖拽可以改变位置。若是在四周拖拽。可以拉伸改变窗体的位置。
实现代码

void FCustomTitleWidget::updateWidgetSizeByDragDir(DragDir dragDir, const QPoint &mousePos)
{
	if (_ownerWidget == nullptr)
	{
		return;
	}
	auto widgetGeometry = _ownerWidget->geometry();
	switch (dragDir)
	{
	case 	DragDirMove:
	{
		_ownerWidget->move(mousePos.x() - _lastMousePoint.x()+_ownerWidget->pos().x(), mousePos.y() - _lastMousePoint.y() + _ownerWidget->pos().y());
	}
	break;
	case	DragDirLeftUp:
	{
		widgetGeometry.setTopLeft(mousePos);
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirRightBottom:
	{
		widgetGeometry.setBottomRight(mousePos);
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirUp:
	{
		widgetGeometry.setTop(mousePos.y());
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirBottom:
	{
		widgetGeometry.setBottom(mousePos.y());
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirRightUp:
	{
		widgetGeometry.setTopRight(mousePos);
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirLeftBottom:
	{
		widgetGeometry.setBottomLeft(mousePos);
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirLeft:
	{
		widgetGeometry.setLeft(mousePos.x());
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	case	DragDirRight:
	{
		widgetGeometry.setRight(mousePos.x());
		_ownerWidget->setGeometry(widgetGeometry);
	}
	break;
	default:
		break;
	}
}

使用示例

#include "FCustomTitleWidget.h"//自定义标题头
#include <QVBoxLayout>
#include <QTableWidget>
class TestTitleWidget : public QWidget
{
public:
	TestTitleWidget()
	{
		_layout = new QVBoxLayout;
		this->setLayout(_layout);
		_titleWidget = new FCustomTitleWidget;
		_titleWidget->setOwnerWidget(this);//设置标题头的拥有窗体
		_layout->addWidget(_titleWidget);//标题头在最上面
		_tableWidget = new QTableWidget;
		_layout->addWidget(_tableWidget);
		this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);//去掉系统标题头
	}
	~TestTitleWidget() 
	{

	}
private:
	QVBoxLayout *_layout;
	QTableWidget *_tableWidget;
	FCustomTitleWidget* _titleWidget;
 };
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
	TestTitleWidget loginWidget;
	loginWidget.show();
    return a.exec();
}

代码链接

因为很多人上GitHub的网速都很慢。所以就将代码托管在了Gitee上面。
注意
代码不是一个完整的工程。只有.h文件以及.cpp文件。文件名是FCustomTitleWidget.hFCustomTitleWidget.cpp
git地址
https://gitee.com/zmf199785/csdncode.git
代码在FCustomTitleWidget 目录中

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一路初心向前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值