Qt实现改变无标题栏窗体大小及移动窗体

在Qt中,通过设置Qt::FramelessWindowHint标志可以去掉窗体标题栏,但这会导致无法拖动窗体和改变大小。解决方案是使用QSizeGrip类实现拖动和调整大小功能。当使用QSizeGrip时,会同时触发窗体移动和大小改变。为了解决这个问题,需要从QSizeGrip派生新的类,重写鼠标事件处理,以确保仅能改变窗体大小而不会移动它。
摘要由CSDN通过智能技术生成

目录

1.问题的提出

2.实现方法

3.存在的问题


1.问题的提出

一般情况下,当去掉窗体标题栏时,按住鼠标左键就无法实现拖动窗体;当去掉窗体标题栏时,窗体四周的边框也去掉了,此时按住鼠标左键拖动窗体四周边沿,无法实现鼠标拖动改变窗体大小。如下为Qt实现去掉窗体标题栏的代码:


	setWindowFlag(Qt::FramelessWindowHint);  // 去掉标题栏

现在的问题是:

  • 在去掉窗体标题栏的情况下,如何按住鼠标左键,实现鼠标拖动改变窗体大小?
  • 在去掉窗体标题栏的情况下,如何在窗体上按住鼠标左键,实现移动窗体?

2.实现方法

Qt中有个QSizeGrip类,可以很好解决1节提到的问题,关于该类的具体用法,参见Qt Assistant。

下面直接上代码:

.h文件如下:

#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtGuiApplication2.h"

class QtGuiApplication2 : public QWidget
{
	Q_OBJECT

public:
	QtGuiApplication2(QWidget *parent = Q_NULLPTR);

private:  // virtual

	void mousePressEvent(QMouseEvent* event) override;

	void mouseReleaseEvent(QMouseEvent* event) override;

	void mouseMoveEvent(QMouseEvent* event) override;
private:
	Ui::QtGuiApplication2Class ui;
	bool m_bLeftMousePressed{ false };  // 鼠标左键是否被按下
	QPoint m_lastPoint;               // 鼠标上次按下的点
};

.cpp文件如下:

#include "QtGuiApplication2.h"
#include<QSizeGrip>
#include<QVBoxLayout>
#include<QFrame>
#include<QStatusBar>
#include<QMouseEvent>
QtGuiApplication2::QtGuiApplication2(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	setWindowFlag(Qt::FramelessWindowHint);  // 去掉标题栏

	QVBoxLayout* pMainWnd = new QVBoxLayout(this);
	setLayout(pMainWnd);

	auto pFrame = new QFrame(this);
	pFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	pMainWnd->addWidget(pFrame);
	
	QHBoxLayout* pBottomLayout = new QHBoxLayout(this);
	pMainWnd->addLayout(pBottomLayout);

	// 加一个水平弹簧,为了把后面的QSizeGrip挤到最右边
	auto horizontalSpacer = new QSpacerItem(193, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
	pBottomLayout->addItem(horizontalSpacer);

   // 创建QSizeGrip对象,该对象就是用来调整窗体大小的
	auto pSizeGrip = new QSizeGrip(this);
	pSizeGrip->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
	pBottomLayout->addWidget(pSizeGrip); // 将QSizeGrip对象加入窗体右下角

	// 也可以加入一个状态栏来实现拖动窗体右下角改变窗体大小
	//auto pStatusBar = new QStatusBar(this);
	//pStatusBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
	//pBottomLayout->addWidget(pStatusBar);
}

// 鼠标左键按下,准备移动窗体
void  QtGuiApplication2::mousePressEvent(QMouseEvent* event)
{
	if (Qt::LeftButton != event->button())
	{
		return;
	}

	m_lastPoint = event->globalPos();
	m_bLeftMousePressed = true;
}

// 移动窗体结束
void  QtGuiApplication2::mouseReleaseEvent(QMouseEvent* event)
{
	if (Qt::LeftButton != event->button())
	{
		return;
	}

	m_bLeftMousePressed = false;
}

// 开始移动窗体
void  QtGuiApplication2::mouseMoveEvent(QMouseEvent* event)
{
	auto curMousePt = event->globalPos(); // 注意:这里记录是窗体在屏幕上的坐标位置
	auto offsetPt = curMousePt - m_lastPoint; // 计算和上次移动点的坐标差值
	move(pos() + offsetPt);
	m_lastPoint = curMousePt;  // 记录本次窗体所在位置,以便下次计算位置
}

效果如下:

图1

QSizeGrip对象在窗体中的位置如下:

图2

说明:

  • Qt中的QDialog和QStatusBar类封装了 QSizeGrip对象,故上面代码也可以插入QStatusBar类到右下角来实现 QSizeGrip对象调整大小功能,即注释掉29~31行代码,取消34~36注释,实现同样功能。
  • Qt中的QDialog和QStatusBar类提供了setSizeGripEnabled(bool)方法用来设置是否启用QSizeGrip对象,默认是启用的,即右下角QSizeGrip对象是可见的。

3.存在的问题

       从图1可以看到,当按住鼠标左键拖动右下角的QSizeGrip对象以改变窗体大小,此时窗体大小确实改变了,但窗体也随之被移动了,也就是既改变了窗体大小也移动了窗体。原因是QSizeGrip对象必须响应鼠标移动事件才能改变窗体大小,与此同时窗体响应鼠标事件被移动。如何只保证改变窗体大小,而不移动窗体呢?此时必须从QSizeGrip类派生出自己的子类,代码如下:

mySizeGrip.h:

#pragma once

#include <QSizeGrip>
namespace Ui { class CMySizeGrip; };

class CMySizeGrip : public QSizeGrip
{
	Q_OBJECT

public:
	CMySizeGrip(QWidget *parent = Q_NULLPTR);
	~CMySizeGrip();
private:  // virtual

	void mousePressEvent(QMouseEvent* event) override;

	void mouseReleaseEvent(QMouseEvent* event) override;

	void mouseMoveEvent(QMouseEvent* event) override;

private:
	Ui::CMySizeGrip *ui;
	QPoint m_lastPoint;                 // 鼠标上次按下的点
	QWidget* m_pParent; // 父窗体,也就是要调节大小的窗体
};

mySizeGrip.cpp:

#include "mySizeGrip.h"
#include "ui_mySizeGrip.h"
#include<QMouseEvent>
#include<QApplication>
CMySizeGrip::CMySizeGrip(QWidget *parent)
	: QSizeGrip(parent)
{
	m_pParent = parent;
	ui = new Ui::CMySizeGrip();
	ui->setupUi(this);
}

CMySizeGrip::~CMySizeGrip()
{
	delete ui;
}
void  CMySizeGrip::mousePressEvent(QMouseEvent* event)
{
	if (Qt::LeftButton != event->button())
	{
		return;
	}

	m_lastPoint = event->globalPos();
}

void  CMySizeGrip::mouseReleaseEvent(QMouseEvent* event)
{

}
void  CMySizeGrip::mouseMoveEvent(QMouseEvent* event)
{
	auto curMousePt = event->globalPos();
	auto offset = curMousePt - m_lastPoint;
	m_lastPoint = curMousePt;

    // 调整父窗体大小
	m_pParent->resize(m_pParent->size().width() + offset.x(), m_pParent->size().height() + offset.y());
}

将前面第29行的:

auto pSizeGrip = new QSizeGrip(this);

改为:

auto pSizeGrip = new CMySizeGrip(this);

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值