【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)

目录

0.背景

1.详细实现

思路简介

.h文件

.cpp文件


0.背景

Qt + Linux;项目遇到问题,解决后特此记录

项目需要,个性化的标题栏(是个widget),在传统的三个按钮(最大化、最小化、关闭)的基础上,新增了标题栏拖拽功能,有个额外要求是:拖拽标题栏的同时,让窗口变为normal状态(非最大化,也非最小化),也就是跟网页差不多的居中效果。

我希望的窗口大小效果:最大化(1920*1080);普通normal状态(1344*756);最小化(0);

我遇到的问题是:在拖拽时界面从max变为normal时,大小虽然修改为了1344*756,但如果此时我的鼠标在点击标题栏时,是在normal大小之外(如下图示意),此时变为normal后,会发现鼠标和窗体是分开的状态(按住鼠标时仍可拖动),就很怪。

排查后发现是因为【当窗口从最大化状态恢复为普通大小时,窗口的左上角位置会改变,但鼠标的全局位置保持不变】;

修改思路:在最大化状态下,记录鼠标在窗口中的相对位置比例 (xRatioyRatio);恢复普通窗口后,按相同比例计算鼠标在新窗口中的位置 (newXnewY);计算窗口的新位置 newWindowPos,使得鼠标在屏幕中的绝对位置保持不变。

修改后normal时鼠标状态如下:

修改后可以保证鼠标无论点击标题栏的何处,都是可以平滑的点击、移动,鼠标不会有点击后出现在normal窗体外的效果。详细代码见下文。

1.详细实现

思路简介

就是实现3个按钮release的事件;然后重写3个protectes函数;

.h文件

#ifndef BCI_SEEG_STEER_NEW_WIDGET_H
#define BCI_SEEG_STEER_NEW_WIDGET_H#include <QWidget>
#include <QMouseEvent>
#include <QDesktopWidget>namespace Ui {
class BCI_SEEG_Steer_New_Widget;
}class BCI_SEEG_Steer_New_Widget : public QWidget
{Q_OBJECTpublic:explicit BCI_SEEG_Steer_New_Widget(QWidget *parent = nullptr);~BCI_SEEG_Steer_New_Widget();protected:void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;private slots:void on_btn_mini_released();void on_btn_max_released();void on_btn_close_released();private:Ui::BCI_SEEG_Steer_New_Widget *ui;bool m_isDragging = false;///<拖动标题栏QPoint m_dragPosition;
};#endif // BCI_SEEG_STEER_NEW_WIDGET_H

.cpp文件

#include "BCI_SEEG_Steer_New_Widget.h"
#include "ui_BCI_SEEG_Steer_New_Widget.h"BCI_SEEG_Steer_New_Widget::BCI_SEEG_Steer_New_Widget(QWidget *parent) :QWidget(parent),ui(new Ui::BCI_SEEG_Steer_New_Widget)
{ui->setupUi(this);setWindowFlags(Qt::FramelessWindowHint);showMaximized();//初始化时先告诉widget,是最大化的状态
}BCI_SEEG_Steer_New_Widget::~BCI_SEEG_Steer_New_Widget()
{delete ui;
}//重写鼠标按下事件
void BCI_SEEG_Steer_New_Widget::mousePressEvent(QMouseEvent *event)
{///< 判断是否点击了自定义标题栏,我的ui中标题栏名字叫【title_frame】,使用时要改成你的控件,你希望鼠标在哪个区域按下时,触发可移动的事件,就改成哪个控件的名字if (event->button() == Qt::LeftButton &&childAt(event->pos()) && childAt(event->pos())->objectName() == "title_frame"){if (isMaximized()) {// 保存鼠标在屏幕中的绝对位置QPoint globalMousePos = event->globalPos();// 保存鼠标在最大化窗口中的相对位置比例qreal xRatio = (qreal)event->pos().x() / width();qreal yRatio = (qreal)event->pos().y() / height();// 恢复普通窗口并调整大小showNormal();resize(1344, 756);ui->btn_max->setIcon(QIcon(":/img/maximize windows.svg"));// 计算鼠标在新窗口中的预期位置int newX = xRatio * width();int newY = yRatio * height();// 计算窗口应该移动到的位置,使鼠标保持在同一屏幕位置QPoint newWindowPos = globalMousePos - QPoint(newX, newY);// 确保窗口不会移出屏幕QRect screenGeometry = QApplication::desktop()->availableGeometry(this);newWindowPos.setX(qMax(screenGeometry.left(),qMin(newWindowPos.x(),screenGeometry.right() - width())));newWindowPos.setY(qMax(screenGeometry.top(),qMin(newWindowPos.y(),screenGeometry.bottom() - height())));// 移动窗口到新位置move(newWindowPos);// 更新拖动位置为鼠标在窗口中的新位置m_dragPosition = QPoint(newX, newY);}else {// 普通窗口状态下直接计算偏移m_dragPosition = event->globalPos() - frameGeometry().topLeft();}m_isDragging = true;event->accept();return;}QWidget::mousePressEvent(event);
}//重写鼠标移动事件
void BCI_SEEG_Steer_New_Widget::mouseMoveEvent(QMouseEvent *event)
{///< 处理窗口拖动if (m_isDragging && (event->buttons() & Qt::LeftButton)) {move(event->globalPos() - m_dragPosition);event->accept();return;}QWidget::mouseMoveEvent(event);
}//重写鼠标释放事件
void BCI_SEEG_Steer_New_Widget::mouseReleaseEvent(QMouseEvent *event)
{Q_UNUSED(event);m_isDragging = false;
}//点击最小化按钮
void BCI_SEEG_Steer_New_Widget::on_btn_mini_released()
{showMinimized();
}//点击最大化/normal按钮
void BCI_SEEG_Steer_New_Widget::on_btn_max_released()
{if (isMaximized()) {showNormal();this->resize(1344, 756);ui->btn_max->setIcon(QIcon(":/img/maximize windows.svg"));} else {showMaximized();this->resize(1920, 1080);ui->btn_max->setIcon(QIcon(":/img/restored windows.svg"));}
}//点击关闭按钮
void BCI_SEEG_Steer_New_Widget::on_btn_close_released()
{this->close();
}

.ui文件

ui界面代码我就不附上了,相关的只有标题栏和3个按钮而已,布局如下

--END--

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/83836.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何用 pnpm patch 给 element-plus 打补丁修复线上 bug(以 2.4.4 修复 PR#15197 为例)

背景 在实际项目开发中&#xff0c;依赖的三方库&#xff08;如 element-plus&#xff09;难免会遇到 bug。有时候官方虽然已经修复&#xff0c;但新版本升级成本高&#xff0c;或者有兼容性风险。这时&#xff0c;给依赖打补丁是最优雅的解决方案之一。 本文以 element-plus…

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…

优化电脑的磁盘和驱动器提高电脑性能和延长硬盘寿命?

磁盘优化 磁盘清理&#xff1a; 使用系统自带的磁盘清理工具&#xff08;如Windows的“磁盘清理”&#xff09;删除不必要的文件。清空回收站。删除临时文件和缓存。 磁盘碎片整理&#xff08;针对机械硬盘&#xff09;&#xff1a; 定期进行磁盘碎片整理&#xff0c;以提高文…

EDA断供危机下的冷思考:中国芯片设计软件的破局之道优雅草卓伊凡

EDA断供危机下的冷思考&#xff1a;中国芯片设计软件的破局之道优雅草卓伊凡 一、EDA是什么&#xff1f;芯片行业的”隐形基石” 1.1 EDA技术解析 EDA&#xff08;Electronic Design Automation&#xff0c;电子设计自动化&#xff09;是用于设计和验证集成电路的软件工具链…

Jpackage

简介 jpackage - 用于打包自包含 Java 应用程序的工具&#xff0c;是 JDK 14 引入的一个工具。 该工具将 Java 应用程序和 Java 运行时映像作为输入&#xff0c;并生成包含所有必要依赖项的 Java 应用程序映像。它将能够生成特定于平台的格式的本机包&#xff0c;例如包括打包 …

CRM管理软件的数据可视化功能使用技巧:让数据驱动决策

在当今数据驱动的商业环境中&#xff0c;CRM管理系统的数据可视化功能已成为企业优化客户管理、提升销售效率的核心工具。据企销客研究显示&#xff0c;具备优秀可视化能力的CRM系统&#xff0c;用户决策效率可提升47%。本文将深入解析如何通过数据可视化功能最大化CRM管理软件…

智慧充电:新能源汽车智慧充电桩的发展前景受哪些因素影响?

全球能源结构转型与碳中和目标的推进&#xff0c;新能源汽车产业迎来爆发式增长&#xff0c;而智慧充电桩作为其核心基础设施&#xff0c;发展前景备受关注。智慧充电不仅关乎用户充电体验的优化&#xff0c;更是电网平衡、能源效率提升的关键环节。 然而&#xff0c;其发展并…

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…

多模态大语言模型arxiv论文略读(105)

UnifiedMLLM: Enabling Unified Representation for Multi-modal Multi-tasks With Large Language Model ➡️ 论文标题&#xff1a;UnifiedMLLM: Enabling Unified Representation for Multi-modal Multi-tasks With Large Language Model ➡️ 论文作者&#xff1a;Zhaowei…

SQLServer中的存储过程与事务

一、存储过程的概念 1. 定义 存储过程&#xff08;Stored Procedure&#xff09;是一组预编译的 SQL 语句的集合&#xff0c;它们被存储在数据库中&#xff0c;可以通过指定存储过程的名称并执行来调用它们。存储过程可以接受输入参数、输出参数&#xff0c;并且可以返回执行…

使用UDP连接ssh

使用UDP连接ssh mosh简介两端安装moshWindows安装mosh 放行端口使用mosh登录Linuxdebug mosh简介 Mosh最大的特点是基于UDP方式传输&#xff0c;支持在服务端创建一个临时的Key供客户端一次性连接&#xff0c;退出后失效&#xff1b;也支持通过SSH的配置进行认证&#xff0c;但…

软件功能模块归属论证方法

文章目录 **一、核心设计原则****二、论证方法****三、常见决策模式****四、验证方法****五、反模式警示****总结** 在讨论软件功能点应该归属哪些模块时&#xff0c;并没有放之四海而皆准的固定方法&#xff0c;但可以通过系统化的论证和设计原则来做出合理决策。以下是常见的…

ServBay 1.13.0 更新,新增第三方反向代理/内网穿透

ServBay 作为一款简化本地开发环境搭建与管理的强大工具&#xff0c;致力于打造一个开箱即用、稳定可靠的本地开发平台&#xff0c;让用户专注于代码编写&#xff0c;提升开发效率。 ServBay 1.13.0 正式发布&#xff01;本次更新聚焦于提升本地开发项目的外部可访问性、增强国…

如何利用乐维网管进行IP管理

IP管理是网络管理中的关键环节&#xff0c;对于保障网络的正常运行、提升资源利用效率以及保障网络安全等方面都具有不可忽视的重要性。乐维网管在IP管理方面具有多种实用功能&#xff0c;以下从IP规划与分配、IP状态监测、IP冲突处理、IP审计与报表生成四个方面&#xff0c;介…

Go语言学习-->go的跨平台编译

Go语言学习–&#xff1e;go的跨平台编译 默认我们go build的可执行文件都是当前操作系统可执行的文件&#xff0c;Go语言支持跨平台编译——在当前平台下编译其他平台的可执行文件。 eg&#xff1a;在windows界面的代码&#xff0c;编译完成后在linux上面运行 实现方式&#…

SpringBoot自动配置原理深度解析

一、引言 SpringBoot的"约定优于配置"理念极大地简化了Spring应用的开发流程&#xff0c;而其核心魔法就是自动配置(Auto-Configuration)。本文将深入剖析自动配置的实现原理&#xff0c;帮助开发者更好地理解和定制SpringBoot应用。 二、自动配置核心机制 1. Ena…

使用阿里云百炼embeddings+langchain+Milvus实现简单RAG

使用阿里云百炼embeddingslangchainMilvus实现简单RAG 注意测试时&#xff0c;替换其中的key、文档等 import os from langchain_community.embeddings import DashScopeEmbeddings from langchain_community.vectorstores import Milvus from langchain_text_splitters impor…

事件监听 ——CAD C#二次开发

一、AutoCAD .NET API 事件机制 1. 事件监听核心 - Database.ModifyObjects 事件 当数据库中的实体&#xff08;如图形对象&#xff09;发生修改时触发&#xff0c;包括&#xff1a; - 几何属性变更&#xff08;移动、缩放、旋转&#xff09;。 - 非几何属性变更&#xff08…

动量及在机器人控制中的应用

动量是物理学中的一个基本概念&#xff0c;在机器人学中也有重要应用。以下是详细解释&#xff1a; 1. 动量的基本定义 动量&#xff08;Momentum&#xff09;是描述物体运动状态的物理量&#xff0c;定义为&#xff1a; 线性动量&#xff1a;$ p mv $ $ m $ 为质量&#xf…

LeetCode 2434.使用机器人打印字典序最小的字符串:贪心(栈)——清晰题解

【LetMeFly】2434.使用机器人打印字典序最小的字符串&#xff1a;贪心(栈)——清晰题解 力扣题目链接&#xff1a;https://leetcode.cn/problems/using-a-robot-to-print-the-lexicographically-smallest-string/ 给你一个字符串 s 和一个机器人&#xff0c;机器人当前有一个…