QT 自定义可拖动缩放的无边框窗口,可用于mainmindow, widget
1. 用于拖动,缩放的工具类
“WindowControl.h”
#ifndef WINDOWCONTROL_H
#define WINDOWCONTROL_H
#include <QObject>
#include <QRubberBand>
#include <QStyleOptionFocusRect>
#include <QStylePainter>
class RubberBand;
class CursorPosCalculator;
/**
* 窗口控制类
* 存储界面对应的数据集合,及是否可移动、可缩放属性
* 进行缩放等相关操作
*/
class WindowControl : public QObject {
Q_OBJECT
public:
explicit WindowControl(QObject *parent = nullptr);
~WindowControl();
void activeWindow(QWidget *window); // 激活窗体
void removeWindow(QWidget *window); // 移除窗口
void setWindowMove(bool moveAble); // 窗体移动
void setWindowResize(bool resizeAble); // 窗体缩放
void setRubberBandOnMove(bool movable); // 设置橡皮筋移动
void setRubberBandOnResize(bool resizable); // 设置橡皮筋缩放
void handleWidgetEvent(QEvent *event); // 处理鼠标划过、按下、按下、释放、移动事件
void updateRubberBandStatus(); // 更新橡皮筋状态
protected:
virtual bool eventFilter(QObject *obj,
QEvent *event); // 事件过滤, 移动,缩放
private:
/** 状态 **/
// QHash<QWidget*, WindowData*> windowDataHash; // 缓存要控制的窗口
bool windowMoveAble; // 可以移动
bool windowResizeAble; // 可以缩放
bool windowRubberBandOnResize; // 可以橡皮筋移动
bool windowRubberBandOnMove; // 可以橡皮筋缩放
/** 窗口及其操作 **/
RubberBand *m_pRubberBand; // 橡皮筋选择框
QWidget *m_pWidget; // 被控制的窗口
QPoint m_ptDragPos; // 拖动时坐标
CursorPosCalculator *m_pressedMousePos;
CursorPosCalculator *m_moveMousePos;
bool m_bLeftButtonPressed; // 鼠标左键是否按下
bool m_bCursorShapeChanged; // 鼠标形状是否改变
bool m_bLeftButtonTitlePressed; // 标题区域是否按下鼠标
Qt::WindowFlags m_windowFlags;
void updateCursorShape(const QPoint &gMousePos); // 更新鼠标样式
void resizeWidget(const QPoint &gMousePos); // 重置窗体大小
void moveWidget(const QPoint &gMousePos); // 移动窗体
void handleMousePressEvent(QMouseEvent *event); // 处理鼠标按下
void handleMouseReleaseEvent(QMouseEvent *event); // 处理鼠标释放
void handleMouseMoveEvent(QMouseEvent *event); // 处理鼠标移动
void handleLeaveEvent(QEvent *event); // 处理鼠标离开
void handleHoverMoveEvent(QHoverEvent *event); // 处理鼠标进入
};
// ================================================================
/**
* 窗口控制,
*/
class WindowData {};
// ==================================================================
/**
* 自定义的橡皮筋选择框
* @brief The RubberBand class
*/
class RubberBand : public QRubberBand {
public:
RubberBand(Shape s, QWidget *p = nullptr) : QRubberBand(s, p) {
QPalette palette;
palette.setBrush(QPalette::WindowText, QBrush(Qt::lightGray));
setPalette(palette); // 调色板应用到当前的橡皮筋对象上
repaint();
}
protected:
virtual void paintEvent(QPaintEvent *) {
QStylePainter painter(this);
QStyleOptionFocusRect option;
option.initFrom(this);
QPen pen;
pen.setStyle(Qt::DashLine);
pen.setWidth(1);
pen.setColor(QColor(Qt::red));
painter.setPen(pen);
painter.drawControl(QStyle::CE_FocusFrame, option);
}
};
// ==================================================================
/**
* 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
*/
class CursorPosCalculator {
public:
explicit CursorPosCalculator();
void reset();
void recalculate(const QPoint &globalMousePos, const QRect &frameRect);
public:
bool m_bOnEdges;
bool m_bOnLeftEdge;
bool m_bOnRightEdge;
bool m_bOnTopEdge;
bool m_bOnBottomEdge;
bool m_bOnTopLeftEdge;
bool m_bOnBottomLeftEdge;
bool m_bOnTopRightEdge;
bool m_bOnBottomRightEdge;
static int m_nBorderWidth;
static int m_nTitleHeight;
};
#endif // WINDOWCONTROL_H
WindowControl.cpp
#include "utils/WindowControl.h"
#include "qcoreevent.h"
#include <QMouseEvent>
/**
* @brief WindowControl::WindowControl
*/
WindowControl::WindowControl(QObject *parent) : QObject(parent) {
// 初始化状态
windowMoveAble = true;
windowResizeAble = true;
windowRubberBandOnMove = false;
windowRubberBandOnResize = false;
m_pressedMousePos = new CursorPosCalculator;
m_moveMousePos = new CursorPosCalculator;
}
WindowControl::~WindowControl() {
m_pWidget->setMouseTracking(false); // 禁用鼠标跟踪
m_pWidget->setWindowFlags(m_windowFlags); // 还原窗口标志
m_pWidget->setAttribute(Qt::WA_Hover, false); // 禁用鼠标指针悬停事件
delete m_pRubberBand;
m_pRubberBand = NULL;
delete m_pressedMousePos;
m_pressedMousePos = NULL;
delete m_moveMousePos;
m_moveMousePos = NULL;
}
bool WindowControl::eventFilter(QObject *obj, QEvent *event) {
switch (event->type()) {
case QEvent::MouseMove:
case QEvent::HoverMove:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::Leave: {
if (obj == m_pWidget) {
handleWidgetEvent(event);
return true;
}
}
default:
return QObject::eventFilter(obj, event);
}
}
void WindowControl::activeWindow(QWidget *window) {
m_pWidget = window;
window->installEventFilter(this); // 安装事件过滤器
m_bLeftButtonPressed = false;
m_bCursorShapeChanged = false;
m_bLeftButtonTitlePressed = false;
m_pRubberBand = NULL;
m_windowFlags = m_pWidget->windowFlags();
m_pWidget->setMouseTracking(true); // 鼠标追踪
m_pWidget->setAttribute(Qt::WA_Hover, true); // 启用鼠标指针悬停事件
updateRubberBandStatus();
}
void WindowControl::removeWindow(QWidget *window) {
if (m_pWidget) {
delete this;
}
}
void WindowControl::setWindowMove(bool moveAble) { windowMoveAble = moveAble; }
void WindowControl::setWindowResize(bool resizeAble) { windowResizeAble = resizeAble; }
void WindowControl::setRubberBandOnMove(bool movable) {
windowRubberBandOnMove = movable;
updateRubberBandStatus();
}
void WindowControl::setRubberBandOnResize(bool resizable) {
windowRubberBandOnResize = resizable;
updateRubberBandStatus();
}
void WindowControl::updateRubberBandStatus() {
if (windowRubberBandOnResize || windowRubberBandOnMove) {
if (NULL == m_pRubberBand) {
m_pRubberBand = new RubberBand(QRubberBand::Rectangle);
}
} else {
delete m_pRubberBand;
m_pRubberBand = NULL;
}
}
void WindowControl::handleWidgetEvent(QEvent *event) {
switch (event->type()) {
default:
break;
case QEvent::MouseButtonPress:
handleMousePressEvent(static_cast<QMouseEvent *>(event));
break;
case QEvent::MouseButtonRelease:
handleMouseReleaseEvent(static_cast<QMouseEvent *>(event));
break;
case QEvent::MouseMove:
handleMouseMoveEvent(static_cast<QMouseEvent *>(event));
break;
case QEvent::Leave:
handleLeaveEvent(event);
break;
case QEvent::HoverMove:
handleHoverMoveEvent(static_cast<QHoverEvent *>(event));
break;
}
}
void WindowControl::updateCursorShape(const QPoint &gMousePos) {
// 检查全屏或最大化状态
if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
if (m_bCursorShapeChanged) {
m_pWidget->unsetCursor(); // 光标设置为默认
}
return;
}
m_moveMousePos->recalculate(gMousePos, m_pWidget->frameGeometry());
if (m_moveMousePos->m_bOnTopLeftEdge || m_moveMousePos->m_bOnBottomRightEdge) {
m_pWidget->setCursor(Qt::SizeFDiagCursor); // 对角线大小调整光标
m_bCursorShapeChanged = true;
} else if (m_moveMousePos->m_bOnTopRightEdge || m_moveMousePos->m_bOnBottomLeftEdge) {
m_pWidget->setCursor(Qt::SizeBDiagCursor); // 反对角线大小调整光标
m_bCursorShapeChanged = true;
} else if (m_moveMousePos->m_bOnLeftEdge || m_moveMousePos->m_bOnRightEdge) {
m_pWidget->setCursor(Qt::SizeHorCursor); // 水平调整大小光标
m_bCursorShapeChanged = true;
} else if (m_moveMousePos->m_bOnTopEdge || m_moveMousePos->m_bOnBottomEdge) {
m_pWidget->setCursor(Qt::SizeVerCursor); // 垂直调整大小光标
m_bCursorShapeChanged = true;
} else {
if (m_bCursorShapeChanged) {
m_pWidget->unsetCursor(); // 恢复默认
m_bCursorShapeChanged = false;
}
}
}
void WindowControl::resizeWidget(const QPoint &gMousePos) {
QRect origRect;
if (windowRubberBandOnResize)
origRect = m_pRubberBand->frameGeometry();
else
origRect = m_pWidget->frameGeometry();
int left = origRect.left();
int top = origRect.top();
int right = origRect.right();
int bottom = origRect.bottom();
origRect.getCoords(&left, &top, &right, &bottom);
// int minWidth = m_pWidget->minimumWidth();
// int minHeight = m_pWidget->minimumHeight();
int minWidth = 40;
int minHeight = 40;
if (m_pressedMousePos->m_bOnTopLeftEdge) {
left = gMousePos.x();
top = gMousePos.y();
} else if (m_pressedMousePos->m_bOnBottomLeftEdge) {
left = gMousePos.x();
bottom = gMousePos.y();
} else if (m_pressedMousePos->m_bOnTopRightEdge) {
right = gMousePos.x();
top = gMousePos.y();
} else if (m_pressedMousePos->m_bOnBottomRightEdge) {
right = gMousePos.x();
bottom = gMousePos.y();
} else if (m_pressedMousePos->m_bOnLeftEdge) {
left = gMousePos.x();
} else if (m_pressedMousePos->m_bOnRightEdge) {
right = gMousePos.x();
} else if (m_pressedMousePos->m_bOnTopEdge) {
top = gMousePos.y();
} else if (m_pressedMousePos->m_bOnBottomEdge) {
bottom = gMousePos.y();
}
QRect newRect(QPoint(left, top), QPoint(right, bottom));
if (newRect.isValid()) {
if (minWidth > newRect.width()) {
if (left != origRect.left())
newRect.setLeft(origRect.left());
else
newRect.setRight(origRect.right());
}
if (minHeight > newRect.height()) {
if (top != origRect.top())
newRect.setTop(origRect.top());
else
newRect.setBottom(origRect.bottom());
}
if (windowRubberBandOnResize) {
m_pRubberBand->setGeometry(newRect);
} else {
m_pWidget->setGeometry(newRect);
}
}
}
void WindowControl::moveWidget(const QPoint &gMousePos) {
if (windowRubberBandOnMove) {
m_pRubberBand->move(gMousePos - m_ptDragPos);
} else {
m_pWidget->move(gMousePos - m_ptDragPos);
}
}
void WindowControl::handleMousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
m_bLeftButtonPressed = true;
m_bLeftButtonTitlePressed = event->pos().y() < 30;
QRect frameRect = m_pWidget->frameGeometry();
QRect moveRect(frameRect.x(), frameRect.y(), frameRect.width(), 30);
m_pressedMousePos->recalculate(event->globalPos(), frameRect);
m_ptDragPos = event->globalPos() - frameRect.topLeft();
if (m_pressedMousePos->m_bOnEdges) {
if (windowRubberBandOnResize) {
m_pRubberBand->setGeometry(frameRect);
m_pRubberBand->show();
}
} else if (windowRubberBandOnMove) {
if (moveRect.contains(event->globalPos())) {
m_pRubberBand->setGeometry(frameRect);
m_pRubberBand->show();
}
}
}
}
void WindowControl::handleMouseReleaseEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
m_bLeftButtonPressed = false;
m_bLeftButtonTitlePressed = false;
m_pressedMousePos->reset();
if (m_pRubberBand && m_pRubberBand->isVisible()) {
m_pRubberBand->hide();
m_pWidget->setGeometry(m_pRubberBand->geometry());
}
}
}
void WindowControl::handleMouseMoveEvent(QMouseEvent *event) {
if (m_bLeftButtonPressed) {
if (windowResizeAble && m_pressedMousePos->m_bOnEdges) {
resizeWidget(event->globalPos());
} else if (windowMoveAble && m_bLeftButtonTitlePressed) {
moveWidget(event->globalPos());
}
} else if (windowResizeAble) {
updateCursorShape(event->globalPos());
}
}
void WindowControl::handleLeaveEvent(QEvent *event) {
Q_UNUSED(event)
if (!m_bLeftButtonPressed) {
m_pWidget->unsetCursor();
}
}
void WindowControl::handleHoverMoveEvent(QHoverEvent *event) {
if (windowResizeAble) {
updateCursorShape(m_pWidget->mapToGlobal(event->pos())); // 局部坐标转全局屏幕坐标
}
}
// CursorPosCalculator==========================================
int CursorPosCalculator::m_nBorderWidth = 5;
int CursorPosCalculator::m_nTitleHeight = 30;
CursorPosCalculator::CursorPosCalculator() { reset(); }
void CursorPosCalculator::reset() {
m_bOnEdges = false;
m_bOnLeftEdge = false;
m_bOnRightEdge = false;
m_bOnTopEdge = false;
m_bOnBottomEdge = false;
m_bOnTopLeftEdge = false;
m_bOnBottomLeftEdge = false;
m_bOnTopRightEdge = false;
m_bOnBottomRightEdge = false;
}
void CursorPosCalculator::recalculate(const QPoint &gMousePos, const QRect &frameRect) {
int globalMouseX = gMousePos.x();
int globalMouseY = gMousePos.y();
int frameX = frameRect.x();
int frameY = frameRect.y();
int frameWidth = frameRect.width();
int frameHeight = frameRect.height();
m_bOnLeftEdge = (globalMouseX >= frameX && globalMouseX <= frameX + m_nBorderWidth);
m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth && globalMouseX <= frameX + frameWidth);
m_bOnTopEdge = (globalMouseY >= frameY && globalMouseY <= frameY + m_nBorderWidth);
m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth && globalMouseY <= frameY + frameHeight);
m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge;
m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge;
m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge;
m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge;
m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge;
}
2. 使用示例
定义基类:
#ifndef WINDOW_H
#define WINDOW_H
#include <QMainWindow>
/**
* 自定义无边框mainwindow
*/
class Window : public QMainWindow {
Q_OBJECT
public:
Window(QWidget *parent = nullptr);
~Window();
private:
void framelesshelperInit();
};
#endif // WINDOW_H
#include "component/window.h"
#include "utils/WindowControl.h"
Window::Window(QWidget *parent) : QMainWindow(parent) {
resize(1200, 740);
setWindowFlags(Qt::FramelessWindowHint);
framelesshelperInit();
}
Window::~Window() {}
void Window::framelesshelperInit() {
// this指的是要处理的窗体
WindowControl *control = new WindowControl(this);
control->activeWindow(this); //激活当前窗体
control->setWindowMove(true); //设置窗体可移动
control->setWindowResize(true); //设置窗体可缩放
control->setRubberBandOnMove(true); //设置橡皮筋效果-可移动
control->setRubberBandOnResize(true); //设置橡皮筋效果-可缩放
}
继承可拖动缩放的窗口:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "component/window.h"
#include <QMainWindow>
class MainWindow : public Window {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) : Window(parent) {
resize(1200, 740);
setWindowFlags(Qt::FramelessWindowHint);
// 创建自定义标题栏
QLabel *customTitleBar = new QLabel("自定义标题栏", this);
customTitleBar->setStyleSheet("background-color: blue; color: white;");
// 设置自定义标题栏
setMenuWidget(customTitleBar);
}
MainWindow::~MainWindow() {}
使用:
#include "mainwindow.h"
#include "component/window.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
控制类引用自: https://blog.csdn.net/u012959478/article/details/140658545
上述测试工程代码: https://download.csdn.net/download/qq_51355375/89783077
原文地址:https://blog.csdn.net/qq_51355375/article/details/142435365
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!