Qt 实现自定义无边框窗口拖动(windows平台的快速实现方法)

通常我们在实现一个自定义Qt窗口的拖动时,我们都要记录鼠标的按下位置和鼠标释放位置,然后通过move,进行移动。这样可以实现,但是比较繁琐,我在网上找到这样一个适用于windows平台的简单方法。

引入windows库

#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <qt_windows.h>
#endif

重载mousePressEvent

void mousePressEvent(QMouseEvent * event)
{
#ifdef Q_OS_WIN
	if (ReleaseCapture())
	{
		QWidget *pWindow = this->window();
		if (pWindow->isTopLevel())
		{
			SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
		}
	}
	event->ignore();
#else
#endif
}

使用实例

此方法的原理也是重载鼠标事件,而后调用的windows api。我在两种场景下使用过此方法。

一、直接在整个窗口上使用此重载函数,此时需要判断要拖动的是否是标题栏。

在这里插入图片描述
最简单的方式就是判断一下 y 值是否小于标题栏的高度了。

#include <QMouseEvent>
#include "GuiAddCameraDialog.h"

#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <qt_windows.h>
#endif

GuiAddCameraDialog::GuiAddCameraDialog(QWidget *parent)
	: QDialog(parent)
{
	ui.setupUi(this);

	connect(ui.btnClose, &QPushButton::clicked, this, &GuiAddCameraDialog::close);
	connect(ui.btnConfirm, &QPushButton::clicked, this, &GuiAddCameraDialog::accept);
	connect(ui.btnCancel, &QPushButton::clicked, this, &GuiAddCameraDialog::reject);
}

void GuiAddCameraDialog::mousePressEvent(QMouseEvent * event)
{
	if (event->pos().y() > 40)	// 小于40才允许拖动窗口
		return;
#ifdef Q_OS_WIN
	if (ReleaseCapture())
	{
		QWidget *pWindow = this->window();
		if (pWindow->isTopLevel())
		{
			SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
		}
	}
	event->ignore();
#else
#endif
}

二、单独写一个标题栏,重载Pressed实现。下面例子同时包含了,windows中实现窗口最大化、最小化等操作。

#include <QStyle>
#include <QLabel>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QPixmap>
#include <QTimer>
#include <QApplication>
#include "GuiTitleBar.h"

#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <qt_windows.h>
#endif

GuiTitleBar::GuiTitleBar(QWidget *parent)
	: QWidget(parent)
{
	setFixedHeight(30);

	m_pIconLabel = new QLabel(this);
	m_pTitleLabel = new QLabel(this);
	m_pMinimizeButton = new QPushButton(this);
	m_pMaximizeButton = new QPushButton(this);
	m_pCloseButton = new QPushButton(this);

	m_pIconLabel->setFixedSize(30, 30);
	m_pIconLabel->setScaledContents(true);

	m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

	m_pMinimizeButton->setIconSize(QSize(27, 22));
	m_pMinimizeButton->setIcon(QIcon(":/GuiCameraSetupWidget/Resources/minbutton.png"));
	m_pMinimizeButton->setFlat(true);
	//--
	m_pMaximizeButton->setIconSize(QSize(27, 22));
	m_pMaximizeButton->setIcon(QIcon(":/GuiCameraSetupWidget/Resources/maxbutton.png"));
	m_pMaximizeButton->setFlat(true);
	//--
	m_pCloseButton->setIconSize(QSize(27, 22));
	m_pCloseButton->setIcon(QIcon(":/GuiCameraSetupWidget/Resources/close1.png"));
	m_pCloseButton->setFlat(true);

	//设置窗口部件的名称
	m_pTitleLabel->setObjectName("whiteLabel");
	m_pMinimizeButton->setObjectName("minimizeButton");
	m_pMaximizeButton->setObjectName("maximizeButton");
	m_pCloseButton->setObjectName("closeButton");


	//给按钮设置静态tooltip,当鼠标移上去时显示tooltip
	m_pMinimizeButton->setToolTip("最小化");
	m_pMaximizeButton->setToolTip("最大化");
	m_pCloseButton->setToolTip("关闭");

	//标题栏布局
	QHBoxLayout *pLayout = new QHBoxLayout(this);
	pLayout->addWidget(m_pIconLabel);
	pLayout->addSpacing(5);
	pLayout->addWidget(m_pTitleLabel);
	pLayout->addWidget(m_pMinimizeButton);
	pLayout->addWidget(m_pMaximizeButton);
	pLayout->addWidget(m_pCloseButton);
	pLayout->setSpacing(0);
	pLayout->setContentsMargins(5, 0, 5, 0);
	setLayout(pLayout);

	//连接三个按钮的信号槽
	connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
	connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
	connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
}
GuiTitleBar::~GuiTitleBar()
{
}

void GuiTitleBar::mouseDoubleClickEvent(QMouseEvent * event)
{
	Q_UNUSED(event);

	emit m_pMaximizeButton->clicked();
}

void GuiTitleBar::mousePressEvent(QMouseEvent * event)
{
#ifdef Q_OS_WIN
	if (ReleaseCapture())
	{
		QWidget *pWindow = this->window();
		if (pWindow->isTopLevel())
		{
			SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
		}
	}
	event->ignore();
#else
#endif
}

bool GuiTitleBar::eventFilter(QObject * obj, QEvent * event)
{
	switch (event->type()) //判断发生事件的类型
	{
	case QEvent::WindowTitleChange: //窗口标题改变事件
	{
		QWidget *pWidget = qobject_cast<QWidget *>(obj); //获得发生事件的窗口对象
		if (pWidget)
		{
			//窗体标题改变,则标题栏标题也随之改变
			m_pTitleLabel->setText(pWidget->windowTitle());
			return true;
		}
	}
	break;

	case QEvent::WindowIconChange: //窗口图标改变事件
	{
		QWidget *pWidget = qobject_cast<QWidget *>(obj);
		if (pWidget)
		{
			//窗体图标改变,则标题栏图标也随之改变
			QIcon icon = pWidget->windowIcon();
			m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size()));
			return true;
		}
	}
	break;

	case QEvent::Resize:
		updateMaximize(); //最大化/还原
		return true;

	default:
		return QWidget::eventFilter(obj, event);
	}

	return QWidget::eventFilter(obj, event);
}

void GuiTitleBar::onClicked()
{
	//QObject::Sender()返回发送信号的对象的指针,返回类型为QObject *
	QPushButton *pButton = qobject_cast<QPushButton *>(sender());

	QWidget *pWindow = this->window(); //获得标题栏所在的窗口

	if (pWindow->isTopLevel())
	{
		//判断发送信号的对象使哪个按钮
		if (pButton == m_pMinimizeButton)
		{
			pWindow->showMinimized(); //窗口最小化显示
		}
		else if (pButton == m_pMaximizeButton)
		{
			pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();  //窗口最大化/还原显示
		}
		else if (pButton == m_pCloseButton)
		{
			pWindow->close(); //窗口关闭
		}
	}
}

void GuiTitleBar::updateMaximize()
{
	QWidget *pWindow = this->window(); //获得标题栏所在的窗口

	if (pWindow->isTopLevel())
	{
		bool bMaximize = pWindow->isMaximized(); //判断窗口是不是最大化状态,是则返回true,否则返回false
		if (bMaximize)
		{
			//目前窗口是最大化状态,则最大化/还原的toolTip设置为"Restore"
			m_pMaximizeButton->setToolTip(tr("还原"));
			m_pMaximizeButton->setIcon(QIcon(":/GuiCameraSetupWidget/Resources/maxbutton2.png"));
			//设置按钮的属性名为"maximizeProperty"
			m_pMaximizeButton->setProperty("maximizeProperty", "restore");
		}
		else
		{
			//目前窗口是还原状态,则最大化/还原的toolTip设置为"Maximize"
			m_pMaximizeButton->setToolTip(tr("最大化"));
			m_pMaximizeButton->setIcon(QIcon(":/GuiCameraSetupWidget/Resources/maxbutton.png"));
			//设置按钮的属性名为"maximizeProperty"
			m_pMaximizeButton->setProperty("maximizeProperty", "maximize");
		}

		m_pMaximizeButton->setStyle(QApplication::style());
	}
}

版权声明:本文为xiaonuo911teamo原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。