C++ QT 无边框设计之<拖拽窗体>

QT无边框设计时,要进行拖拽窗体一般有两种方法:

目录

    • 方案1:重写鼠标函数
    • 方案2:使用qt_windows.h头文件

方案1:重写鼠标函数

该方案是常规写法,
重写鼠标点击函数mousePressEvent :获取窗体坐标点、鼠标坐标点;
重写鼠标移动函数mouseMoveEvent:获取最终鼠标点,移动窗口
下面是Demo类

mainwidget .h文件:

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QMouseEvent>
#include <QPoint>

class MainWidget : public QWidget
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = nullptr);
    ~MainWidget();
    void mousePressEvent(QMouseEvent* event) override;//重写鼠标按键事件
    void mouseMoveEvent(QMouseEvent* event) override;//重写鼠标移动事件

private:
    QPoint m_diff_pos;//鼠标和窗口的相对位移
    QPoint m_window_pos;//窗口左上角点的位置
    QPoint m_mouse_pos;//鼠标绝对位置

};
#endif // MAINWIDGET_H

mainwidget .cpp文件:

#include "mainwidget.h"



MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);//设置无边框窗口

}

MainWidget::~MainWidget()
{
}

void MainWidget::mousePressEvent(QMouseEvent *event)
{
    //鼠标刚点击的时候,求出相对位置
    m_mouse_pos = event->globalPos();
    m_window_pos = this->pos();

    m_diff_pos = m_mouse_pos - m_window_pos;
}

void MainWidget::mouseMoveEvent(QMouseEvent *event)
{//鼠标移动后
    QPoint pos = event->globalPos();//获取鼠标移动后的全局位置
//    this->move(pos);//直接这么移动会产生跳跃感
    this->move(pos - m_diff_pos);//鼠标位置减去相对距离
}


测试主函数
main.cpp

#include "mainwidget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWidget w;
    w.show();
    return a.exec();
}

方案2:使用qt_windows.h头文件

该方案依赖window系统头文件和内置库,特点是代码简单

移动窗体主要在mousePressEvent函数的重构上

void CTitleBar::mousePressEvent(QMouseEvent* event)
{//菜单栏可以拖拽整个窗口,这种写法依赖Windows的头文件及库,#include <qt_windows.h>
    if(ReleaseCapture())
    {
        QWidget* pWindow = this->window();//获取主窗口
        if(pWindow->isTopLevel())
        {
            SendMessage(HWND(pWindow->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
        }
    }
}

下面是个标题类的完整写法:

ctitlebar.h文件

#ifndef CTITLEBAR_H
#define CTITLEBAR_H

#include <QObject>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QMouseEvent>
#include <qt_windows.h>//鼠标按下,拖拽窗口的写法
#pragma comment(lib,"user32.lib")






class CTitleBar:public QWidget
{
    Q_OBJECT

public:
    CTitleBar(QWidget* p = nullptr);
    ~CTitleBar();

private:
    QLabel * m_pLogo= nullptr;//标题栏的logo
    QLabel* m_ptitleTextlabel= nullptr;//标题栏名字
    QPushButton* m_pSetBtn= nullptr;//右上角设置按钮
    QPushButton* m_pMinBtn= nullptr;//右上角最小化按钮
    QPushButton* m_pMaxBtn= nullptr;//右上角最大化按钮
    QPushButton* m_pCloseBtn= nullptr;//右上角关闭按钮

private:
    void initUI();

private:
    void mousePressEvent(QMouseEvent* event) override;//鼠标点击按钮,可实现移动主窗体
    void mouseDoubleClickEvent(QMouseEvent* event) override;//鼠标双击标题的时候方法,双击的时候最大化或者回归到平常



private slots:
    void onClicked();

signals:
    void sig_close();//发射信号给主窗口,是否关闭

};

#endif // CTITLEBAR_H

ctitlebar.cpp文件

#include "ctitlebar.h"
#include<QHBoxLayout>


CTitleBar::CTitleBar(QWidget* p )
    :QWidget(p)
{
    initUI();
}

CTitleBar::~CTitleBar()
{
if(!m_pLogo)delete m_pLogo;
if(!m_ptitleTextlabel)delete m_ptitleTextlabel;
if(!m_pSetBtn)delete m_pSetBtn;
if(!m_pMinBtn)delete m_pMinBtn;
if(!m_pMaxBtn)delete m_pMaxBtn;
if(!m_pCloseBtn)delete m_pCloseBtn;

}

void CTitleBar::initUI()
{

    setAttribute(Qt::WA_StyledBackground);//禁止父窗口影响子窗口样式
    this->setFixedHeight(32+5*2);//设置标题大小
    this->setStyleSheet("background-color:rgb(44,62,80)");//标题暗黑色  54,54,54



    m_pLogo = new QLabel(this);
    m_pLogo->setFixedSize(32,32);
    m_pLogo->setStyleSheet("background-image:url(:/resources/titlebar/JX_32x32.png);border:none");

    m_ptitleTextlabel = new QLabel(this);
    m_ptitleTextlabel->setText(u8"标题名字");
    m_ptitleTextlabel->setFixedWidth(120);
    m_ptitleTextlabel->setStyleSheet("QLabel{font-family:Microsoft YaHei; \
font-size:18px; \
color:#BDC8E2;}");//background-color:rgb(54,54,54);

    m_pSetBtn = new QPushButton(this);
    m_pSetBtn->setFixedSize(32,32);
    m_pSetBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/set.svg);border:nong;} \
QPushButton:hover{background-color:rgb(99,99,99);background-image:url(:/resources/titlebar/set_hover.svg);border:none;}");

    m_pMinBtn = new QPushButton(this);
    m_pMinBtn->setFixedSize(32,32);
    m_pMinBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/min.svg);border:nong;} \
QPushButton:hover{background-color:rgb(99,99,99);background-image:url(:/resources/titlebar/min_hover.svg);border:none;}");


    m_pMaxBtn = new QPushButton(this);
    m_pMaxBtn->setFixedSize(32,32);
    m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/normal.svg);border:nong;} \
QPushButton:hover{background-color:rgb(99,99,99);background-image:url(:/resources/titlebar/normal_hover.svg);border:none;}");

    m_pCloseBtn = new QPushButton(this);
    m_pCloseBtn->setFixedSize(32,32);
    m_pCloseBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/close.svg);border:nong;} \
QPushButton:hover{background-color:rgb(232,17,35);background-image:url(:/resources/titlebar/close_hover.svg);border:none;}");

    QHBoxLayout * pHlay = new QHBoxLayout(this);
    pHlay->addWidget(m_pLogo);
    pHlay->addWidget(m_ptitleTextlabel);

    pHlay->addStretch();//增加弹簧

    pHlay->addWidget(m_pSetBtn);

    //方案1,通过QSpacerItem添加间距
//    QSpacerItem* pSpacerItem1 = new QSpacerItem(18,20,QSizePolicy::Fixed,QSizePolicy::Fixed);
//    pHlay->addSpacerItem(pSpacerItem1);//弹簧每次使用的时候都得new出来,不能重复使用,否则重复释放造成程序异常

    //方案2,通过addSpacing添加间距
    pHlay->addSpacing(10);
    pHlay->addWidget(m_pMinBtn);
    pHlay->addSpacing(10);
    pHlay->addWidget(m_pMaxBtn);
    pHlay->addSpacing(10);
    pHlay->addWidget(m_pCloseBtn);
    pHlay->setContentsMargins(5,5,5,5);

    connect(m_pMinBtn,&QPushButton::clicked,this,&CTitleBar::onClicked);
    connect(m_pMaxBtn,&QPushButton::clicked,this,&CTitleBar::onClicked);
    connect(m_pCloseBtn,&QPushButton::clicked,this,&CTitleBar::onClicked);
    connect(m_pSetBtn,&QPushButton::clicked,this,&CTitleBar::onClicked);

}

void CTitleBar::mousePressEvent(QMouseEvent* event)
{//菜单栏可以拖拽整个窗口,这种写法依赖Windows的头文件及库,#include <qt_windows.h>
    if(ReleaseCapture())
    {
        QWidget* pWindow = this->window();//获取主窗口
        if(pWindow->isTopLevel())
        {
            SendMessage(HWND(pWindow->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
        }
    }


}

void CTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    m_pMaxBtn->click();//双击的时候就是最大化按钮点击一下
}

void CTitleBar::onClicked()
{//点击右上角设置、最大化、最小化、关闭按钮的响应槽函数
    QPushButton *pButton = qobject_cast<QPushButton*> (sender());//拿到发送者
    QWidget* pWindow = this->window();//拿到父窗口指针
    if(pButton == m_pMinBtn)
    {
        pWindow->showMinimized();//父窗口最小化
    }else if(pButton == m_pMaxBtn)
    {

        if(pWindow->isMaximized())
        {//如果是最大化的时候,则恢复正常
            pWindow->showNormal();
            m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/normal.svg);border:nong;} \
        QPushButton:hover{background-color:rgb(99,99,99);background-image:url(:/resources/titlebar/normal_hover.svg);border:none;}");

        }else
        {//如果不是最大化的时候则进行最大化
            pWindow->showMaximized();//父窗口最大化
            //并且更改图标样式
            m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/resources/titlebar/max.svg);border:nong;} \
        QPushButton:hover{background-color:rgb(99,99,99);background-image:url(:/resources/titlebar/max_hover.svg);border:none;}");
        }

    }
    else if(pButton == m_pCloseBtn)
    {
        //pWindow->close();//父窗口关闭
        //增加判断提醒,是否关闭主窗口,确认关闭后再关闭
        emit sig_close();//发射关闭信号
    }
//    else if(pButton == m_pSetBtn)
//    {
//        //弹出自定义的设置窗口
//    }

}




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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【原创教程】西门子1500TCP_UDP通信说明大全(下篇)

2.3.3 TRCV故障说明 通讯无法正常连接时,ERROR引脚和STATUS引脚得状态有助于我们判断错误得原因,根据下表得提示,快速排除问题。 2.3.4 TRCV使用 点击TRCV指令得右上角蓝色图标,打开开始组态画面,按照控制要求填写 EN_R:用于激活接收的控制参数,及何时使用TRCV的接收功…

Grafana配置告警规则推送企微机器人服务器资源告警

前提 已经部署Grafana&#xff0c;并且dashboard接入数据 大屏编号地址&#xff1a;Node Exporter Full | Grafana Labs 创建企微机器人 备注&#xff1a;群里若有第三方外部人员不能创建 机器人创建完成&#xff0c;记录下来Webhook地址 Grafana配置告警消息模板 {{ define &…

RabbitMQ如何构建集群?

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ如何构建集群&#xff1f;】面试题。希望对大家有帮助&#xff1b; RabbitMQ如何构建集群&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在RabbitMQ中&#xff0c;集群&#xff08;Cluster&#x…

JDK以及JRE

目录 1.常用的快捷键操作2.重要的dos命令3.Jre&#xff08;java Runtime environment&#xff09;4.Jdk&#xff08;java development kit&#xff09;5.安装JDK6.JDK的目录7.Jdk的环境变量配置8.写第一个java程序8.1 安装UE软件8.2 写第一个HelloWorld 9.java运行机制 1.常用的…

Groovy 语法快速入门

文章目录 1. Groovy 的特点2. 基本语法2.1. 变量2.2. 字符串2.3. 条件语句 3. 集合操作3.1. 列表&#xff08;List&#xff09;3.2. 映射&#xff08;Map&#xff09; 4. 循环语句4.1. 普通循环4.2. 闭包遍历 5. 方法定义6. 闭包&#xff08;Closure&#xff09;6.1. 定义与调用…

MySQL 事务管理

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 MySQL 事务管理 收录于专栏[MySQL] 本专栏旨在分享学习MySQL的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 CURD 不加控制&#xff0…

【大模型微调学习5】-大模型微调技术LoRA

【大模型微调学习5】-大模型微调技术LoRA LoRa微调1.现有 PEFT 方法的局限与挑战2.LoRA: 小模型有大智慧 (2021)3.AdaLoRA: 自适应权重矩阵的高效微调 (2023)4.QLoRA: 高效微调量化大模型 (2023) LoRa微调 1.现有 PEFT 方法的局限与挑战 Adapter方法&#xff0c;通过增加模型深…

Windows server服务器之网络安全管理(防火墙入站规则创建)

任务14.1 Windows server 防火墙的管理 系统防火墙概述&#xff1a;无论哪一种操作系统都有自己的防火墙&#xff0c;无论是客户端OS还是服务器端的NOS都有防火墙。 winr-control----打开控制面板 上图是Windows客户端的防火墙&#xff0c;三个重点要关注的内容&#xff1b;网…

【Python】PyWebIO 初体验:用 Python 写网页

目录 前言1 使用方法1.1 安装 Pywebio1.2 输出内容1.3 输入内容 2 示例程序2.1 BMI 计算器2.2 Markdown 编辑器2.3 聊天室2.4 五子棋 前言 前两天正在逛 Github&#xff0c;偶然看到一个很有意思的项目&#xff1a;PyWebIo。 这是一个 Python 第三方库&#xff0c;可以只用 P…

四、CSS3

一、CSS3简介 1、CSS3概述 CSS3 是 CSS2 的升级版本&#xff0c;他在CSS2的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题。 CSS在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Loki 微服务模式组件介绍

目录 一、简介 二、架构图 三、组件介绍 Distributor&#xff08;分发器&#xff09; Ingester&#xff08;存储器&#xff09; Querier&#xff08;查询器&#xff09; Query Frontend&#xff08;查询前端&#xff09; Index Gateway&#xff08;索引网关&#xff09…

上海亚商投顾:创业板指缩量下跌 多只高位股午后跌停

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天震荡调整&#xff0c;创业板指领跌&#xff0c;高位股开始出现退潮&#xff0c;建设工业、星光股份、…

libnanomsg详解

libnanomsg&#xff0c;或简称为nanomsg&#xff0c;是一个高性能的消息传递库&#xff0c;它为开发者提供了简单且高效的“可扩展协议”实现。以下是对libnanomsg的详细解析&#xff1a; 一、基本概述 项目地址&#xff1a;GitCode - 全球开发者的开源社区,开源代码托管平台 …

MySQL基础大全(看这一篇足够!!!)

文章目录 前言一、初识MySQL1.1 数据库基础1.2 数据库技术构成1.2.1 数据库系统1.2.2 SQL语言1.2.3 数据库访问接口 1.3 什么是MySQL 二、数据库的基本操作2.1 数据库创建和删除2.2 数据库存储引擎2.2.1 MySQL存储引擎简介2.2.2 InnoDB存储引擎2.2.3 MyISAM存储引擎2.2.4 存储引…

geoserver 瓦片地图,tomcat和nginx实现负载均衡

在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;GeoServer作为一个强大的开源服务器&#xff0c;能够发布各种地图服务&#xff0c;包括瓦片地图服务。为了提高服务的可用性和扩展性&#xff0c;结合Tomcat和Nginx实现负载均衡成为了一个有效的解决方案。本文将详细…

Spark执行计划解析后是如何触发执行的?

在前一篇Spark SQL 执行计划解析源码分析中&#xff0c;笔者分析了Spark SQL 执行计划的解析&#xff0c;很多文章甚至Spark相关的书籍在讲完执行计划解析之后就开始进入讲解Stage切分和调度Task执行&#xff0c;每个概念之间没有强烈的关联&#xff0c;因此这中间总感觉少了点…

前端的知识(部分)

11 前端的编写步骤 第一步:在HTML的页面中声明方法 第二步:在<script>中定义一个函数,其中声明一个data来为需要的数据 赋值一个初始值 第三步:编写这个方法实现对应的功能

网络编程中的黏包和半包问题

引言 - 什么是黏包和半包&#xff1f; 在网络编程中&#xff0c;黏包和半包问题是常见的数据传输问题&#xff0c;尤其是在使用TCP协议时。Netty作为一个高性能的网络框架&#xff0c;提供了多种解决方案来处理这些问题。下面我将详细解释黏包和半包问题&#xff0c;以及Netty…

F5中获取客户端ip地址(client ip)

当F5设备对其原始设置上的所有IP地址使用NAT时&#xff0c;连接到poo成员&#xff08;nodes、backend servers&#xff09;的出站连接将是NAT IP地址。 pool 成员&#xff08;nodes、backend servers&#xff09;将无法看到真实的客户端 ip地址&#xff0c;因为看到的是F5上的…

【容器】k8s学习笔记原理详解(十万字超详细)

Pod详解 Pod介绍 Pod结构 每个Pod中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&#xff0c;数量可多可少Pause容器&#xff0c;这是每个Pod都会有的一个根容器&#xff0c;它的作用有两个&#xff1a; 可以以它为依据&am…