QMainwindow的鼠标跟踪事件不触发问题

发布于:2024-12-20 ⋅ 阅读:(70) ⋅ 点赞:(0)

一、无边框窗口实现代码

1.1 头文件

class EtcTestTool : public QMainWindow
{
	Q_OBJECT

public:
	EtcTestTool(QWidget *parent = Q_NULLPTR);
private:
	void InitialUi();
	//...
protected:
	void mousePressEvent(QMouseEvent*event)override;
	void mouseReleaseEvent(QMouseEvent*event)override;
	void mouseMoveEvent(QMouseEvent*event)override;
private:
	// 鼠标的 活动范围的枚举
	enum MousePosition
	{    /* 这里我们将一个窗口划分为9个区域,分别为
		左上角(1, 1)、中上(2,1)、右上角(3, 1)
		左中  (1, 2)、 中间(2, 2)、右中  (3, 2)
		左下角(1, 3)、中下(2,3)、 右下角(3, 3)
		10*x+y区分各个区域
		*/
		LeftTop = 11,
		Top = 21,
		RightTop = 31,
		Left = 12,
		Mid = 22,
		Right = 32,
		LeftBottom = 13,
		Bottom = 23,
		RightBottom = 33
	};
	//根据鼠标的设置鼠标样式,用于拉伸
	void SetMouseCursor(int x, int y);
	//判断鼠标的区域,用于拉伸
	int GetMouseRegion(int x, int y);
private:
	QPoint m_windowsLastPs;
	QPoint m_mouseLastPs;
	int m_mouse_press_region = MousePosition::Mid;
	QPoint m_dragStartPos;
	bool m_bPressing = false;

private:
	Ui::EtcTestToolClass ui;
};

1.2 实现文件


EtcTestTool::EtcTestTool(QWidget *parent)
	: QMainWindow(parent)
{
	
	setWindowFlags(Qt::FramelessWindowHint);
	ui.setupUi(this);
	InitialUi();
	//...
	
}


void EtcTestTool::InitialUi()
{
	//mainwindow的鼠标跟踪事件被子控件遮挡拦截
	this->setMouseTracking(true);
	ui.centralWidget->setMouseTracking(true);
	ui.frame->setMouseTracking(true);
	ui.frmTitle->setMouseTracking(true);
	ui.groupBox->setMouseTracking(true);
    //...
	
}


void EtcTestTool::on_btnMin_clicked()
{
	showMinimized();
}
void EtcTestTool::on_btnMax_clicked()
{
	if (isMaximized())
	{
		showNormal();
		ui.btnMax->setProperty("Max", false);
	}
	else
	{
		showMaximized();
		ui.btnMax->setProperty("Max", true);
	}
	ui.btnMax->style()->polish(ui.btnMax);
}

void EtcTestTool::on_btnClose_clicked()
{
	close();
}


void EtcTestTool::mousePressEvent(QMouseEvent*event)
{
	if (event->button() == Qt::LeftButton)
	{
		// 如果是鼠标左键
		// 获取当前窗口位置,以窗口左上角为标定
		m_windowsLastPs = pos();
		// 获取鼠标在屏幕的位置  就是全局的坐标 以屏幕左上角为坐标系
		m_mouseLastPs = event->globalPos();
		m_bPressing = true;
		m_mouse_press_region = GetMouseRegion(event->pos().x(), event->pos().y());
	}
	QWidget::mousePressEvent(event);
}

void EtcTestTool::mouseReleaseEvent(QMouseEvent*event)
{
	if (event->button() == Qt::LeftButton)
	{
		m_bPressing = false;
	}
	setCursor(QCursor{});
	QWidget::mousePressEvent(event);
}

void EtcTestTool::mouseMoveEvent(QMouseEvent*event)
{
	// 设置鼠标的形状
	SetMouseCursor(event->pos().x(), event->pos().y());
	// 计算的鼠标移动偏移量, 就是鼠标全局坐标 - 减去点击时鼠标坐标
	QPoint point_offset = event->globalPos() - m_mouseLastPs;
	if ((event->buttons() == Qt::LeftButton) && m_bPressing)
	{
		if (m_mouse_press_region == Mid)
		{
			// 如果鼠标是在窗口的中间位置,就是移动窗口
			move(m_windowsLastPs + point_offset);
		}
		else {
			// 其他部分 是拉伸窗口
			// 获取客户区
			QRect rect = geometry();
			switch (m_mouse_press_region)
			{
				// 左上角
			case LeftTop:
				rect.setTopLeft(rect.topLeft() + point_offset);
				break;
			case Top:
				rect.setTop(rect.top() + point_offset.y());
				break;
			case RightTop:
				rect.setTopRight(rect.topRight() + point_offset);
				break;
			case Right:
				rect.setRight(rect.right() + point_offset.x());
				break;
			case RightBottom:
				rect.setBottomRight(rect.bottomRight() + point_offset);
				break;
			case Bottom:
				rect.setBottom(rect.bottom() + point_offset.y());
				break;
			case LeftBottom:
				rect.setBottomLeft(rect.bottomLeft() + point_offset);
				break;
			case Left:
				rect.setLeft(rect.left() + point_offset.x());
				break;
			default:
				break;
			}
			setGeometry(rect);
			m_mouseLastPs = event->globalPos();
		}
	}
	QWidget::mousePressEvent(event);
}

void EtcTestTool::SetMouseCursor(int x, int y)
{
	// 鼠标形状对象
	Qt::CursorShape cursor{};
	int region = GetMouseRegion(x, y);
	switch (region)
	{
	case LeftTop:
	case RightBottom:
		cursor = Qt::SizeFDiagCursor; break;
	case RightTop:
	case LeftBottom:
		cursor = Qt::SizeBDiagCursor; break;
	case Left:
	case Right:
		cursor = Qt::SizeHorCursor; break;
	case Top:
	case Bottom:
		cursor = Qt::SizeVerCursor; break;
	caseMid:
		cursor = Qt::ArrowCursor; break;
	default:
		break;
	}
	setCursor(cursor);
}


int EtcTestTool::GetMouseRegion(int x, int y)
{
	int region_x = 0, region_y = 0;
	// 鼠标的X坐标小于 边界 说明他在最上层区域 第一区域
	if (x < kMouseBorderSize)
	{
		region_x = 1;
	}
	else if (x > (this->width() - kMouseBorderSize)) {
		region_x = 3;
	}
	else {
		region_x = 2;
	}
	if (y < kMouseBorderSize)
	{
		region_y = 1;
	}
	else if (y > (this->height() - kMouseBorderSize)) {
		region_y = 3;
	}
	else {
		region_y = 2;
	}
	return region_x * 10 + region_y;
}

二、鼠标移动事件无法触发

2.1 现象和原因

        Qt默认鼠标跟踪事件是关闭的,只有按下鼠标左键移动时才会触发;所以需要setMouseTracking(true)开启鼠标追踪事件。但是开启后仍然无法在不按左键情况下触发鼠标移动事件,后发现软件复写的QMainWindow的mouseMoveEvent函数,但是QMainWindow界面被centralWidget和布局的各种widget遮挡导致鼠标移动事件无法触发。

 

2.2 解决方案

解决方案:将QMainWindow的子控件centralWidget等同样开启鼠标跟踪事件setMouseTracking(true),则子控件的鼠标移动事件会通过事件循环传递到父类的QMainWindow中,最终触发QMainWindow的mouseMoveEvent函数。

void EtcTestTool::InitialUi()
{
    //mainwindow的鼠标跟踪事件被子控件遮挡拦截,
    this->setMouseTracking(true);
    ui.centralWidget->setMouseTracking(true);
    ui.frame->setMouseTracking(true);
    ui.frmTitle->setMouseTracking(true);
    ui.groupBox->setMouseTracking(true);
    //...
}