当前位置: 首页 > article >正文

Qt无边框界面添加鼠标事件

在Qt中实现无边框窗口的鼠标事件处理,主要涉及窗口拖动和调整大小功能。以下是分步实现的代码示例:

1. 创建无边框窗口

首先,创建一个继承自QWidget的自定义窗口类,并设置无边框标志:

#include <QWidget>
#include <QMouseEvent>class FramelessWindow : public QWidget {Q_OBJECTpublic:FramelessWindow(QWidget *parent = nullptr) : QWidget(parent) {setWindowFlags(Qt::FramelessWindowHint);setMouseTracking(true); // 启用鼠标追踪}
};

2. 处理窗口拖动

在标题栏区域按下鼠标左键时拖动窗口:

protected:void mousePressEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton) {if (isInDragRegion(event->pos())) {m_dragging = true;m_dragStartPos = event->globalPos();m_windowPos = pos();}}QWidget::mousePressEvent(event);}void mouseMoveEvent(QMouseEvent *event) override {if (m_dragging) {QPoint delta = event->globalPos() - m_dragStartPos;move(m_windowPos + delta);}QWidget::mouseMoveEvent(event);}void mouseReleaseEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton) {m_dragging = false;}QWidget::mouseReleaseEvent(event);}private:bool m_dragging = false;QPoint m_dragStartPos;QPoint m_windowPos;bool isInDragRegion(const QPoint &pos) const {// 假设标题栏高度为30像素return pos.y() < 30;}

3. 实现调整窗口大小

检测边缘并调整窗口大小:

protected:enum ResizeDirection { None, Left, Right, Top, Bottom, TopLeft, TopRight, BottomLeft, BottomRight };ResizeDirection m_resizeDir = None;void checkResizeRegion(const QPoint &pos) {const int borderWidth = 5;QRect rect = this->rect();bool left = pos.x() <= borderWidth;bool right = pos.x() >= rect.width() - borderWidth;bool top = pos.y() <= borderWidth;bool bottom = pos.y() >= rect.height() - borderWidth;if (left && top) m_resizeDir = TopLeft;else if (right && top) m_resizeDir = TopRight;else if (left && bottom) m_resizeDir = BottomLeft;else if (right && bottom) m_resizeDir = BottomRight;else if (left) m_resizeDir = Left;else if (right) m_resizeDir = Right;else if (top) m_resizeDir = Top;else if (bottom) m_resizeDir = Bottom;else m_resizeDir = None;}void mousePressEvent(QMouseEvent *event) override {// ... 原有拖动处理 ...checkResizeRegion(event->pos());if (m_resizeDir != None) {m_resizing = true;m_resizeStartPos = event->globalPos();m_initialGeometry = geometry();}}void handleResize(const QPoint &globalPos) {QRect newGeometry = m_initialGeometry;QPoint delta = globalPos - m_resizeStartPos;switch (m_resizeDir) {case Left:newGeometry.setLeft(newGeometry.left() + delta.x());break;case Right:newGeometry.setRight(newGeometry.right() + delta.x());break;case Top:newGeometry.setTop(newGeometry.top() + delta.y());break;case Bottom:newGeometry.setBottom(newGeometry.bottom() + delta.y());break;case TopLeft:newGeometry.setTopLeft(newGeometry.topLeft() + delta);break;case TopRight:newGeometry.setTopRight(newGeometry.topRight() + delta);break;case BottomLeft:newGeometry.setBottomLeft(newGeometry.bottomLeft() + delta);break;case BottomRight:newGeometry.setBottomRight(newGeometry.bottomRight() + delta);break;}// 限制最小尺寸newGeometry = newGeometry.normalized().adjusted(0, 0, 1, 1);if (newGeometry.width() < minimumWidth() || newGeometry.height() < minimumHeight())return;setGeometry(newGeometry);}

4. 更新光标形状

根据鼠标位置调整光标:

    void updateCursorShape(const QPoint &pos) {checkResizeRegion(pos);switch (m_resizeDir) {case Left:case Right:setCursor(Qt::SizeHorCursor);break;case Top:case Bottom:setCursor(Qt::SizeVerCursor);break;case TopLeft:case BottomRight:setCursor(Qt::SizeFDiagCursor);break;case TopRight:case BottomLeft:setCursor(Qt::SizeBDiagCursor);break;default:unsetCursor();}}

5. 双击最大化

双击标题栏切换最大化:

    void mouseDoubleClickEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton && isInDragRegion(event->pos())) {toggleMaximize();}QWidget::mouseDoubleClickEvent(event);}void toggleMaximize() {isMaximized() ? showNormal() : showMaximized();}

完整示例代码

整合以上代码,完整的无边框窗口类如下:

#include <QWidget>
#include <QMouseEvent>
#include <QCursor>class FramelessWindow : public QWidget {Q_OBJECTpublic:FramelessWindow(QWidget *parent = nullptr) : QWidget(parent) {setWindowFlags(Qt::FramelessWindowHint);setMouseTracking(true);}protected:void mousePressEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton) {if (isInDragRegion(event->pos())) {m_dragging = true;m_dragStartPos = event->globalPos();m_windowPos = pos();} else {checkResizeRegion(event->pos());if (m_resizeDir != None) {m_resizing = true;m_resizeStartPos = event->globalPos();m_initialGeometry = geometry();}}}QWidget::mousePressEvent(event);}void mouseMoveEvent(QMouseEvent *event) override {if (!m_resizing && !m_dragging)updateCursorShape(event->pos());if (m_dragging) {QPoint delta = event->globalPos() - m_dragStartPos;move(m_windowPos + delta);} else if (m_resizing) {handleResize(event->globalPos());}QWidget::mouseMoveEvent(event);}void mouseReleaseEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton) {m_dragging = false;m_resizing = false;m_resizeDir = None;unsetCursor();}QWidget::mouseReleaseEvent(event);}void mouseDoubleClickEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton && isInDragRegion(event->pos())) {toggleMaximize();}QWidget::mouseDoubleClickEvent(event);}private:bool m_dragging = false;QPoint m_dragStartPos;QPoint m_windowPos;bool m_resizing = false;QPoint m_resizeStartPos;QRect m_initialGeometry;enum ResizeDirection {None, Left, Right, Top, Bottom,TopLeft, TopRight, BottomLeft, BottomRight};ResizeDirection m_resizeDir = None;bool isInDragRegion(const QPoint &pos) const {return pos.y() < 30; // 标题栏区域高度}void checkResizeRegion(const QPoint &pos) {const int border = 5;bool left = pos.x() <= border;bool right = pos.x() >= width() - border;bool top = pos.y() <= border;bool bottom = pos.y() >= height() - border;if (left && top) m_resizeDir = TopLeft;else if (right && top) m_resizeDir = TopRight;else if (left && bottom) m_resizeDir = BottomLeft;else if (right && bottom) m_resizeDir = BottomRight;else if (left) m_resizeDir = Left;else if (right) m_resizeDir = Right;else if (top) m_resizeDir = Top;else if (bottom) m_resizeDir = Bottom;else m_resizeDir = None;}void updateCursorShape(const QPoint &pos) {checkResizeRegion(pos);switch (m_resizeDir) {case Left: case Right:setCursor(Qt::SizeHorCursor); break;case Top: case Bottom:setCursor(Qt::SizeVerCursor); break;case TopLeft: case BottomRight:setCursor(Qt::SizeFDiagCursor); break;case TopRight: case BottomLeft:setCursor(Qt::SizeBDiagCursor); break;default:unsetCursor();}}void handleResize(const QPoint &globalPos) {QRect newGeo = m_initialGeometry;int deltaX = globalPos.x() - m_resizeStartPos.x();int deltaY = globalPos.y() - m_resizeStartPos.y();switch (m_resizeDir) {case Left:newGeo.setLeft(newGeo.left() + deltaX);break;case Right:newGeo.setRight(newGeo.right() + deltaX);break;case Top:newGeo.setTop(newGeo.top() + deltaY);break;case Bottom:newGeo.setBottom(newGeo.bottom() + deltaY);break;case TopLeft:newGeo.setTopLeft(newGeo.topLeft() + QPoint(deltaX, deltaY));break;case TopRight:newGeo.setTopRight(newGeo.topRight() + QPoint(deltaX, deltaY));break;case BottomLeft:newGeo.setBottomLeft(newGeo.bottomLeft() + QPoint(deltaX, deltaY));break;case BottomRight:newGeo.setBottomRight(newGeo.bottomRight() + QPoint(deltaX, deltaY));break;}if (newGeo.width() < minimumWidth() || newGeo.height() < minimumHeight())return;setGeometry(newGeo);}void toggleMaximize() {isMaximized() ? showNormal() : showMaximized();}
};

注意事项

  • 边缘检测:调整边缘检测的阈值(如border = 5)以适应不同需求。
  • 最小尺寸:确保窗口不会调整到小于minimumWidthminimumHeight
  • 最大化处理:在最大化状态下可能需要禁用调整大小或特殊处理拖动行为。
  • 性能优化:避免频繁的几何计算影响性能。

通过以上步骤,即可在Qt的无边框窗口中实现完整的鼠标交互功能。

http://www.lryc.cn/news/2384178.html

相关文章:

  • 企业级爬虫进阶开发指南
  • Ubuntu ping网络没有问题,但是浏览器无法访问到网络
  • 网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】
  • 数据结构实验10.1:内部排序的基本运算
  • C#:多线程
  • 基于Zynq SDK的LWIP UDP组播开发实战指南
  • c#将json字符串转换为对象数组
  • 机器学习在智能水泥基复合材料中的应用与实践
  • wps编辑技巧
  • 开放世界RPG:无缝地图与动态任务的拓扑学架构
  • 【图像处理入门】1. 数字图像的本质:从像素到色彩模型
  • (已解决:基于WSL2技术)Windows11家庭中文版(win11家庭版)如何配置和使用Docker Desktop
  • Ubuntu20.04部署KVM
  • OpenCV CUDA 模块图像过滤------创建一个高斯滤波器函数createGaussianFilter()
  • 计算机视觉与深度学习 | matlab实现ARIMA-WOA-CNN-LSTM时间序列预测(完整源码和数据)
  • 可视化图解算法43:数组中的逆序对
  • 【Python】使用Python实现调用API获取图片存储到本地
  • 腾讯2025年校招笔试真题手撕(一)
  • Vue3 与 Vue2 区别
  • java集合详细讲解
  • 嵌入式学习笔记 - STM32 U(S)ART 模块HAL 库函数总结
  • 【VLNs篇】04:SayNav-为新环境中的动态规划到导航进行大型语言模型的基础构建
  • MySQL中添加一个具有创建数据库权限的用户
  • oracle使用SPM控制执行计划
  • [Java实战]Spring Boot整合Seata:分布式事务一致性解决方案(三十一)
  • Openwrt下使用ffmpeg配合自建RTSP服务器实现推流
  • MySQL 索引的增删改查
  • MySQL Host 被封锁解决方案(全版本适用 + Java 后端优化)
  • wifi 如果检查失败,UI 就会出现延迟或缺失打勾的现象。
  • 点云(point cloud):自动驾驶的“三维扫描图“