How does Qt imitate the docking window effect of Visual Studio

renderings

 

Function

1. The mouse is in the middle direction mark: overlay window
2. The mouse is in the top, bottom, left and right direction marks: divide the target window, and add a new window next to the surrounding position of the target window
3. The mouse is in the inner most up, down, left and right direction marks: the target window is located at the most Add a new window at the top, bottom, left,
and right positions 4. The mouse is on the outermost, top, bottom, left, and right directions: add a new window at the top, bottom, left, and right positions of the main program window. 5. The mouse is on the tab position: insert a new window at
the current tab page position.
On the rightmost position: add a new window at the end of the tab page.
Comments: Dock docking priority: In some cases, the outer most up, down, left, and right directions will overlap with the target window direction. At this time, following the middle docking is better than the external docking , The principle that direction indicator docking is better than tab page docking.

partial header file

#pragma once
#include <QWidget>
#include <QPaintEvent>
#include "QWHDockWidget.h"
class QMainWindow;
class QTabWidget;
class QDockWidget;
class QSplitter;
class QWHTabWidgetMask : public QWidget
{
	Q_OBJECT
public:
	enum Area
	{
		None,Top, Right, Bottom, Left, TopMore, RightMore, BottomMore, LeftMore, Center, TopMost, RightMost, BottomMost, LeftMost
	};
	QWHTabWidgetMask();
	~QWHTabWidgetMask();
	static QWHTabWidgetMask *getInstance();
	// 设置程序主窗口
	void setMainWindow(QMainWindow *mainWindow);
	// 创建停靠窗口
	QWHDockWidget *createDockWidget(QWHDockWidget::AreaMode areaMode, const QString &windowTitle = "");
	// 创建分裂器(水平分裂)
	QSplitter *createSplitter();
	// 创建分裂器(由参数orientation决定分裂方向)
	QSplitter *createSplitter(Qt::Orientation orientation);
	// 设置程序主分裂器
	void setMainSplitter(QSplitter *splitter);
	// 设置目标窗口(接收方)
	void setTargetWidget(QTabWidget *widget);
	// 设置当前页索引(鼠标移入当前页 或 鼠标移入中心方向标)
	void setCurTabIndex(int index);
	// 设置鼠标按下的停靠窗口(准备移动的窗口)
	void setMousePressed(QWHDockWidget *moveDockWidget);
	// 设置鼠标释放
	void setMouseReleased();
	// 获取停靠窗口推荐最小尺寸
	QSize minimumSizeHint() const override;
	// 获取鼠标按下的停靠窗口(准备移动或正在移动的窗口)
	QDockWidget *moveDockWidget();
	// 获取程序主分裂器
	QSplitter *mainSplitter();
	// 获取程序主窗口
	QMainWindow *mainWindow();
protected:
	void paintEvent(QPaintEvent *event);
private:
	// 获取指定索引的边界路径
	QPainterPath tabWidgetBorderPath(QTabWidget *tabWidget, int tabIndex);
	// 绘制主停靠窗口的指示器
	void drawMainDockIndicator();
	// 绘制次停靠窗口的指示器
	void drawMinorDockIndicator();
	// 检查鼠标所在方向标区域
	Area checkArea(QPoint globalPos);
signals:
	// 创建停靠窗口
	void dockWidgetAdded(QWHDockWidget *newDockWidget);
private:
	QMainWindow *m_mainWindow;
	QSplitter *m_mainSplitter;
	QWHDockWidget *m_moveDockWidget;
	QTabWidget *m_targetWidget;
	QList<QWHDockWidget *> m_listDockWidgets;
	int m_tabIndex;
	QColor m_borderColor;
	QColor m_bgColor;
	QRect m_centerRect;	// 中心矩形
	QRect m_topRect, m_rightRect, m_bottomRect, m_leftRect;	// 四个方位矩形(紧挨着中心矩形)
	QRect m_topMoreRect, m_rightMoreRect, m_bottomMoreRect, m_leftMoreRect;	// 更加靠边四个方位矩形(紧挨着四个方位矩形)
	QRect m_topMostRect, m_rightMostRect, m_bottomMostRect, m_leftMostRect;	// 最靠边四个方向矩形(紧挨着主窗口四边)
	QPixmap m_centerPixmap;
	QPixmap m_topPixmap, m_rightPixmap, m_bottomPixmap, m_leftPixmap;
	QPixmap m_topMostPixmap, m_rightMostPixmap, m_bottomMostPixmap, m_leftMostPixmap;
	QPixmap m_centerPixmapHover;
	QPixmap m_topPixmapHover, m_rightPixmapHover, m_bottomPixmapHover, m_leftPixmapHover;
	QPixmap m_topMostPixmapHover, m_rightMostPixmapHover, m_bottomMostPixmapHover, m_leftMostPixmapHover;
};

test code

TestVSWindow::TestVSWindow(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
	QWHTabWidgetMask::getInstance()->setMainWindow(this);
	
	// 测试左侧停靠窗体
	QWHDockWidget *dockWidget = QWHTabWidgetMask::getInstance()->createDockWidget(QWHDockWidget::Mode_Minor, "总tab");
	QSplitter *splitter = QWHTabWidgetMask::getInstance()->createSplitter();
	splitter->addWidget(dockWidget);
	dockWidget->setFloating(false);
	
	QWidget *widget1 = new QWidget();
	widget1->setMinimumSize(200, 100);
	widget1->setStyleSheet("background-color: green;");
	dockWidget->tabWidget()->addTab(widget1, "第一页");
	QWidget *widget2 = new QWidget();
	widget2->setMinimumSize(200, 100);
	widget2->setStyleSheet("background-color: green;");
	dockWidget->tabWidget()->addTab(widget2, "第二页");
	QWidget *widget3 = new QWidget();
	widget3->setMinimumSize(200, 100);
	widget3->setStyleSheet("background-color: green;");
	dockWidget->tabWidget()->addTab(widget3, "第三页");
	// 测试中间停靠窗体
	QWHDockWidget *dockWidgetCenter = QWHTabWidgetMask::getInstance()->createDockWidget(QWHDockWidget::Mode_Main, "总tabCenter");
	splitter->addWidget(dockWidgetCenter);
	dockWidgetCenter->setFloating(false);
	
	QWidget *widgetCenter1 = new QWidget();
	widgetCenter1->setMinimumSize(200, 100);
	widgetCenter1->setStyleSheet("background-color: rgb(255, 174, 201);");
	dockWidgetCenter->tabWidget()->addTab(widgetCenter1, "第一页Center");
	QWidget *widgetCenter2 = new QWidget();
	widgetCenter2->setMinimumSize(200, 100);
	widgetCenter2->setStyleSheet("background-color: rgb(255, 174, 201);");
	dockWidgetCenter->tabWidget()->addTab(widgetCenter2, "第二页Center");
	QWidget *widgetCenter3 = new QWidget();
	widgetCenter3->setMinimumSize(200, 100);
	widgetCenter3->setStyleSheet("background-color: rgb(255, 174, 201);");
	dockWidgetCenter->tabWidget()->addTab(widgetCenter3, "第三页Center");
	// 测试右侧停靠窗体
	QWHDockWidget *dockWidget2 = QWHTabWidgetMask::getInstance()->createDockWidget(QWHDockWidget::Mode_Minor, "总tab2");
	splitter->addWidget(dockWidget2);
	dockWidget2->setFloating(false);
	QWidget *widget12 = new QWidget();
	widget12->setMinimumSize(200, 100);
	widget12->setStyleSheet("background-color: gray;");
	dockWidget2->tabWidget()->addTab(widget12, "第一页2");
	QWidget *widget22 = new QWidget();
	widget22->setMinimumSize(200, 100);
	widget22->setStyleSheet("background-color: gray;");
	dockWidget2->tabWidget()->addTab(widget22, "第二页2");
	QWidget *widget32 = new QWidget();
	widget32->setMinimumSize(200, 100);
	widget32->setStyleSheet("background-color: gray;");
	dockWidget2->tabWidget()->addTab(widget32, "第三页2");
	QWHTabWidgetMask::getInstance()->setMainSplitter(splitter);
}

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/130566443
Recommended