【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)
目录
0.背景
1.详细实现
思路简介
.h文件
.cpp文件
0.背景
Qt + Linux;项目遇到问题,解决后特此记录
项目需要,个性化的标题栏(是个widget),在传统的三个按钮(最大化、最小化、关闭)的基础上,新增了标题栏拖拽功能,有个额外要求是:拖拽标题栏的同时,让窗口变为normal状态(非最大化,也非最小化),也就是跟网页差不多的居中效果。
我希望的窗口大小效果:最大化(1920*1080);普通normal状态(1344*756);最小化(0);
我遇到的问题是:在拖拽时界面从max变为normal时,大小虽然修改为了1344*756,但如果此时我的鼠标在点击标题栏时,是在normal大小之外(如下图示意),此时变为normal后,会发现鼠标和窗体是分开的状态(按住鼠标时仍可拖动),就很怪。
排查后发现是因为【当窗口从最大化状态恢复为普通大小时,窗口的左上角位置会改变,但鼠标的全局位置保持不变】;
修改思路:在最大化状态下,记录鼠标在窗口中的相对位置比例 (xRatio
, yRatio
);恢复普通窗口后,按相同比例计算鼠标在新窗口中的位置 (newX
, newY
);计算窗口的新位置 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--
相关文章:

【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)
目录 0.背景 1.详细实现 思路简介 .h文件 .cpp文件 0.背景 Qt Linux;项目遇到问题,解决后特此记录 项目需要,个性化的标题栏(是个widget),在传统的三个按钮(最大化、最小化、关闭…...

FPGA定点和浮点数学运算-实例对比
在创建 RTL 示例时,经常使用 VHDL 2008 附带的 VHDL 包。它提供了出色的功能,可以高效地处理定点数,当然,它们也是可综合的。该包的一些优点包括: 有符号和无符号(后缀和后缀)定点向量。轻松将定…...
MySQL Binlog 数据恢复全指南
MySQL Binlog 数据恢复全指南 一、Binlog 核心概念 1. 什么是 Binlog? Binlog(二进制日志)是 MySQL 记录所有修改数据的 SQL 语句的日志文件,采用二进制格式存储。它是 MySQL 最重要的日志之一,具有三大核心功能&am…...
python版若依框架开发:后端开发规范
python版若依框架开发 从0起步,扬帆起航。 python版若依部署代码生成指南,迅速落地CURD!项目结构解析前端开发规范后端开发规范文章目录 python版若依框架开发1.启动命令2.配置⽂件3.上传配置1.启动命令 本项⽬⾃定义了两个启动命令 pyhton app.py --env=devpython app.p…...

Linux编程:2、进程基础知识
一、进程基本概念 1、进程与程序的区别 程序:静态的可执行文件(如电脑中的vs2022安装程序)。进程:程序的动态执行过程(如启动后的vs2022实例),是操作系统分配资源的单位(如 CPU 时…...
时序数据库IoTDB与EdgeX Foundry集成适配服务介绍
一、背景介绍 EdgeX Foundry:由Linux基金会运维的开放源码边缘计算软件框架,自2017年开源后广泛应用于全球各行业场景。VMware自2018年起在中国社区推广EdgeX技术,拓展生态,并持续贡献代码。IoTDB:由Apache基…...
Android第十二次面试-多线程和字符串算法总结
多线程的创建与常见使用方法 一、多线程创建方式 1. 继承Thread类 class MyThread extends Thread {Overridepublic void run() {// 线程执行逻辑System.out.println(Thread.currentThread().getName() " is running");} }// 使用 MyThread thread new …...
ES6——数组扩展之Set数组
在ES6(ECMAScript 2015)中,JavaScript的Set对象提供了一种存储任何值唯一性的方式,类似于数组但又不需要索引访问。这对于需要确保元素唯一性的场景非常有用。Set对象本身并不直接提供数组那样的方法来操作数据(例如ma…...

Cursor Rules 使用
前言 最近在使用 Cursor 进行编程辅助时,发现 AI 生成的代码风格和当前的代码风格大相径庭。而且有时它会输出很奇怪的代码,总是不符合预期。 遂引出本篇,介绍一下 Rules ,它就可以做一些规范约束之类的事情。 什么是 Cursor R…...

服务器数据恢复—服务器raid5阵列崩溃如何恢复数据?
服务器数据恢复环境&故障: 某品牌型号为X3850服务器上有一组由14块数据盘和1块热备盘组建的raid5磁盘阵列。 服务器在正常使用过程中突然崩溃,管理员查看raid5阵列故障情况的时发现磁盘阵列中有2块硬盘掉线,但是热备盘没有启用。 服务器数…...

Go语言堆内存管理
Go堆内存管理 1. Go内存模型层级结构 Golang内存管理模型与TCMalloc的设计极其相似。基本轮廓和概念也几乎相同,只是一些规则和流程存在差异。 2. Go内存管理的基本概念 Go内存管理的许多概念在TCMalloc中已经有了,含义是相同的,只是名字有…...

【DAY41】简单CNN
内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点: 数据增强卷积神经网络定义的写法batch归一化:调整一个批次的分布,常用与图像数据特征图:只有卷积操作输出的才叫特征图调度器:直接修改基础学习率 卷积操作常…...
Rust 学习笔记:使用自定义命令扩展 Cargo
Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Cargo 支持通过 $PATH 中的 cargo-something 形式的二进制文件拓展子命令,而无需修改 Cargo 本身。 …...
LeetCode 08.06 面试题 汉诺塔 (Java)
经典递归解决汉诺塔问题:清晰的三步移动策略 问题描述 在汉诺塔问题中,有 3 根柱子和 N 个大小不同的盘子,盘子初始按升序堆叠在第一根柱子上(最小的在顶部)。目标是将所有盘子移动到第三根柱子上,并满足…...

使用MinIO搭建自己的分布式文件存储
目录 引言: 一.什么是 MinIO ? 二.MinIO 的安装与部署: 三.Spring Cloud 集成 MinIO: 1.前提准备: (1)安装依赖: (2)配置MinIO连接: &…...
单元测试与QTestLib框架使用
一.单元测试的意义 在软件开发中,单元测试是指对软件中最小可测试单元(通常是函数、类的方法)进行隔离的、可重复的验证。进行单元测试具有以下重要意义: 1.提升代码质量与可靠性: 早期错误检测: 在开发…...
java面试场景题:QPS 短链系统怎么设计
以下是对文章的润色版本: 这道场景设计题,初看似乎业务简单,实则覆盖的知识点极为丰富: 高并发与高性能分布式 ID 生成机制;Redis Bloom Filter——高并发、低内存损耗的过滤组件知识;分库、分表海量数据存…...
java面试场景提题:
以下是润色后的文章,结构更清晰,语言更流畅,同时保留了技术细节: 应对百倍QPS增长的系统设计策略 整体架构设计思路 面对突发性百倍QPS增长,系统设计需从硬件、架构、代码、数据四个维度协同优化: 硬件层…...

K7 系列各种PCIE IP核的对比
上面三个IP 有什么区别,什么时候用呢? 7 series Integrated Block for PCIE AXI Memory Mapped to PCI Express DMA subsystem for PCI Express 特点 这是 Kintex-7 内置的 硬核 PCIe 模块。部分事务层也集成在里面,使用标准的PCIE 基本没…...

natapp 内网穿透失败
连不上网络错误调试排查详解 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 如何将DNS服务器修改为114.114.114.114_百度知道 连不上/错误信息等问题解决汇总 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 nslookup auth.natapp.cnping auth.natapp.cn...

深入解析CI/CD开发流程
引言:主播最近实习的时候发现部门里面使用的是CI/CD这样的集成开发部署,但是自己不是太了解什么意思,所以就自己查了一下ci/cd相关的资料,整理分享了一下 一、CI/CD CI/CD是持续集成和持续交付部署的缩写,旨在简化并…...

Docke启动Ktransformers部署Qwen3MOE模型实战与性能测试
docker运行Ktransformers部署Qwen3MOE模型实战及 性能测试 最开始拉取ktransformers:v0.3.1-AVX512版本,发现无论如何都启动不了大模型,后来发现是cpu不支持avx512指令集。 由于本地cpu不支持amx指令集,因此下载avx2版本镜像: …...

应用分享 | 精准生成和时序控制!AWG在确定性三量子比特纠缠光子源中的应用
在量子技术飞速发展的今天,实现高效稳定的量子态操控是推动量子计算、量子通信等领域迈向实用化的关键。任意波形发生器(AWG)作为精准信号控制的核心设备,在量子实验中发挥着不可或缺的作用。丹麦哥本哈根大学的研究团队基于单个量…...

相机--相机标定实操
教程 camera_calibration移动画面示例 usb_cam使用介绍和下载 标定流程 单目相机标定 我使用的是USB相机,所以直接使用ros的usb_cam功能包驱动相机闭关获取实时图像,然后用ros的camera_calibration标定相机。 1,下载usb_cam和camera_calibration: …...
深入理解汇编语言中的顺序与分支结构
本文将结合Visual Studio环境配置、顺序结构编程和分支结构实现,全面解析汇编语言中的核心编程概念。通过实际案例演示无符号/有符号数处理、分段函数实现和逻辑表达式短路计算等关键技术。 一、汇编环境配置回顾(Win32MASM) 在Visual Studi…...

DAY43 复习日
浙大疏锦行-CSDN博客 kaggle找到一个图像数据集,用cnn网络进行训练并且用grad-cam做可视化 进阶:把项目拆分成多个文件 src/config.py: 用于存放项目配置,例如文件路径、学习率、批次大小等。 # src/config.py# Paths DATA_DIR "data…...
【仿生机器人】仿生机器人智能架构:从感知到个性的完整设计
仿生机器人智能架构:从感知到个性的完整设计 仿生机器人不仅需要模拟人类的外表,更需要具备类人的认知、情感和个性特征。本研究提出了一个综合性的软件架构,实现了从环境感知到情感生成、从实时交互到人格塑造的完整智能系统。该架构突破了…...
【业务框架】3C-相机-Cinemachine
概述 插件,做相机需求,等于相机老师傅多年经验总结的工具 Feature Transform:略Control Camera:控制相机参数Noise:增加随机性Blend:CameraBrain的混合列表指定一个虚拟相机到另一个相机的过渡ÿ…...

【Auto.js例程】华为备忘录导出到其他手机
目录 问题描述方法步骤1.安装下载Visual Studio Code2.安装扩展3.找到Auto.js插件,并安装插件4.启动服务器5.连接手机6.撰写脚本并运行7.本文实现功能的代码8.启动手机上的换机软件 问题描述 问题背景:华为手机换成一加手机,华为备忘录无法批…...

单片机的低功耗模式
什么是低功耗? STM32的低功耗(low power mode)特性是其嵌入式处理器系列的一个重要优势,特别适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。 在很多应用场合中都对电子设备的…...