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

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.xdnf.cn/news/588277.html

相关文章:

  • 吃透 Golang 基础:数据结构之切片
  • 实现了TCP的单向通信
  • 【数据库】-2 mysql基础语句(上)
  • 旋转编码器计次 红外对射传感器计次小实验及其相关库函数详解 (江协科技)
  • 第四章:YOLOv11 实战应用与开发指南
  • LeetCode 404.左叶子之和的迭代求解:栈结构与父节点定位的深度解析
  • 力扣.H指数力扣.字母异位词力扣.289生命游戏力扣452.用最小数量的箭引爆气球力扣.86分隔链表力扣.轮转数组
  • 高等数学-常微分方程
  • 国产三维CAD皇冠CAD(CrownCAD)建模教程:交流发电机
  • 推荐一个Excel与实体映射导入导出的C#开源库
  • 手写简单的tomcat
  • (泛函分析)线性算子连续必有界的证明
  • GraphRAG使用
  • 动态规划(七)——子数组系列(求和问题)
  • labview实现将百分制分数转换为等级制分数
  • Vue 3 官方 Hooks 的用法与实现原理
  • ai外呼平台:AnKo打造高效多模型服务体验!
  • labview实现LED流水灯的第二种方法
  • 每日算法刷题计划day13 5.22:leetcode不定长滑动窗口最短/最小1道题+求子数组个数越长越合法2道题,用时1h
  • 学习vue3:跨组件通信(provide+inject)
  • vscode include总是报错
  • Ubuntu24.04 LTS安装java8、mysql8.0
  • 【VScode】python初学者的有力工具
  • Labview使用报表工具
  • linux二进制安装mysql:
  • 遥控器处理器与光纤通信技术解析
  • 深入理解指针part1
  • 【Django ORM】三万字了解Django ORM的基本概念和基本使用
  • 并发编程之并发协同工具类
  • ollama+open-webui搭建可视化大模型聊天