Qt无边框窗体模仿Win32标准窗体鼠标拖拽效果
程序员文章站
2022-03-02 10:29:36
...
本文介绍如何针对Qt的无边框窗体(即setWindowFlags(Qt::FramelessWindowHint);
)实现鼠标拖拽标题栏移动窗体位置、鼠标拖拽窗体四周边框改变窗体大小的行为。
一、为所有控件添加MouseTracking
在Qt中,控件默认只有在至少有一个鼠标按键被按下的情况下,控件才能捕获鼠标的移动事件。针对我们想要模拟“鼠标拖拽窗体四周边框改变窗体大小的行为”,需要能够实时获得鼠标的移动事件,以便在鼠标移动到窗体四周时能做出相应的处理。虽然我们可以对所有控件都添加上“鼠标追踪”属性(setMouseTracking(true);
),但一个个控件添加太麻烦,下面的setAllWidgetMouseTracking
函数,可以递归地为父widget下的所有控件添加“鼠标追踪”属性。一般情况我们只需要将centralWidget
传给setAllWidgetMouseTracking
函数即可。
void BaseMainWindow::setAllWidgetMouseTracking(QWidget *widget) {
if(!widget)
return;
widget->setMouseTracking(true);
QObjectList list = widget->children();
foreach(QObject *obj, list) {
if(obj->metaObject()->className() == QStringLiteral("QWidget")) {
QWidget* w = (QWidget*)obj;
qDebug() << w->objectName();
w->setMouseTracking(true);
setAllWidgetMouseTracking(w);
}
}
}
二、实现原理
- 模拟鼠标拖拽标题栏移动窗体位置
通过void setTitleWidget(const QString &widgetName);
接口设置一个widget名称,当鼠标左键在该widget区域按下,并保持着按下状态,就会启用鼠标移动则窗体位置跟着移动的效果。 - 模拟鼠标拖拽窗体四周边框改变窗体大小
通过void setEnableResize(bool b);
接口来启动该功能。
鼠标移动到窗体边缘附件时(具体值由m_iResizeRegionPadding
来设置),鼠标形状会变成Qt::SizeVerCursor
,此时用户再按下鼠标左键,移动鼠标就可以改变窗体大小。
BaseMainWindow .h
#pragma once
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QWidget>
class BaseMainWindow : public QMainWindow {
Q_OBJECT
public:
enum Direction {
UP = 0,
DOWN = 1,
LEFT,
RIGHT,
LEFTTOP,
LEFTBOTTOM,
RIGHTBOTTOM,
RIGHTTOP,
NONE
};
BaseMainWindow(QWidget *parent = Q_NULLPTR);
virtual ~BaseMainWindow();
void setTitleWidget(const QString &widgetName);
void setEnableResize(bool b);
void setAllWidgetMouseTracking(QWidget *widget);
protected:
bool eventFilter(QObject *target, QEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
protected:
void region(const QPoint &cursorGlobalPoint);
protected:
bool m_bLeftPressed;
Direction m_Direction;
const int m_iResizeRegionPadding;
bool m_bEnableResize;
QPoint m_DragPos;
QString m_strTitleWidget;
};
BaseMainWindow.cpp
#include "stdafx.h"
#include "BaseMainWindow.h"
BaseMainWindow::BaseMainWindow(QWidget *parent) : QMainWindow(parent),
m_bLeftPressed(false),
m_bEnableResize(false),
m_Direction(Direction::NONE),
m_iResizeRegionPadding(2) {
}
BaseMainWindow::~BaseMainWindow() {
}
void BaseMainWindow::setTitleWidget(const QString &widgetName) {
m_strTitleWidget = widgetName;
}
void BaseMainWindow::setEnableResize(bool b) {
m_bEnableResize = b;
}
void BaseMainWindow::mousePressEvent(QMouseEvent *event) {
if(event->button() == Qt::LeftButton) {
m_bLeftPressed = true;
if(m_Direction != Direction::NONE) {
this->mouseGrabber();
}
else if(m_strTitleWidget.length() > 0) {
QWidget *action = QApplication::widgetAt(event->globalPos());
if(action) {
if(action->objectName() == m_strTitleWidget) {
m_DragPos = event->globalPos() - this->frameGeometry().topLeft();
}
}
}
}
return QWidget::mousePressEvent(event);
}
void BaseMainWindow::mouseMoveEvent(QMouseEvent *event) {
QPoint globalPoint = event->globalPos();
if(m_bLeftPressed) {
if(m_Direction != NONE) {
QRect rect = this->rect();
QPoint tl = mapToGlobal(rect.topLeft());
QPoint rb = mapToGlobal(rect.bottomRight());
QRect rMove(tl, rb);
switch(m_Direction) {
case LEFT:
if(rb.x() - globalPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(globalPoint.x());
break;
case RIGHT:
rMove.setWidth(globalPoint.x() - tl.x());
break;
case UP:
if(rb.y() - globalPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(globalPoint.y());
break;
case DOWN:
rMove.setHeight(globalPoint.y() - tl.y());
break;
case LEFTTOP:
if(rb.x() - globalPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(globalPoint.x());
if(rb.y() - globalPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(globalPoint.y());
break;
case RIGHTTOP:
rMove.setWidth(globalPoint.x() - tl.x());
rMove.setY(globalPoint.y());
break;
case LEFTBOTTOM:
rMove.setX(globalPoint.x());
rMove.setHeight(globalPoint.y() - tl.y());
break;
case RIGHTBOTTOM:
rMove.setWidth(globalPoint.x() - tl.x());
rMove.setHeight(globalPoint.y() - tl.y());
break;
default:
break;
}
this->setGeometry(rMove);
}
else {
this->move(event->globalPos() - m_DragPos);
event->accept();
}
}
else {
region(globalPoint);
}
return QWidget::mouseMoveEvent(event);
}
void BaseMainWindow::region(const QPoint &cursorGlobalPoint) {
if(!m_bEnableResize)
return;
QRect rect = this->rect();
QPoint tl = mapToGlobal(rect.topLeft());
QPoint rb = mapToGlobal(rect.bottomRight());
int x = cursorGlobalPoint.x();
int y = cursorGlobalPoint.y();
if(tl.x() + m_iResizeRegionPadding >= x && tl.x() <= x && tl.y() + m_iResizeRegionPadding >= y && tl.y() <= y) {
// 左上角
m_Direction = Direction::LEFTTOP;
this->setCursor(QCursor(Qt::SizeFDiagCursor));
}
else if(x >= rb.x() - m_iResizeRegionPadding && x <= rb.x() && y >= rb.y() - m_iResizeRegionPadding && y <= rb.y()) {
// 右下角
m_Direction = Direction::RIGHTBOTTOM;
this->setCursor(QCursor(Qt::SizeFDiagCursor));
}
else if(x <= tl.x() + m_iResizeRegionPadding && x >= tl.x() && y >= rb.y() - m_iResizeRegionPadding && y <= rb.y()) {
//左下角
m_Direction = Direction::LEFTBOTTOM;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if(x <= rb.x() && x >= rb.x() - m_iResizeRegionPadding && y >= tl.y() && y <= tl.y() + m_iResizeRegionPadding) {
// 右上角
m_Direction = Direction::RIGHTTOP;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if(x <= tl.x() + m_iResizeRegionPadding && x >= tl.x()) {
// 左边
m_Direction = Direction::LEFT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if(x <= rb.x() && x >= rb.x() - m_iResizeRegionPadding) {
// 右边
m_Direction = Direction::RIGHT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if(y >= tl.y() && y <= tl.y() + m_iResizeRegionPadding) {
// 上边
m_Direction = Direction::UP;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else if(y <= rb.y() && y >= rb.y() - m_iResizeRegionPadding) {
// 下边
m_Direction = Direction::DOWN;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else {
// 默认
m_Direction = Direction::NONE;
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
void BaseMainWindow::mouseReleaseEvent(QMouseEvent *event) {
m_bLeftPressed = false;
if(m_Direction != NONE) {
this->releaseMouse();
this->setCursor(QCursor(Qt::ArrowCursor));
}
return QWidget::mouseReleaseEvent(event);
}
void BaseMainWindow::setAllWidgetMouseTracking(QWidget *widget) {
if(!widget)
return;
widget->setMouseTracking(true);
QObjectList list = widget->children();
foreach(QObject *obj, list) {
if(obj->metaObject()->className() == QStringLiteral("QWidget")) {
QWidget* w = (QWidget*)obj;
qDebug() << w->objectName();
w->setMouseTracking(true);
setAllWidgetMouseTracking(w);
}
}
}
上一篇: Qt的编程风格与规范
下一篇: 将String转化成HTML格式