Qt implements custom header header

description

In many cases, you need to customize the style of the header. In Qt. If you remove the title header that comes with the system. Then many attributes will disappear. For example, the form cannot be dragged and dropped. It is not possible to stretch the window with the mouse.

Roughly realize the idea

Add a horizontal layout. There are two QLabel and three QPushButton inside. Two QLabel are used to display the icon and the title of the window. The three QPushButtons correspond to hidden. Maximize and close buttons.
Then when the mouse is near the edge of the form, the shape of the mouse cursor needs to be changed. And you can stretch the form. At the same time, you can drag and drop by pressing the mouse on the title. This title header maintains QWidget* _ownerWidget internally . In fact, it is the owning window of this title header. Then use event filters eventFilterto monitor events such as mouse events.
Implementation code

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);//安装事件过滤器
		
	}
}

Drag and drop implementation

When the mouse is pressed. Record the position where the mouse is pressed. Then record the difference with the last position when the mouse is dragged and moved. Then change the position of the form.
Implementation code

		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;

Change the mouse cursor

Setting the properties of_ownerWidget->setAttribute(Qt::WA_Hover); **_ownerWidget can detect mouse hovering events. Then determine where the mouse is in _ownerWidget**. If it is around, change the shape of the mouse cursor according to the direction.
Implementation code

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;
}

Mouse stretch form

First, determine how to change the position or size of the form according to the direction of the mouse drag. If the mouse is not around, but in the header of this title. Then it is to move the position of the form. If it's all around. You need to change the position and size of the form. Because the author does not have GIF production tools. The renderings will not be posted. The specific effect can be seen in visual studio. Place the mouse around the visual studio. You can find that the cursor has changed. If you click on the heading above, drag and drop to change the position. If dragging around. You can stretch to change the position of the form.
Implementation code

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;
	}
}

Usage example

#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();
}

Code link

Because many people's internet speed on GitHub is very slow. So the code is hosted on Gitee .
Note that the
code is not a complete project. There are only .h files and .cpp files. The file name is FCustomTitleWidget.h and FCustomTitleWidget.cpp
git address
https://gitee.com/zmf199785/csdncode.git The
code is in the FCustomTitleWidget directory

Guess you like

Origin blog.csdn.net/weixin_39308337/article/details/111401622