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

news2025/6/9 1:40:52

目录

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_OBJECT

public:
    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.coloradmin.cn/o/2404815.html

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

相关文章

FPGA定点和浮点数学运算-实例对比

在创建 RTL 示例时&#xff0c;经常使用 VHDL 2008 附带的 VHDL 包。它提供了出色的功能&#xff0c;可以高效地处理定点数&#xff0c;当然&#xff0c;它们也是可综合的。该包的一些优点包括&#xff1a; 有符号和无符号&#xff08;后缀和后缀&#xff09;定点向量。轻松将定…

Linux编程:2、进程基础知识

一、进程基本概念 1、进程与程序的区别 程序&#xff1a;静态的可执行文件&#xff08;如电脑中的vs2022安装程序&#xff09;。进程&#xff1a;程序的动态执行过程&#xff08;如启动后的vs2022实例&#xff09;&#xff0c;是操作系统分配资源的单位&#xff08;如 CPU 时…

Cursor Rules 使用

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

服务器数据恢复—服务器raid5阵列崩溃如何恢复数据?

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

Go语言堆内存管理

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

【DAY41】简单CNN

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点&#xff1a; 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常…

使用MinIO搭建自己的分布式文件存储

目录 引言&#xff1a; 一.什么是 MinIO &#xff1f; 二.MinIO 的安装与部署&#xff1a; 三.Spring Cloud 集成 MinIO&#xff1a; 1.前提准备&#xff1a; &#xff08;1&#xff09;安装依赖&#xff1a; &#xff08;2&#xff09;配置MinIO连接&#xff1a; &…

K7 系列各种PCIE IP核的对比

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

natapp 内网穿透失败

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

深入解析CI/CD开发流程

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

Docke启动Ktransformers部署Qwen3MOE模型实战与性能测试

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

应用分享 | 精准生成和时序控制!AWG在确定性三量子比特纠缠光子源中的应用

在量子技术飞速发展的今天&#xff0c;实现高效稳定的量子态操控是推动量子计算、量子通信等领域迈向实用化的关键。任意波形发生器&#xff08;AWG&#xff09;作为精准信号控制的核心设备&#xff0c;在量子实验中发挥着不可或缺的作用。丹麦哥本哈根大学的研究团队基于单个量…

相机--相机标定实操

教程 camera_calibration移动画面示例 usb_cam使用介绍和下载 标定流程 单目相机标定 我使用的是USB相机&#xff0c;所以直接使用ros的usb_cam功能包驱动相机闭关获取实时图像&#xff0c;然后用ros的camera_calibration标定相机。 1,下载usb_cam和camera_calibration: …

DAY43 复习日

浙大疏锦行-CSDN博客 kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;把项目拆分成多个文件 src/config.py: 用于存放项目配置&#xff0c;例如文件路径、学习率、批次大小等。 # src/config.py# Paths DATA_DIR "data…

【Auto.js例程】华为备忘录导出到其他手机

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

单片机的低功耗模式

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

架构师级考验!飞算 JavaAI 炫技赛:AI 辅助编程解决老项目难题

当十年前 Hibernate 框架的 N1 查询隐患在深夜持续困扰排查&#xff0c;当 SpringMVC 控制器中错综复杂的业务逻辑在跨语言迁移时令人抓狂&#xff0c;企业数字化进程中的百万行老系统&#xff0c;已然成为暗藏危机的 “技术债冰山”。而此刻&#xff0c;飞算科技全新发布的 Ja…

手机端抓包大麦网抢票协议:实现自动抢票与支付

&#x1f680; 手机端抓包大麦网抢票协议&#xff1a;实现自动抢票与支付 &#x1f680; &#x1f525; 你是否还在为抢不到热门演出票而烦恼&#xff1f;本文将教你如何通过抓包技术获取大麦网抢票协议&#xff0c;并编写脚本实现自动化抢票与支付&#xff01;&#x1f525; …

[TIP] Ubuntu 22.04 配置多个版本的 GCC 环境

问题背景 在 Ubuntu 22.04 中安装 VMware 虚拟机时&#xff0c;提示缺少 VMMON 和 VMNET 模块 编译这两个模块需要 GCC 的版本大于 12.3.0&#xff0c;而 Ubuntu 22.04 自带的 GCC 版本为 11.4.0 因此需要安装对应的 GCC 版本&#xff0c;但为了不影响其他程序&#xff0c;需…

如何思考?分析篇

现代人每天刷 100 条信息&#xff0c;却难静下心读 10 页书。 前言&#xff1a; 我一直把思考当作一件生活中和工作中最为重要的事情。但是我发现当我想写一篇跟思考有关的文章时&#xff0c;却难以下手。因为思考是一件非常复杂的事情&#xff0c;用文字描述十分的困难。 读书…