通常我们在实现一个自定义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版权协议,转载请附上原文出处链接和本声明。