Qt::FramelessWindowHint无边框化,移动,大小调整

2023-11-11

导读

最近工作一个项目需要用QT设计一个UI,看了一下目前主流商业化UI,例如扣扣,微信,网易云音乐…结合个人审美(本人非美术专业,但游戏经验丰富,对人机交互界面有个人看法),目前界面风格都是扁平化,纯色调,简单易懂。下面是网易云音乐的效果,本人比较喜欢科技风,类似《使命召唤》和《钢铁侠》风格交互。
系统的标题栏和按钮太传统,想在自定义标题栏类似于网易云音乐标题栏风格。在这里插入图片描述

开发环境

本人之前用MFC接触QT后感觉开发效率一个天上一个地上,QT可以说把MFC按在地上摩擦。无论QT还是MFC有优点也有缺点,使用过程会详细介绍。
Qt Creator 4.11.0 Based on Qt 5.14.0 (MSVC 2017, 32 bit)

QT界面无边框

了解各九宫格的概念
一个窗体可以被划分为上、下、左、右、左上、左下、右上、右下、中间,除了中间部分,其他都需要写程序处理。
在这里插入图片描述
在程序中定义Padding 为2,并同时定义枚举类型。

#define PADDING 2
enum Direction { UP=0, DOWN=1, LEFT, RIGHT, LEFTTOP, LEFTBOTTOM, RIGHTBOTTOM, RIGHTTOP, NONE };
        this->setWindowFlags(Qt::FramelessWindowHint);                //取消标题栏
        // 去掉标题栏,去掉工具栏,窗口置顶
        setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
        setWindowOpacity(0.7); //设置窗体透明度

主要使用Qt::FramelessWindowHint。但是设置后窗口无法移动,无法关闭,无法调整大小!查了一下资料,网上大神基本给出2种解决办法:

  1. 重写mouseMoveEvent,mousePressEvent,mouseReleaseEvent 等事件进行处理。
  2. Qt可以处理windows的消息。重新实现bool winEvent(MSG *message, long *result);QT 5.0之后的需要重新实现bool nativeEvent(const QByteArray &eventType, void *message, long *result);

方法1

重写mouseMoveEvent,mousePressEvent,mouseReleaseEvent
MainWindow.h

public:
    void region(const QPoint &currentGlobalPoint);  //鼠标的位置,改变光标
protected:
    //鼠标按下移动及释放事件
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private:
    QPoint m_movePoint;  //鼠标的位置
    bool isLeftPressDown;  // 判断左键是否按下
    Direction dir;        // 窗口大小改变时,记录改变方向

MainWindow.cpp

void MainWindow::region(const QPoint &currentGlobalPoint)
{
    // 获取窗体在屏幕上的位置区域,topLeft为坐上角点,rightButton为右下角点
    QRect rect = this->rect();

    QPoint topLeft = this->mapToGlobal(rect.topLeft()); //将左上角的(0,0)转化为全局坐标
    QPoint rightButton = this->mapToGlobal(rect.bottomRight());

    int x = currentGlobalPoint.x(); //当前鼠标的坐标
    int y = currentGlobalPoint.y();

    if(((topLeft.x() + PADDING >= x) && (topLeft.x() <= x))
            && ((topLeft.y() + PADDING >= y) && (topLeft.y() <= y)))
    {
        // 左上角
        dir = LEFTTOP;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));  // 设置光标形状
    }else if(((x >= rightButton.x() - PADDING) && (x <= rightButton.x()))
              && ((y >= rightButton.y() - PADDING) && (y <= rightButton.y())))
    {
        // 右下角
        dir = RIGHTBOTTOM;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }else if(((x <= topLeft.x() + PADDING) && (x >= topLeft.x()))
              && ((y >= rightButton.y() - PADDING) && (y <= rightButton.y())))
    {
        //左下角
        dir = LEFTBOTTOM;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }else if(((x <= rightButton.x()) && (x >= rightButton.x() - PADDING))
              && ((y >= topLeft.y()) && (y <= topLeft.y() + PADDING)))
    {
        // 右上角
        dir = RIGHTTOP;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }else if((x <= topLeft.x() + PADDING) && (x >= topLeft.x()))
    {
        // 左边
        dir = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }else if((x <= rightButton.x()) && (x >= rightButton.x() - PADDING))
    {
        // 右边
        dir = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }else if((y >= topLeft.y()) && (y <= topLeft.y() + PADDING))
    {
        // 上边
        dir = UP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }else if((y <= rightButton.y()) && (y >= rightButton.y() - PADDING))
    {
        // 下边
        dir = DOWN;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }else
    {
        // 默认
        dir = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}


//三个鼠标事件的重写
//鼠标按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    switch(event->button())
    {
        case Qt::LeftButton:
            isLeftPressDown = true;

            if(dir != NONE)
            {
                this->mouseGrabber(); //返回当前抓取鼠标输入的窗口
            }
            else
            {
                m_movePoint = event->globalPos() - this->frameGeometry().topLeft();
                //globalPos()鼠标位置,topLeft()窗口左上角的位置
            }
            break;
        case Qt::RightButton:
            this->setWindowState(Qt::WindowMinimized);
            break;
        default:
            MainWindow::mousePressEvent(event);
    }
}



//鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    QPoint globalPoint = event->globalPos();   //鼠标全局坐标

    QRect rect = this->rect();  //rect == QRect(0,0 1280x720)
    QPoint topLeft = mapToGlobal(rect.topLeft());
    QPoint bottomRight = mapToGlobal(rect.bottomRight());

    if (this->windowState() != Qt::WindowMaximized)
    {
        if(!isLeftPressDown)  //没有按下左键时
        {
            this->region(globalPoint); //窗口大小的改变——判断鼠标位置,改变光标形状
        }
        else
        {
            if(dir != NONE)
            {
                QRect newRect(topLeft, bottomRight); //定义一个矩形  拖动后最大1000*1618

                switch(dir)
                {
                    case LEFT:

                        if(bottomRight.x() - globalPoint.x() <= this->minimumWidth())
                        {
                            newRect.setLeft(topLeft.x());  //小于界面的最小宽度时,设置为左上角横坐标为窗口x
                            //只改变左边界
                        }
                        else
                        {
                            newRect.setLeft(globalPoint.x());
                        }
                        break;
                    case RIGHT:
                        newRect.setWidth(globalPoint.x() - topLeft.x());  //只能改变右边界
                        break;
                    case UP:
                        if(bottomRight.y() - globalPoint.y() <= this->minimumHeight())
                        {
                            newRect.setY(topLeft.y());
                        }
                        else
                        {
                            newRect.setY(globalPoint.y());
                        }
                        break;
                    case DOWN:
                        newRect.setHeight(globalPoint.y() - topLeft.y());
                        break;
                    case LEFTTOP:
                        if(bottomRight.x() - globalPoint.x() <= this->minimumWidth())
                        {
                            newRect.setX(topLeft.x());
                        }
                        else
                        {
                            newRect.setX(globalPoint.x());
                        }

                        if(bottomRight.y() - globalPoint.y() <= this->minimumHeight())
                        {
                            newRect.setY(topLeft.y());
                        }
                        else
                        {
                            newRect.setY(globalPoint.y());
                        }
                        break;
                     case RIGHTTOP:
                          if (globalPoint.x() - topLeft.x() >= this->minimumWidth())
                          {
                              newRect.setWidth(globalPoint.x() - topLeft.x());
                          }
                          else
                          {
                              newRect.setWidth(bottomRight.x() - topLeft.x());
                          }
                          if (bottomRight.y() - globalPoint.y() >= this->minimumHeight())
                          {
                              newRect.setY(globalPoint.y());
                          }
                          else
                          {
                              newRect.setY(topLeft.y());
                          }
                          break;
                     case LEFTBOTTOM:
                          if (bottomRight.x() - globalPoint.x() >= this->minimumWidth())
                          {
                              newRect.setX(globalPoint.x());
                          }
                          else
                          {
                              newRect.setX(topLeft.x());
                          }
                          if (globalPoint.y() - topLeft.y() >= this->minimumHeight())
                          {
                              newRect.setHeight(globalPoint.y() - topLeft.y());
                          }
                          else
                          {
                              newRect.setHeight(bottomRight.y() - topLeft.y());
                          }
                          break;
                      case RIGHTBOTTOM:
                          newRect.setWidth(globalPoint.x() - topLeft.x());
                          newRect.setHeight(globalPoint.y() - topLeft.y());
                          break;
                      default:
                          break;
                }
                this->setGeometry(newRect);
            }
            else
            {
                move(event->globalPos() - m_movePoint); //移动窗口
                event->accept();
            }
        }
    }
}


//鼠标释放事件
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isLeftPressDown = false;
        if (dir != NONE)
        {
            this->releaseMouse(); //释放鼠标抓取
            this->setCursor(QCursor(Qt::ArrowCursor));
            dir = NONE; //热心网友指正
        }
    }
}

总结起来:
1)窗体矩形区域要转换成在屏幕上的区域,我采取的方式就是取TopLeft和RightBottom两个点来确定这个区域。
2)鼠标移动要去全局的坐标。
3)region函数中判断坐标区间,然后改变鼠标形状

方法2

Qt可以处理windows的消息。重新实现bool winEvent(MSG *message, long *result);QT 5.0之后的需要重新实现bool nativeEvent(const QByteArray &eventType, void *message, long *result);
MainWindow.h

protected:
    bool nativeEvent(const QByteArray &eventType, void *message, long *result);

MainWindow.cpp

bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
    MSG* msg = (MSG*)message;
    switch(msg->message)
    {
    case WM_NCHITTEST:
        int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x();
        int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y();
        if(this->childAt(xPos,yPos) == 0)
        {
            *result = HTCAPTION;
        }else{
            return false;
        }
        if(xPos > 0 && xPos < 8)
            *result = HTLEFT;
        if(xPos > (this->width() - 8) && xPos < (this->width() - 0))
            *result = HTRIGHT;
        if(yPos > 0 && yPos < 8)
            *result = HTTOP;
        if(yPos > (this->height() - 8) && yPos < (this->height() - 0))
            *result = HTBOTTOM;
        if(xPos > 18 && xPos < 22 && yPos > 18 && yPos < 22)
            *result = HTTOPLEFT;
        if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > 18 && yPos < 22)
            *result = HTTOPRIGHT;
        if(xPos > 18 && xPos < 22 && yPos > (this->height() - 22) && yPos < (this->height() - 18))
            *result = HTBOTTOMLEFT;
        if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > (this->height() - 22) && yPos < (this->height() - 18))
            *result = HTBOTTOMRIGHT;
        return true;
    }
    return false;
}

引用

http://www.cnblogs.com/xufeiyang/p/3313104.html
https://blog.csdn.net/u014789012/article/details/103819195

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt::FramelessWindowHint无边框化,移动,大小调整 的相关文章

  • Qt 人工鼠标点击无法正常工作

    小玩具应用程序可以在这里找到 http gist github com 517445 http gist github com 517445 我正在尝试将人工鼠标事件发送到小部件 我使用QApplication sendEvent为此 接下
  • 如何使用 Qt DOM 通过此语法获取 xml 属性

    我正在使用 Qt DOM XML 解析器 并且遇到了如下属性定义的问题
  • Qt qDebug() 在 Windows shell 中不起作用

    我正在使用一个qDebug Qt 框架的printf屏幕上有东西 当我从 Qt Creator 运行应用程序时它工作得很好 但是当我尝试从 Windows 执行它时cmd它什么也没显示 为什么会发生这种情况 你必须添加 CONFIG con
  • QComboBox 下拉项边距

    我想设计我的风格QComboBox为下拉项目留出边距 现在是这样的 我想要这样的东西 我尝试过 QComboBox QAbstractItemView item margin 3px 但它不起作用 你能帮我解决这个问题吗 您想在项目之间设置
  • 在没有加载器的情况下实例化内联组件

    有没有办法实例化内联Component 即在同一文件中定义 而不使用Loader 我不太关心使用的性能影响Loader因为我要用很多东西污染我的文件Loader包装纸 我发现从 JavaScript 创建动态 QML 对象 http doc
  • QT:删除QGridLayout中QLabel之间的空格

    我将一些具有不同颜色的 QLabels 添加到 QGridLayout 作为 QWidget 的布局 现在我在每个 Qlabel 与下一个 Qlabel 之间有一个间距 我想将其删除 我尝试将标签的边距设置为 0 将 GridLayout
  • 在 Qt 中使用多个不同的流读取同一文件

    使用 Qt 是否可以使用多个流读取文件以同时访问其中的不同数据部分 请注意 Qt 中的流 QTextStream QDataStream 不处理底层设备中的位置 流类只是一个包装器 用于更轻松地解析设备 QFile 实例 内的二进制数据 因
  • PyQt4 QPalette 不工作

    btn QtGui QPushButton Button self palettes btn palette palettes setColor btn backgroundRole QtCore Qt green btn setPalet
  • Qt中Q_PROPERTY的意义是什么?

    我无法理解 Q PROPERTY 的用法 Q PROPERTY 如何帮助程序具有防御性 它是干什么用的 我看过这个论坛 但确实无法应用 我已经理解了这个例子 但不明白它的用法 这是一个例子 我能从中得到什么 我知道阅读将赋予只读特权 wri
  • 覆盖 QWebView 中的页面回复

    我试图在 Qt 的 QWebView 中拦截页面 表单请求 并在某些情况下使用替代内容进行响应 QNetworkReply ngcBrowser createRequest Operation operation const QNetwor
  • 如何将自定义 Qt 类型与 QML 信号一起使用?

    我在 Qt 5 2 qml 应用程序中创建了一个自定义类型 class Setting public QObject Q OBJECT Q PROPERTY QString key READ key WRITE setKey Q PROPE
  • 连接到 QNetworkReply::error 信号

    我正在使用 Qt5 的新连接语法 QNetworkReply 有一个名为error http qt project org doc qt 5 0 qtnetwork qnetworkreply html error 2还有一个函数叫做err
  • 在 Qt 中,许多插槽连接到同一信号,它们在发出信号时是否按顺序调用?

    In the Qt文件说 如果多个插槽连接到一个信号 则这些插槽将 按照它们连接的顺序一个接一个地执行 当信号发出时 但在connect 功能 设置Qt ConnectionType输入为Qt QueuedConnection意思是 当控制
  • 如何将 QFile 与 std::iostream 一起使用?

    是否可以像 std iostream 一样使用 QFile 我很确定那里一定有一个包装纸 问题是在哪里 我有另一个库 它需要 std istream 作为输入参数 但在我的程序中 此时我只有一个 QFile 我使用以下代码提出了自己的解决方
  • 使用 QNetworkAccessManager 的 Qt 控制台应用程序

    我正在尝试写一个Qt调用网络服务的应用程序 这是一个控制台应用程序 url 将作为命令行参数传入 我搜索了例如http程序在Qt并找到这个链接 http qt project org doc qt 5 qnetworkaccessmanag
  • CMake AUTOMOC,文件位于不同文件夹中

    我有一个简单的 CMake 项目 proj project folder a h a cpp CMakeLists txt CMakeLists txt cmake minimum required VERSION 3 2 set CMAK
  • Qt - 如何使用 QNetworkAccessmanager 获取响应文本

    这是我的代码 Widget Widget manager new QNetworkAccessManager this connect manager SIGNAL finished QNetworkReply this SLOT repl
  • QThread - 使用槽 quit() 退出线程

    我想在线程完成运行时通知对象 但是 我无法让线程正确退出 我有以下代码 处理器 cpp thread new QThread tw new ThreadWorker connect tw SIGNAL updateStatus QStrin
  • PyQt5 使动态小部件可点击并将参数传递给另一个函数

    我正在尝试制作动态小部件并使它们可点击 通过单击一个小部件 它应该将动态值传递给其他小部件 我尝试过 sender 和其他访问小部件的选项 但没有任何效果 所有小部件都从最后一个小部件发送信息 下面是代码 import sys from P
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se

随机推荐

  • 《QDebug 2023年8月》

    一 Qt Widgets 问题交流 1 获取 QWidget 当前所在屏幕区域 本来以为 QWidget 的 screen 接口返回的是组件自己所在屏幕的 QSreen 实测是所属 Window 所在的屏幕 如果 Window 跨屏了两者所
  • Android 内存分析工具

    Dalvik 虚拟机支持垃圾收集 但是这不意味着你可以不用关心内存管理 你应该格外注意移动设备的内存使用 手机和平板的内存空间是受到限制的 在这篇文章里面 我们来看看Android SDK里面的一些内存剖析工具 profiling tool
  • Windows11安装Vim编辑器配置指南

    Vim简介 Vim 是一个高度可配置的文本编辑器 旨在让创建和更改任何类型的文本变得非常高效 大多数 UNIX 系统和 Apple OS X 都将它作为 vi 包含在内 用惯了Linux中的Vim编辑器 如果需在Windows的cmd终端中
  • form表单的单输入框回车出现同步提交事件处理

    问题 form表单中如果只有一个输入框 在输入时按Enter回车键会出发默认事件自动提交表单 该交互是同步发生的 会导致页面刷新 解决思路 有三种解决思路 1 增加input输入框的数量 如果form表单中不止一个input输入框 那么该表
  • 基于Python的餐厅点餐系统-订餐食堂预约Python爬虫安装数据分析与可视化计算机毕业设计

    更多项目资源 最下方联系我们 目录 一 项目技术介绍 二 项目配套文档 部分内容 资料获取 一 项目技术介绍 该项目含有源码 文档 PPT 配套开发软件 软件安装教程 项目发布教程 包运行成功以及课程答疑与微信售后交流群 送查重系统不限次数
  • 《管理的套路》图解(二)

    13 Iceburg冰山模型 备注 在组织行为学中 冰山模型从三个层面来描述一个人 A态度 深层 B行为 表层 C能力 中间层 14 Burke Litwin组织变革模型 备注 除了考虑外部环境因素 组织和个人绩效因素以及沟通反馈外 还要考
  • 【python】【kNN】【OCR】用python实现字符识别

    一 问题 OCR 光学字符识别 是机器学习重要的应用之一 一般要经过二值化 去噪 倾斜校正 特征抽取 字符切割 字符识别 后处理等过程 其中难度最大的是字符切割 最关键的步骤是字符识别 一般进行字符识别的方法有kNN SVM CNN等方式
  • NUMA模式

    NUMA模式 补充经常听师兄们提到一个词NUMA模式 NUMA架构产生的背景 早期的计算机中 内存控制器在北桥中 所有CPU对内存的访问都要通过北桥来完成 此时所有CPU访问内存都是 一致的 如下图所示 这样的架构称为UMA Uniform
  • GPT3.5插件免费使用方法(无须科学上网)

    1 下载并安装微软Edge浏览器 2 在浏览器输入 edge extensions 或者在页面操作 3 在扩展页面搜索 webtab 插件 4 启用插件 在浏览器输入 edge extensions 回到扩展管理页面 随后会自动进入页面 选
  • 图的拓扑序列

    拓扑序列 拓扑序是按照点的先后顺序排列的 拓扑序列满足以下两点 1 每个顶点在序列中出现且只出现一次 2 若存在一条从顶点 A 到顶点 B 的路径 那么在序列中顶点 A 出现在顶点 B 的前面 拓扑序列只存在于有向无环图中 可以理解成一个将
  • replace和replaceAll区别

    1 replace的参数是char和CharSequence 即可以支持字符的替换 也支持字符串的替换 CharSequence即字符串序列的意思 说白了也就是字符串 2 replaceAll的参数是regex 即基于规则表达式的替换 比如
  • 浅谈一下Python的现状、发展前景以及Python的就业岗位(含趋势)

    在面对职业选择时我们难免纠结 徘徊 不知道去哪能走多远 我们没有办法只考虑当下 无视未来 当下Python工程师正处于人才需求旺盛 供应短缺的时期 工资一路上涨 假如 即便选择了目前火热的Python编程 那你需要先来了解一下Python的
  • 知识产权贯标补贴政策查询大全及怎么申请,奖励20万

    华夏泰科小编认为知识产权贯标旨在促进企业知识产权创造 运用 保护能力提高 使管理工作制度化 规范化 常规化 整体推进全省企业知识产权管理水平有效提升 申请后可以提升企业无形资产价值 巩固企业市场地位 可向科技主管部门申请战略推进项目 专利实
  • win10下设置maven环境变量

    一 先去maven官网 http maven apache org download cgi 下载压缩包 下拉页面可以看到好多版本 注意下载的版本为红色标注版本 apache maven 3 5 0 bin zip 点击下载即可 二 将下载
  • JSR303(一) 简介

    1 简介 数据校验是任何一个应用程序都会用到的功能 无论是显示层还是持久层 通常 相同的校验逻辑会分散在各个层中 这样 不仅浪费了时间还会导致错误的发生 译注 重复代码 为了避免重复 开发人员经常会把这些校验逻辑直接写在领域模型里面 但是这
  • 关于$'\r': command not found错误的一点体会

    今天运行一个其他组开发的jar包 这个jar包由于运行参数是通过命令行的方式输入的 所以需要运行一个shell脚本来启动 启动脚本类似这样 bin bash jdbc driverClassName com mysql jdbc Drive
  • 力扣-->#剑指Offer 897 . 递增顺序搜索树(E)

    class Solution TreeNode curr public TreeNode increasingBST TreeNode root TreeNode first new TreeNode 1 用first 来记录curr的初始
  • 途客圈创业记--读书笔记

    一 初创公司股权结构 2011年6月公司创立 自筹启动资金50万 1 陈天和Alex 每人出资25万元 总计50万元 作为启动资金 2 陈天 CTO兼董事长 股份60 因为是想法的发起人 且在实现这个想法的过程中 Alex CEO 股份40
  • 【C++学习第三讲】C++语句

    目录 C 语句 一 引入 二 声明语句和变量 1 为什么变量必须声明 三 赋值语句 四 cout新花样 五 cout和printf 六 其他C 语句 1 使用cin 2 使用cout进行拼接 七 类简介 一 引入 C 程序是一组函数 而每个
  • Qt::FramelessWindowHint无边框化,移动,大小调整

    QT工作笔记壹 导读 开发环境 QT界面无边框 方法1 方法2 引用 导读 最近工作一个项目需要用QT设计一个UI 看了一下目前主流商业化UI 例如扣扣 微信 网易云音乐 结合个人审美 本人非美术专业 但游戏经验丰富 对人机交互界面有个人看