用VS Code搞Qt 6:Gui基础类型——QGuiApplication和QWindow
在99.996%的情况下,我们弄 Qt 应用都会使用 QApplication 类和 QWidget 类,即直接用 Widgets 库中的组件/控件。为了方便开发人员自己造轮子,Qt 也提供了一套基础的 GUI 组件。这些组件位于 Gui 库中。
实际上,Widgets 也是在 Gui 库上实现的,算是官方默认为咱们实现的图形组件库。若是我们自己也想实现一套图形组件库,就得从 Gui 库入手。当然,此行为需要决心、恒心、耐心、信心、专心、勇气、朝气、力气、努力、神力、洪荒之力。毕竟是一项大工程,没有上述精神元素是很难做成的。因此,许多时候,我们压根儿不会去弄,就算要写个自定义的可视化组件,那一般也是从 QWidget 派生。
尽管不怎么用,但还得了解一下的。QGuiAppliction 类用于管理整个应用程序的消息循环,初始化完各类组件后,开启主消息循环,直到循环结束,程序归西。QApplication 类就是它的子类。
QWindow 类是各种窗口部件的基类。它不仅指窗体,也包括窗口上的控件什么的。控件会被视为子窗口(就是没有了标题栏和边框这些)。所以,从 QWindow 类派生既能实现窗体逻辑,也能自定义控件。不过,咱们一般不会直接从 QWindow 类派生,而是使用以下两个家伙:
1、QRasterWindow :这个很好使,就是我们最最最的绘图方式来画控件的可视化部分。Raster 是“光栅”的意思。
2、QOpenGLWindow :看名字也猜到,该类使用 OpenGL 来绘制控件的可视化部分。
下面老周弄一个简单的演示,实现一个 MyCustWindow 类,派生自 QRasterWindow。里面也没啥逻辑,就是先把窗口的背景刷成红色,显得异常地喜庆和活泼。然后当鼠标移到窗口上时,会在窗口上画一个饼……不,是一个圆,这个圆会跟着鼠标指针走——其实,圆并不会动,只不过在鼠标移动后不断地将窗口重新绘制,以制造出圆会动的效果。
总体的代码文件有四个,其实就两个,C/C++都有头文件,于是就四个了。
/* CMakeLists.txt */ project(MyApp LANGUAGES CXX) find_package(Qt6 REQUIRED COMPONENTS Core Gui)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(MyApp WIN32
app.h
app.cpp
MyCustWindow.h
MyCustWindow.cpp) target_link_libraries(MyApp PRIVATE
Qt6::Core
Qt6::Gui)
app.cpp 是写 main 的,自定义窗口是 MyCustWindow.h 和 MyCustWindow.cpp。老周有个习惯,写C++代码通常会新建个头文件,把要用到的所有头文件一次性弄上去,然后项目中其他地方包含这个头文件就行了。比如这里的 app.h。
#ifndef _APP_H_
#define _APP_H_ #include <QGuiApplication>
#include <QRasterWindow>
#include <QRect>
#include <QSize>
#include <QPainter>
#include <QColor>
#include <QEvent>
#include <QMouseEvent> #endif
Qt 这厮基本就是这样的,每个类一个头文件,所以用到哪些类,直接上名字。_APP_H_ 只是个宏,为了防止多次包含此头文件时被重复定义,没有别的用途。这里老周没有用 #pragma once,据说这个不太通用。当然也没说不能用,只要不报错啥也能上。
接下来是自定义窗口类的定义。
/* MyCustWindow.h */ #include "app.h" class MyCustWindow : public QRasterWindow {
Q_OBJECT
public:
explicit MyCustWindow(QWindow* parent = nullptr);
~MyCustWindow();
protected:
void paintEvent(QPaintEvent *event) override;
bool event(QEvent *event) override; private:
QPoint _curr_pos;
};
用在Qt对象树上的类型(说白了是 QObject 的直接或间接子类)都要加个宏 Q_OBJECT,信号和 Cao 需要它。不知道是啥也没事,照搬就行了。
这里,_curr_pos 是私有的成员,主要用来记录当前鼠标指针的坐标,以便在 paintEvent 中画图用。这个示例需要重写两个成员:
1、paintEvent:绘制窗口内容。
2、event:处理事件,捕捉鼠标指针移动事件—— MouseMove。这里其实可以用 eventFilter,也能起来相同的效果,不过,直接重写 event 最划算。
下面看 event 方法的实现。
bool MyCustWindow::event(QEvent *event)
{
// 分析一下事件类型
if(event -> type() == QEvent::MouseMove)
{
QMouseEvent* msevent = dynamic_cast<QMouseEvent*>(event);
// 拿到当前鼠标指针的位置
_curr_pos = msevent->pos(); // 重新绘制窗口
update();
// 已处理,返回true
return true;
} // 剩下的留给基类默认处理
return QRasterWindow::event(event);
}
如果是鼠标事件,那么,event 参数的指针实际指向的是 QMouseEvent 对象,所以我这里用 dynamic_cast 转换了一下,这个运算符虽然不太安全,但指针之间转换比较好用。这里其实不会有啥问题,因为如 event type 确定为 MouseMove,那么 event 参数就是 QMouseEvent* 类型。接着,访问 pos() 获得当前坐标,赋值给 _curr_pos。最后一步是调用 update 方法,这个一定要调用,这样才能强制窗口重新绘制,那个圆才会跟着鼠标走。
当然,最后一行也少不了,毕竟我们这里只关心鼠标事件,可能还有很多事件,于是这些我们不感兴趣的事件交给基类处理。
return QRasterWindow::event(event);
下一步,我们画窗口内容。
void MyCustWindow :: paintEvent(QPaintEvent *event)
{
QColor bkColor(255,0,0); // 背景色
QColor ptColor(255,255,0); // 跟随鼠标指针的颜色 // 开始表演
QPainter painter(this);
// 设置默认背景色
painter.setBackgroundMode(Qt::OpaqueMode);
painter.setBackground(QBrush(bkColor));
painter.setBrush(QBrush(ptColor));
// 擦除画布
painter.eraseRect(0, 0, width(), height());
// 画圆
painter.drawEllipse(_curr_pos, 20, 20); //event -> accept();
}
最后一行的 accept 方法调用,此处可以有也可以省略。accept 后事件就不再传播到父对象了,不是父类,是对象树上的父对象。窗口算是这里的顶层对象了,所以传不传上去无所谓。
这里有坑,有不少同志说,调用 setBackground 方法无法设置背景,全是黑的。这里要注意两点:
1、setBackgroundMode 方法将模式设置为 OpaqueMode 时才能上背景,如果是 TransparentMode,表明是透明背景,此时设置不了背景色的。程序默认就是 OpaqueMode,所以 setBackgroundMode 一行可以省略。
2、设置背景色后,在绘制前一定要清空画布——调用 eraseRect 方法,本示例中要擦除整个窗口的区域,所以,矩形的大小和窗口大小相同。
调用 drawEllipse 方法直接就可以画圆了,我们这里画的不是椭圆,而是正圆,只要让 x 和 y 轴方向上的半径相等(都是 20)就可以了。
回到 app.cpp,写 main 入口函数。
#include "app.h"
#include "MyCustWindow.h" int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv); // 实例化窗口
MyCustWindow window;
// 标题
window.setTitle("喜狼狼和灰太羊");
// 大小
window.resize(300, 270);
// 位置
window.setPosition(670,364);
// 显示窗口
window.show(); return app.exec();
}
app.exec 开启主消息循环,要在所有初始化工作完成再调用,因为它不会马上返回,而是等消息循环结束才返回。
末了,完工,咱们看看效果。
通过这个演示,大伙伴们对 QWindow 的用处,想必有所了解了。若某天你发现你要干自造轮子的大活,那就得这样弄了。
用VS Code搞Qt 6:Gui基础类型——QGuiApplication和QWindow的更多相关文章
- Qt入门之基础篇 ( 一 ) :Qt4及Qt5的下载与安装
转载请注明出处:CN_Simo. 导语: Qt是一个跨平台的C++图形界面应用程序框架.它提供给开发者建立图形用户界面所需的功能,广泛用于开发GUI程序,也可用于开发非GUI程序.Qt很容易扩展,并且 ...
- Unity3D入门之GUI基础以及常用GUI控件使用(2)
1.GUI基础 (1)GUI部分是每帧擦除重绘的,只应该在OnGUI中绘制GUI,按钮:GUILayout.Button(“Hello”); 只读标签:GUILayout.Label() (2)修改控 ...
- Qt入门之基础篇 ( 二 ) :Qt项目建立、编译、运行和发布过程解析
转载请注明出处:CN_Simo. 题解: 本篇内容主讲Qt应用从创建到发布的整个过程,旨在帮助读者能够快速走进Qt的世界. 本来计划是讲解Qt源码静态编译,如此的话读者可能并不能清楚地知道为何要静态编 ...
- Qt入门之基础篇(三):掌握Qt4的静态编译基本方法
转载载请注明出处:CN_Simo. 导语: 前两章都提到过“静态编译”(Static Compilation),在Windows下一次静态编译差不多需要长达三个小时才能完成,而且还非常容易由于各种原因 ...
- 第4天 | 12天搞定Python,基础语法(下)
为了方便你的学习,减轻负重,我特意将基础语法分成上下两部分.希望你喜欢这种方式,如果不喜欢,你可以跟我说,反正我是不会改的,哈哈~~. 如果上部分,你还没看的话,先去看<第4天 | 12天搞定P ...
- Java基础类型与其二进制表示
Java中的基础类型有:byte.short.int.long.float.double.char和boolean. 它们可被分为四种类型,整型.浮点型.char型和boolean型. 整型:byte ...
- go - 内置基础类型
Go 语言中包括以下内置基础类型: 布尔型:bool 整型:int int64 int32 int16 int8 uint8(byte) uint16 uint32 uint64 uint 浮点型:f ...
- Typescript学习笔记(一)基础类型
为了面向ng2和前端未来,开始搞向ts,ts是微软出的一枚语言,作为es6的超集,他出的一些特性还是蛮好用的(略坑).对于我等纯前端(从开始就接触javascript)的人来说,真想说,这特么什么鬼. ...
- Go的基础类型
1. 命名 Go语言中的函数名.变量名.常量名.类型名.语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母.数字或 ...
随机推荐
- Redis三种模式——主从复制,哨兵模式,集群
一.Redis主从复制作用 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复:实际上是一种服务的冗余. 负 ...
- python使用技巧
当存在一个列表你需要将列表中的元素转为对应字典时,如何操作? 例如将["a", 1]变成{"a": 1} data = ["a", 1] d ...
- composer常用命令(部分摘抄)
1. 仅更新单个库 composer update foo/bar 2. 不编辑composer.json的情况下安装库 composer require "foo/bar:1.0.0&qu ...
- Apache DolphinScheduler新一代分布式工作流任务调度平台实战-中
@ 目录 架构设计 总体架构 启动流程图 架构设计思想简述 负载均衡 缓存 实战使用 参数 参数优先级 内置参数 基础内置参数 衍生内置参数 本地参数和全局参数 工作流传参 数据源管理 支持数据源 创 ...
- 6.8 NOI 模拟
\(T1\ edge\) 考虑\(O(q\times n\times \log n)\)的暴力 暴力二分,直接树上差分 #define Eternal_Battle ZXK #include<b ...
- Auto.js 特殊定位控件方法 不能在ui线程执行阻塞操作,请使用setTimeout代替
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js 特殊定位控件方法 操作环 ...
- Python 爬取途虎养车 全系车型 轮胎 保养 数据
Python 爬取途虎养车 全系车型 轮胎 保养 数据 2021.7.27 更新 增加标题.发布时间参数 demo文末自行下载,需要完整数据私聊我 2021.2.19 更新 增加大保养数据 2020. ...
- 使用 for 循环 打印 9X9乘法表
C 语言自学之99乘法表 请使用for循环,倒序打印9*9乘法表 1 #include <stdio.h> 2 3 int main() 4 { 5 int i,j,result;//定义 ...
- ASP.NET Core 6框架揭秘实例演示[32]:错误页面的集中呈现方式
由于ASP.NET是一个同时处理多个请求的Web应用框架,所以在处理某个请求过程中出现异常并不会导致整个应用的中止.出于安全方面的考量,为了避免敏感信息外泄,客户端在默认情况下并不会得到详细的出错信息 ...
- Apache DolphinScheduler&ShenYu(Incubating) 联合 Meetup,暖春 3 月与你相约!
云霞出海曙,梅柳渡江春. 2022 年的早春在疫情中显得格外生机勃勃,虽然接下来寒流仍有可能造访国内部分地区,但开源的世界,早已热闹非凡! 2022 年 3 月 26 日(星期六), Apache D ...