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

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

目录

方案1:重写鼠标函数

该方案是常规写法,

重写鼠标点击函数mousePressEvent :获取窗体坐标点、鼠标坐标点;

重写鼠标移动函数mouseMoveEvent:获取最终鼠标点,移动窗口

下面是Demo类

mainwidget .h文件:

cpp 复制代码
#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文件:

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

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函数的重构上

cpp 复制代码
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文件

cpp 复制代码
#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文件

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)
//    {
//        //弹出自定义的设置窗口
//    }

}
相关推荐
*TQK*18 分钟前
ZZNUOJ(C/C++)基础练习1031——1040(详解版)
c语言·c++·编程知识点
※DX3906※1 小时前
cpp实战项目—string类的模拟实现
开发语言·c++
萌の鱼1 小时前
leetcode 2080. 区间内查询数字的频率
数据结构·c++·算法·leetcode
xianwu5433 小时前
反向代理模块jmh
开发语言·网络·数据库·c++·mysql
行十万里人生4 小时前
Qt事件处理:理解处理器、过滤器与事件系统
开发语言·git·qt·华为od·华为·华为云·harmonyos
黑金IT4 小时前
Python3 + Qt5:实现AJAX异步更新UI
qt·ui·ajax
敖行客 Allthinker5 小时前
从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案
linux·运维·服务器·c++
IU宝5 小时前
list的使用,及部分功能的模拟实现(C++)
开发语言·c++
人工智能教学实践5 小时前
基于 yolov8_pyqt5 自适应界面设计的火灾检测系统 demo:毕业设计参考
qt·yolo·课程设计
青草地溪水旁6 小时前
c++ list的front和pop_front的概念和使用案例
c++·容器·list