目录
1.2、QGuiApplication:GUI 应用程序的核心
3.1、QSurface 和 QSurfaceFormat:定义渲染表面
一. 窗口和屏幕管理
1、核心抽象与基础
1.1、Qt 图形栈中的窗口与屏幕管理
Qt 是一个功能强大的跨平台 C++ 框架,广泛用于构建图形用户界面(GUI)和非 GUI 应用程序。其图形栈(Graphics Stack)是 Qt 的核心模块之一,负责管理窗口、屏幕、渲染表面以及跨平台图形渲染的抽象。
-
窗口管理负责创建、显示和操作窗口;
-
屏幕管理则提供对物理显示设备(如显示器)的访问和配置支持。
从 QGuiApplication 到渲染表面
-
QGuiApplication:GUI 应用程序的核心入口,负责初始化图形栈、管理事件循环、全局设置(如主题、输入法)和应用程序生命周期。
-
QWindow:表示一个顶级窗口或子窗口,负责窗口的创建、显示和用户交互。
-
QScreen:提供对物理屏幕的访问,包含屏幕的几何信息、分辨率、像素密度、方向等属性,支持多显示器场景。
-
QBackingStore:用于软件渲染的后台存储,管理窗口的像素数据,适用于非 OpenGL 的渲染路径。
-
QSurface:抽象的渲染表面,QWindow 和 QOffscreenSurface 都继承自 QSurface,表示可以渲染的内容区域。
-
QSurfaceFormat:定义渲染表面的格式,如颜色深度、缓冲区配置、OpenGL 版本等。
-
QOffscreenSurface:离屏渲染表面,用于在非窗口场景下进行图形渲染(如生成纹理或图像)。
1.2、QGuiApplication:GUI 应用程序的核心
QGuiApplication 是单例类,可以通过 QGuiApplication::instance() 获取当前实例,确保 QGuiApplication已创建,否则返回nullptr。
1.2.1、应用程序生命周期管理和事件循环
-
生命周期:
-
构造:创建 QGuiApplication 实例,通常传递命令行参数(argc 和 argv)。
-
初始化:初始化平台相关的图形资源(如 OpenGL 上下文、窗口系统)。
-
运行:调用 exec() 启动事件循环,处理用户输入、定时器和窗口事件。
-
退出:调用 quit() 或 exit() 结束应用程序,释放资源。
-
-
事件循环:
-
QGuiApplication 维护一个事件循环,负责分发事件(如鼠标点击、键盘输入、窗口重绘)。
-
事件循环通过 QEventLoop 实现,支持异步操作和信号槽机制。
-
开发者可以通过 processEvents() 手动处理挂起的事件。
-
1.2.2、全局设置与配置
-
主题和样式:通过 setStyle() 或 setPalette() 设置应用程序的外观。
-
光标:通过 setOverrideCursor() 全局修改鼠标光标。
-
输入法:支持跨平台的输入法管理(如中文输入法),通过 QInputMethod 访问。
-
字体:通过 setFont() 设置全局字体。
-
高 DPI 支持:通过 setHighDpiScaleFactorRoundingPolicy() 配置高 DPI 缩放策略
1.2.3、信号与槽机制在应用程序管理中的应用
-
screenAdded(QScreen*):新屏幕连接时触发。
-
screenRemoved(QScreen*):屏幕断开时触发。
-
focusWindowChanged(QWindow*):窗口获得或失去焦点时触发。
-
applicationStateChanged(Qt::ApplicationState):应用程序状态(如前台、后台)变化时触发。
1.2.4、应用程序退出和状态管理
-
退出:调用 quit() 或 exit(int returnCode) 终止应用程序。
-
状态管理:
-
applicationState():返回当前状态(Qt::ApplicationActive,Qt::ApplicationSuspended)。
-
isSavingSession():检查是否正在保存会话(平台相关)。
-
1.3、QScreen:访问和管理屏幕信息
QScreen 类提供了对物理屏幕的访问,允许开发者获取屏幕的几何信息、分辨率、像素密度、方向等属性。它是多显示器支持和屏幕适配的核心类,适用于动态调整窗口布局和渲染内容。
-
QGuiApplication::screens():返回所有可用屏幕的 QScreen 指针列表。
-
QGuiApplication::primaryScreen():返回主屏幕的 QScreen 指针。
1.3.1、QScreen 对象的详细属性
-
geometry():返回屏幕的完整矩形(QRect),包括装饰边框(如窗口标题栏)。
-
availableGeometry():返回屏幕的可用区域(QRect),不包括任务栏、Dock 或其他系统 UI 元素。
-
physicalDotsPerInch():返回屏幕的物理 DPI(每英寸点数),反映硬件像素密度。
-
logicalDotsPerInch():返回逻辑 DPI,考虑了操作系统的缩放设置。
-
devicePixelRatio():返回逻辑像素与物理像素的比率(qreal),常用于高 DPI 屏幕。
-
orientation():返回屏幕的方向(Qt::ScreenOrientation)。
-
orientationChanged(Qt::ScreenOrientation) 信号:可用于响应方向变化。
-
refreshRate():返回屏幕的刷新率(Hz),如 60Hz 或 120Hz。
-
colorSpace():返回屏幕支持的颜色空间(如 sRGB、Display P3)。
-
多显示器支持,信号:
-
QGuiApplication::screenAdded(QScreen*)
-
QGuiApplication::screenRemoved(QScreen*)
-
QScreen::geometryChanged(QRect)
-
QScreen::physicalDotsPerInchChanged(qreal)
-
-
virtualGeometry():在多显示器场景下,Qt 支持访问虚拟桌面的整体几何信息.
2、QWindow:顶层窗口的抽象
QWindow 是 Qt 图形栈中表示顶层窗口或子窗口的核心类,提供了跨平台的窗口抽象。它是 Qt Quick 和基于 OpenGL/Vulkan 渲染的应用程序的基础,同时也支持软件渲染。QWindow 不仅负责窗口的创建和显示,还管理几何属性、用户交互事件以及与底层窗口系统的对接。
2.1、QWindow 的基本概念与创建
-
跨平台抽象:QWindow 屏蔽了不同操作系统(如 Windows 的 HWND、Linux 的 X11 Window、macOS 的 NSWindow)的底层窗口实现,提供统一的接口。
-
渲染载体:QWindow 是渲染表面的载体,支持 OpenGL、Vulkan、DirectX 或软件渲染。
-
灵活性:支持顶层窗口(如主窗口)、子窗口(如嵌入式窗口)以及特殊窗口(如弹出菜单、工具提示)。
2.1.1、创建 QWindow 实例
-
QWindow 实例通过构造函数创建,默认构造一个空的顶层窗口。
-
可选参数:指定父窗口(QWindow*)或关联的 QScreen。
-
注意:创建 QWindow 后需调用 show() 使其可见。
2.1.2、设置窗口标题 (setTitle())
-
setTitle(const QString &):设置窗口的标题栏文本。
-
标题通常显示在窗口的顶部(平台相关,可能被忽略,如无边框窗口)。
2.1.3、控制窗口可见性
-
show():显示窗口,使其可见。
-
hide():隐藏窗口,但不销毁。
-
showMaximized():最大化显示。
-
showMinimized():最小化显示。
-
showFullScreen():全屏显示。
2.1.4、关闭窗口,Qt6.0
-
close():关闭窗口,触发 QCloseEvent。
-
closeEvent(QCloseEvent*):虚函数,可重写以自定义关闭行为(如提示保存)。
2.1.5、代码样例
#include <QGuiApplication>
#include <QWindow>
#include <QCloseEvent>
#include <QDebug>
class MyWindow : public QWindow {
protected:
//===========Qt 6
// void closeEvent(QCloseEvent *event) override {
// // 提示用户确认关闭
// qDebug() << "Window is about to close. Save changes?";
// event->accept(); // 接受关闭
// event->ignore(); // 忽略关闭
// }
//=============Qt5
bool event(QEvent *event)
{
if (event->type() == QEvent::Close) {
QCloseEvent *closeEvent = static_cast<QCloseEvent *>(event);
qDebug() << "Window is about to close. Save changes?";
return QWindow::event(closeEvent); // 调用基类处理(很重要)
}
return QWindow::event(event); // 调用父类的事件处理
}
};
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
MyWindow window;
window.setTitle("My Qt Window");
window.show(); //显示
return app.exec();
}
2.2、QWindow 的几何管理
QWindow 提供了丰富的几何管理功能,用于控制窗口的位置、大小和状态。
2.2.1、设置和获取窗口的位置
-
设置位置:
-
setX(int)、setY(int):设置窗口的 x 或 y 坐标(相对于屏幕左上角)。
-
setPosition(const QPoint &):设置窗口的左上角位置。
-
setPosition(int x, int y):同上,接受单独的 x 和 y 值。
-
-
获取位置:
-
x()、y():返回窗口的 x 或 y 坐标。
-
position():返回窗口的左上角位置(QPoint)。
-
2.2.2、设置和获取窗口的大小
-
设置大小:
-
setWidth(int)、setHeight(int):设置窗口的宽度或高度。
-
resize(const QSize &):设置窗口的大小。
-
-
获取大小:
-
width()、height():返回窗口的宽度或高度。
-
size():返回窗口的大小(QSize)。
-
2.2.3、设置和获取窗口的几何矩形
-
setGeometry(const QRect &):设置窗口的位置和大小(包括 x, y, width, height)。
-
setGeometry(int x, int y, int w, int h):同上,接受单独的参数。
-
geometry():返回窗口的几何矩形(QRect),包括位置和大小。
-
注意:geometry 包括窗口框架(标题栏等),实际内容区域可能通过 frameGeometry() 。
2.2.4、窗口状态控制
-
showMaximized():最大化窗口。
-
showMinimized():最小化窗口。
-
showFullScreen():全屏显示。
-
showNormal():恢复正常状态。
-
windowState():返回当前状态(Qt::WindowState)
-
setWindowState(Qt::WindowState):设置窗口状态。
2.2.5、窗口标志 (flags(), setFlags())
-
flags():返回当前窗口标志(Qt::WindowFlags)。
-
setFlags(Qt::WindowFlags):设置窗口标志,控制窗口的行为和外观。
-
常用标志:
-
Qt::FramelessWindowHint:无边框窗口。
-
Qt::WindowStaysOnTopHint:窗口始终保持在顶部。
-
Qt::Tool:工具窗口(如弹出菜单)。
-
Qt::Dialog:对话框窗口。
-
Qt::WindowSystemMenuHint:显示系统菜单(平台相关)。
-
2.2.6、代码样例
#include <QGuiApplication>
#include <QWindow>
#include <QDebug>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QWindow window;
window.setTitle("My Qt Window");
window.setPosition(100, 100); // 移动到 (100, 100)
qDebug() << "Position:" << window.position();
window.setGeometry(100, 100, 800, 600);//几何设置
qDebug() << "Geometry:" << window.geometry();
window.frameGeometry();//内容区
Qt::WindowStates state= window.windowState();//状态
qDebug()<<state<<endl;
window.showMinimized();
state= window.windowState();
qDebug()<<state<<endl;
window.setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);//窗口标识
qDebug()<< window.flags()<<endl;
window.show(); //显示
return app.exec();
}
2.3、QWindow 的事件处理
QWindow 的事件处理机制基于 Qt 的事件系统,允许开发者捕获和响应用户交互、窗口状态变化等事件。
2.3.1、窗口事件类型 (QEvent)
-
窗口事件:如暴露(QExposeEvent)、调整大小(QResizeEvent)、移动(QMoveEvent)、关闭(QCloseEvent)。
-
输入事件:如鼠标(QMouseEvent)、键盘(QKeyEvent)、触摸(QTouchEvent)。
-
焦点事件:如 QFocusInEvent、QFocusOutEvent。
-
其他:如 QShowEvent、QHideEvent。
2.3.2、常见的窗口事件
-
暴露事件 (QExposeEvent):
-
当窗口的一部分或全部需要重绘时触发(如窗口显示或被遮挡区域重新暴露)。
-
用途:触发渲染更新。
-
属性:region() 返回需要重绘的区域。
-
-
调整大小事件 (QResizeEvent):
-
当窗口大小改变时触发。
-
属性:size() 返回新大小,oldSize() 返回旧大小。
-
-
移动事件 (QMoveEvent):
-
当窗口位置改变时触发。
-
属性:pos() 返回新位置,oldPos() 返回旧位置。
-
-
关闭事件 (QCloseEvent):
-
当窗口关闭时触发,可通过 accept() 或 ignore() 控制行为。
-
-
焦点事件 (QFocusInEvent, QFocusOutEvent):
-
当窗口获得或失去焦点时触发。
-
-
输入事件:
-
鼠标事件:QMouseEvent(点击、移动、滚轮)。
-
键盘事件:QKeyEvent(按键按下、释放)。
-
触摸事件:QTouchEvent(多点触控)。
-
2.3.3、重写事件处理函数
-
通用事件处理:重写 event(QEvent*) 处理所有事件。
-
特定事件处理:重写特定事件函数,如 resizeEvent()、exposeEvent()。
2.3.4、代码示例
#include <QGuiApplication>
#include <QWindow>
#include <QEvent>
#include <QExposeEvent>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QCloseEvent>
#include <QFocusEvent>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QTouchEvent>
#include <QDebug>
#include <QPainter>
class MyWindow : public QWindow
{
public:
MyWindow() : QWindow() {
setTitle("Event Test Window");
setGeometry(100, 100, 400, 300);
setMouseGrabEnabled(true); // 启用鼠标抓取,以便接收所有鼠标事件
}
protected:
bool event(QEvent *event) override {
qDebug() << "Event Type:" << event->type();
return QWindow::event(event); // 调用基类实现以确保默认行为
}
void exposeEvent(QExposeEvent *event) override {
qDebug() << "Expose Event - Region:" << event->region();
}
void resizeEvent(QResizeEvent *event) override {
qDebug() << "Resize Event - New Size:" << event->size() << ", Old Size:" << event->oldSize();
}
void moveEvent(QMoveEvent *event) override {
qDebug() << "Move Event - New Position:" << event->pos() << ", Old Position:" << event->oldPos();
}
//============Qt6
// void closeEvent(QCloseEvent *event) override {
// qDebug() << "Close Event - Accepting close";
// event->accept(); // 允许窗口关闭
// // event->ignore(); // 阻止窗口关闭
// }
void focusInEvent(QFocusEvent *event) override {
qDebug() << "Focus In Event - Reason:" << event->reason();
}
void focusOutEvent(QFocusEvent *event) override {
qDebug() << "Focus Out Event - Reason:" << event->reason();
}
void mousePressEvent(QMouseEvent *event) override {
qDebug() << "Mouse Press Event - Button:" << event->button() << ", Position:" << event->pos();
}
void mouseReleaseEvent(QMouseEvent *event) override {
qDebug() << "Mouse Release Event - Button:" << event->button() << ", Position:" << event->pos();
}
void mouseMoveEvent(QMouseEvent *event) override {
qDebug() << "Mouse Move Event - Position:" << event->pos();
}
void keyPressEvent(QKeyEvent *event) override {
qDebug() << "Key Press Event - Key:" << event->key() << ", Text:" << event->text();
}
void keyReleaseEvent(QKeyEvent *event) override {
qDebug() << "Key Release Event - Key:" << event->key();
}
void touchEvent(QTouchEvent *event) override {
qDebug() << "Touch Event - Points:" << event->touchPoints().count();
for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
qDebug() << " Point ID:" << point.id() << ", Pos:" << point.pos() << ", State:" << point.state();
}
event->accept(); // 标记触摸事件已被处理
}
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
MyWindow window;
window.show();
return app.exec();
}
2.4、QWindow 与本地窗口系统的交互
QWindow 通过与底层窗口系统的交互,提供跨平台一致性,同时允许开发者访问平台特定的功能。
2.4.1、窗口句柄 (winId()) 的获取和使用
-
winId():返回平台特定的窗口句柄(如 Windows 的 HWND、Linux 的 Window ID)。
-
用途:与本地 API 交互(如调用 Windows API 设置窗口属性)。
2.4.2、窗口激活和焦点管理
-
requestActivate():请求激活窗口(使其成为前台窗口)。
-
信号:
-
focusObjectChanged(QObject*):焦点对象变化时触发。
-
activeChanged():窗口激活状态变化时触发。
-
2.4.3、模态窗口的实现
-
模态窗口:阻止用户与父窗口交互,直到模态窗口关闭。
-
实现方式:
-
设置窗口标志:Qt::Dialog 或 Qt::Popup。
-
使用 setModality(Qt::WindowModality):
-
Qt::NonModal:非模态(默认)。
-
Qt::WindowModal:对父窗口模态。
-
Qt::ApplicationModal:对整个应用程序模态。
-
-
2.4.4、示例代码
#include <QGuiApplication>
#include <QWindow>
#include <QDebug>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QWindow parent;
parent.setGeometry(100, 100, 800, 600);
parent.show();
QWindow dialog;
dialog.setTitle("Modal Dialog");
dialog.setGeometry(200, 200, 400, 300);
dialog.setModality(Qt::ApplicationModal); // 设置为应用模态
dialog.setFlags(Qt::Dialog);
dialog.show();
//窗口切换会触发
QObject::connect(&dialog,&QWindow::activeChanged,[](){
qDebug()<<"activeChanged"<<endl;
});
return app.exec();
}
3、渲染与显示
3.1、QSurface 和 QSurfaceFormat:定义渲染表面
3.1.1、 QSurface 作为抽象渲染表面的概念
QSurface 是 Qt 中用于表示渲染目标的抽象基类,提供了统一接口来描述可以进行渲染的表面,定义了表面的类型(如 RasterSurface、OpenGLSurface)和属性(如大小、格式)。
子类包括:
-
QWindow:表示屏幕上的窗口表面。
-
QOffscreenSurface:表示离屏渲染表面。
3.1.2、QSurfaceFormat 的作用
QSurfaceFormat 用于指定渲染表面的配置,包括颜色深度、缓冲区类型、OpenGL 特性等。它定义了渲染上下文的属性,适用于 OpenGL 或其他图形 API 的渲染。
使用场景:
-
配置 QWindow 或 QOpenGLWidget 的渲染属性。
-
确保渲染上下文满足特定图形 API 的需求(如 OpenGL 核心模式)。
主要属性:
-
颜色缓冲区:setRedBufferSize()、setGreenBufferSize()、setBlueBufferSize()、setAlphaBufferSize() 用于设置 RGBA 通道的位深度。
-
深度和模板缓冲区:setDepthBufferSize()、setStencilBufferSize() 用于 3D 渲染。
-
交换缓冲区:setSwapBehavior() 控制双缓冲或三缓冲 QSurfaceFormat::DoubleBuffer。
-
OpenGL 特性:
-
setVersion(major, minor):指定 OpenGL 版本(如 3.3、4.5)。
-
setProfile():设置 OpenGL 上下文类型(如核心模式 CoreProfile 或兼容模式 CompatibilityProfile)。
-
setRenderableType():指定渲染 API(如 QSurfaceFormat::OpenGL、OpenGL_ES、Vulkan)。
-
-
采样:setSamples() 设置多重采样抗锯齿(MSAA)的采样数。
-
其他:如 setSwapInterval() 控制垂直同步(V-Sync)。
3.1.3 、为 QWindow 设置 QSurfaceFormat
-
创建 QSurfaceFormat 对象并配置属性。
-
设置 QWindow 的表面类型( QSurface::OpenGLSurface 或 QSurface::RasterSurface)
-
应用 QSurfaceFormat。
-
创建并显示窗口。
-
必须在 QWindow::create() 之前设置 QSurfaceFormat,否则配置无效。
3.1.4、示例代码
#include <QGuiApplication>
#include <QWindow>
#include <QDebug>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QSurfaceFormat format;
format.setVersion(3, 3); // 使用 OpenGL 3.3
format.setProfile(QSurfaceFormat::CoreProfile); // 核心模式
format.setDepthBufferSize(24); // 24 位深度缓冲
format.setSamples(4); // 4x 多重采样
format.setSwapInterval(1); // 开启垂直同步
QWindow window;
window.setSurfaceType(QSurface::OpenGLSurface); // 设置为 OpenGL 表面
window.setFormat(format);//应用 QSurfaceFormat
window.create();
window.show();
return app.exec();
}
3.2、QBackingStore:高效的像素缓冲区管理
QBackingStore 是一个用于光栅化渲染的像素缓冲区管理类,适用于 QWindow 的 2D 绘制。
它提供了一个高效的后备缓冲区(backing store),用于存储窗口的像素数据,并在需要时将其呈现到屏幕。
作用:
-
管理窗口的像素缓冲区,避免直接绘制到屏幕导致闪烁。
-
支持高效的重绘机制,仅更新窗口的脏区域(dirty regions)。
-
与 QPainter 配合,提供简单易用的 2D 绘制接口。
重要性:
-
在非 OpenGL 的光栅化渲染场景中,QBackingStore 是 Qt 的核心组件。
-
适合绘制复杂 UI、文本、图像等场景。
3.2.1、缓冲区的创建、调整和更新
-
构造 QBackingStore 时,传入 QWindow 对象。
-
当窗口大小改变时,调用 resize() 调整缓冲区大小。
-
缓冲区内容通过绘制操作更新,仅在需要时更新脏区域以优化性能。
3.2.2、绘制到 QBackingStore
-
调用 beginPaint() 开始绘制,传入需要更新的区域。
-
获取绘制设备(paintDevice())并使用 QPainter 绘制。
-
调用 endPaint() 结束绘制。
-
绘制操作必须在 beginPaint() 和 endPaint() 之间完成。
-
paintDevice() 返回的设备是缓冲区的像素数据,不能直接用于屏幕显示。
3.2.3、将缓冲区内容呈现到屏幕
-
调用 flush() 将缓冲区内容复制到窗口的指定区域。
-
尽量限制 flush() 的区域,仅更新实际变化的部分(通过 QRegion 指定)。
3.2.4、优化渲染性能的策略
-
使用 QRegion 指定脏区域,仅重绘变化部分,避免不必要的全窗口重绘。
-
对于静态内容,使用 QImage 或 QPixmap 缓存绘制结果,减少重复绘制。
-
如果平台支持(如 Windows 的 Direct2D),Qt 会自动使用硬件加速来优化 QBackingStore 的性能。
3.2.5、示例代码
#include <QGuiApplication>
#include <QWindow>
#include <QBackingStore>
#include <QPainter>
#include <QDebug>
#include <QExposeEvent>
#include <QResizeEvent>
// 创建一个继承自 QWindow 的自定义窗口类
class BackingStoreWindow : public QWindow
{
Q_OBJECT
public:
explicit BackingStoreWindow(QWindow *parent = nullptr)
: QWindow(parent),
m_backingStore(new QBackingStore(this))
{
// 设置窗口的表面类型为 RasterSurface,表明使用光栅化(CPU)渲染
setSurfaceType(QWindow::RasterSurface);
}
~BackingStoreWindow() override
{
delete m_backingStore;
}
protected:
// 处理窗口大小变化的事件
void resizeEvent(QResizeEvent *event) override
{
Q_UNUSED(event);
// 调整 BackingStore 的大小以匹配窗口的新尺寸
m_backingStore->resize(size());
// 窗口大小变化通常需要完全重绘
paint(QRegion(0, 0, width(), height()));
}
// 核心绘制函数,接收需要绘制的区域
void paint(const QRegion ®ion)
{
if (region.isEmpty()) {
return;
}
// 1. 开始绘制到 BackingStore,指定需要更新的区域
m_backingStore->beginPaint(region);
// 2. 获取 BackingStore 的绘制设备,并创建 QPainter
QPaintDevice *device = m_backingStore->paintDevice();
QPainter painter(device);
// 限制 QPainter 的绘制区域,只绘制脏区域,提高效率
painter.setClipRegion(region);
// 3. 执行绘制操作
// 示例:填充背景
painter.fillRect(region.boundingRect(), Qt::white);
// 示例:绘制一个动态位置的矩形
static int xOffset = 0;
painter.setBrush(Qt::blue);
painter.drawRect(50 + xOffset, 50, 100, 50);
xOffset = (xOffset + 1) % 200; // 简单动画效果
// 示例:绘制一些文本
painter.setPen(Qt::black);
painter.setFont(QFont("Arial", 20));
painter.drawText(50, 150, "Hello, QBackingStore!");
painter.drawText(50, 180, QString("Window Size: %1x%2").arg(width()).arg(height()));
// 4. 结束绘制
painter.end();
// 5. 将 BackingStore 的内容呈现到屏幕
// 将绘制的区域 flush 到窗口,使其可见
m_backingStore->flush(region);
}
private:
QBackingStore *m_backingStore;
};
#include "main.moc"
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
BackingStoreWindow window;
window.setTitle("QBackingStore Example");
window.resize(400, 300);
window.show();
return a.exec();
}
3.3、 QOffscreenSurface:离屏渲染
QOffscreenSurface 是一个用于离屏渲染的表面,不直接显示在屏幕上,适合后台渲染任务。
应用场景:
-
图像处理:在后台生成或处理图像(如缩放、滤镜)。
-
纹理生成:为 OpenGL 或 Vulkan 生成纹理数据。
-
测试渲染:在不显示窗口的情况下测试渲染代码。
-
截图或导出:将渲染结果保存为图像文件。
3.3.1、创建和配置 QOffscreenSurface
-
构造 QOffscreenSurface 并设置其格式。
-
设置大小(通过 setSize() 或 QSurfaceFormat 的默认大小)。
-
确保 create() 调用成功(检查 surface.isValid())。
3.3.2、结合 QPainter 或其他渲染 API 进行离屏绘制
-
使用 QPainter:创建 QImage 作为渲染目标,结合 QPainter 绘制。
-
使用 OpenGL:创建 OpenGL 上下文并绑定到 QOffscreenSurface。
3.3.3、获取渲染结果
-
保存为图像:
-
如果使用 QImage,直接保存。
-
如果使用 OpenGL,可以通过 QOpenGLFramebufferObject转换为 QImage。
-
-
将渲染结果作为纹理上传到 GPU。
-
用于后续的图像处理或分析。
3.3.4、示例代码
#include <QGuiApplication>
#include <QOffscreenSurface>
#include <QPainter>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLFramebufferObject>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
// 创建并配置离屏表面
QOffscreenSurface surface;
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL); // 使用 OpenGL
surface.setFormat(format);
surface.create();
if (!surface.isValid()) {
qFatal("Failed to create QOffscreenSurface");
}
// 定义图像大小
QSize imageSize(800, 600);
// 使用 QPainter 进行光栅化渲染
QImage image(imageSize, QImage::Format_ARGB32);
QPainter painter(&image);
painter.fillRect(0, 0, image.width(), image.height(), Qt::blue);
painter.setPen(Qt::white);
painter.setFont(QFont("Arial", 24));
painter.drawText(10, 50, "Offscreen Rendering");
image.save("output.png");
// 使用 OpenGL 进行渲染
QOpenGLContext context;
context.setFormat(surface.format());
if (!context.create()) {
qFatal("Failed to create QOpenGLContext");
}
context.makeCurrent(&surface);
// 初始化 OpenGL 函数
QOpenGLFunctions *gl = context.functions();
// 创建帧缓冲区对象 (FBO)
QOpenGLFramebufferObject fbo(imageSize);
fbo.bind();
// 设置 OpenGL 视口
gl->glViewport(0, 0, imageSize.width(), imageSize.height());
gl->glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // 设置清屏颜色为蓝色
gl->glClear(GL_COLOR_BUFFER_BIT);
// 读取 FBO 的像素数据
QImage imageGL = fbo.toImage(); // 直接从 FBO 获取图像
fbo.release(); // 释放 FBO
context.doneCurrent();
// 翻转图像(OpenGL 坐标系与 Qt 不同)
imageGL = imageGL.mirrored();
imageGL.save("opengl_output.png");
return a.exec();
}
//========================
//console
//========================
//output.png:
//大小:800x600 像素。
//内容:蓝色背景,白色文本 "Offscreen Rendering"(Arial 字体,24 号,位置 (10, 50))。
//opengl_output.png:
//大小:800x600 像素。
//内容:纯蓝色填充(由 glClearColor(0.0f, 0.0f, 1.0f, 1.0f) 决定)。
4、高级主题
4.1、自定义窗口框架 (基于 QWindow)
自定义窗口框架允许开发者创建完全个性化的窗口外观和行为,通常用于实现独特的用户界面设计,例如无边框窗口或自定义标题栏。
4.1.1、使用 Qt::FramelessWindowHint 创建无边框窗口
Qt::FramelessWindowHint 是一个窗口标志,用于移除操作系统的默认窗口边框和标题栏,适合创建自定义窗口样式。
实现步骤:
-
创建一个 QWindow 实例或继承 QWindow 的子类。
-
设置窗口标志 Qt::FramelessWindowHint。
-
可选:结合其他标志(如 Qt::Window)以确保窗口行为符合需求。
-
注:无边框窗口不会自动包含关闭、最小化、最大化按钮,需手动实现。
4.1.2、手动实现标题栏拖动、缩放和关闭功能
-
标题栏拖动:通过捕获鼠标按下、移动和释放事件,实现窗口拖动。
-
窗口缩放:实现窗口缩放需要检测鼠标是否位于窗口边缘,并根据鼠标移动调整窗口大小。
-
关闭功能:实现关闭按钮通常结合自定义 UI(如 QPushButton)或直接处理鼠标点击事件。
4.1.3、鼠标事件和几何管理的结合
自定义窗口需要精确处理鼠标事件与窗口几何形状的交互,以实现流畅的用户体验。
关键点:
-
鼠标事件:使用 mousePressEvent、mouseMoveEvent、mouseReleaseEvent 等捕获用户输入。
-
几何管理:通过 setGeometry、setPosition 等方法动态调整窗口位置和大小。
-
区域判断:结合 QRect 和 QPoint 判断鼠标是否在标题栏、边缘或按钮区域。
-
事件过滤:对于复杂 UI,可使用 eventFilter 拦截子控件事件。
4.1.4、示例代码
#include <QWindow>
#include <QApplication>
#include <QMouseEvent>
class CustomWindow : public QWindow {
public:
CustomWindow() {
setFlags(Qt::FramelessWindowHint | Qt::Window); // 无边框窗口
setMinimumSize(QSize(400, 300)); // 设置最小尺寸
setTitle("Custom Window");
}
protected:
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
//在鼠标按下时,判断鼠标位置是否在可缩放区域。
m_resizeMode = getResizeMode(event->pos());
m_dragPosition = event->globalPos();
//记录鼠标按下时的全局位置和窗口位置。
if(m_resizeMode ==ResizeMode::None){
m_dragging = true;
m_dragPosition = event->globalPos() - position();
}
// 假设关闭按钮区域在右上角 30x30 像素
QRect closeButtonRect(width() - 30, 0, 30, 30);
if (closeButtonRect.contains(event->pos())) {
close();
}
}
}
void mouseMoveEvent(QMouseEvent *event) override {
//在鼠标移动时,动态调整窗口的几何形状。
if (m_resizeMode != None && (event->buttons() & Qt::LeftButton)) {
QRect geo = geometry();
QPoint delta = event->globalPos() - m_dragPosition;
if (m_resizeMode & Left) geo.setLeft(geo.left() + delta.x());
if (m_resizeMode & Right) geo.setRight(geo.right() + delta.x());
if (m_resizeMode & Top) geo.setTop(geo.top() + delta.y());
if (m_resizeMode & Bottom) geo.setBottom(geo.bottom() + delta.y());
setGeometry(geo);
m_dragPosition = event->globalPos();
//在鼠标移动时,计算新位置并更新窗口位置。
}else if (m_dragging && (event->buttons() & Qt::LeftButton)) {
setPosition(event->globalPos() - m_dragPosition);
}
}
void mouseReleaseEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
m_dragging = false;
}
}
private:
enum ResizeMode { None, Left, Right, Top, Bottom, TopLeft, TopRight, BottomLeft, BottomRight };
//定义窗口边缘区域(例如,边界 5 像素)。
ResizeMode getResizeMode(const QPoint &pos) {
const int margin = 5;
bool left = pos.x() < margin;
bool right = pos.x() > width() - margin;
bool top = pos.y() < margin;
bool bottom = pos.y() > height() - margin;
if (left && top) return TopLeft;
if (right && top) return TopRight;
if (left && bottom) return BottomLeft;
if (right && bottom) return BottomRight;
if (left) return Left;
if (right) return Right;
if (top) return Top;
if (bottom) return Bottom;
return None;
}
private:
//使用成员变量跟踪拖动状态。
bool m_dragging = false;
QPoint m_dragPosition;
ResizeMode m_resizeMode =ResizeMode::None;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
CustomWindow window;
window.show();
return app.exec();
}
4.2、透明和半透明窗口 (基于 QWindow)
透明和半透明窗口常用于创建现代化的 UI 效果,例如浮动面板、提示窗口或自定义对话框。
4.2.1、设置窗口透明度 (setOpacity())
用于设置窗口的整体透明度,取值范围为 0.0(完全透明)到 1.0(完全不透明)。实现步骤:
-
创建 QWindow 实例。
-
调用 setOpacity(double) 设置透明度。
-
可动态调整透明度以实现淡入淡出效果。
-
注:透明度对整个窗口生效,包括内容区域。频繁更改透明度可能导致渲染开销。
4.2.2、使用 QSurfaceFormat 配置
-
设置 QSurfaceFormat 的 alphaBufferSize 为 8,启用 alpha 通道。
-
使用 QPainter 绘制自定义内容,背景保持透明。
-
使用 setMask() 定义窗口形状。
4.2.3、处理透明区域的鼠标事件
透明区域的鼠标事件处理是实现交互性窗口的关键,例如在不规则形状窗口中只响应特定区域的点击。实现步骤:
-
使用 setMask() 定义窗口的可见区域,鼠标事件仅在该区域触发。
-
重写 mousePressEvent 等方法,检查鼠标位置是否在有效区域。
-
可结合 QRegion 或自定义逻辑判断有效点击区域。
4.2.4、示例代码(windows)
#include <QWindow>
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#include <QTimer>
#include <QDebug>
#include <QRegion>
#include <QSurfaceFormat>
#include <QBackingStore>
class TransparentWindow : public QWindow {
public:
TransparentWindow() {
// 设置无边框窗口和透明表面
setFlags(Qt::FramelessWindowHint | Qt::Window);
QSurfaceFormat format = this->format();
format.setAlphaBufferSize(8); // 启用透明通道
setFormat(format);
setMinimumSize(QSize(400, 300));
// 初始化后备存储
m_backingStore = new QBackingStore(this);
// 设置初始透明度
setOpacity(0.5); // 初始透明度为50%
// 定义窗口形状和鼠标事件的椭圆区域
QRegion region(QRect(50, 50, 300, 200), QRegion::Ellipse);
setMask(region);
// 动态调整透明度(淡入淡出效果)
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [this]() {
static double opacity = 0.5;
opacity += 0.1;
if (opacity > 1.0) opacity = 0.1;
setOpacity(opacity);
});
timer->start(500); // 每500毫秒更新一次透明度
}
protected:
// 处理窗口暴露事件
void exposeEvent(QExposeEvent *event) override {
if (!isExposed()) return;
// 调整后备存储大小以匹配窗口大小
m_backingStore->resize(size());
// 开始绘制
QRect windowRect(0, 0, width(), height());
m_backingStore->beginPaint(QRegion(windowRect));
// 获取绘制设备
QPaintDevice *device = m_backingStore->paintDevice();
QPainter painter(device);
painter.setRenderHint(QPainter::Antialiasing); // 启用抗锯齿
// 用透明颜色清除背景
painter.fillRect(windowRect, Qt::transparent);
// 绘制椭圆内容
painter.setBrush(Qt::blue); // 填充蓝色
painter.drawEllipse(50, 50, 300, 200); // 椭圆区域
// 结束绘制
m_backingStore->endPaint();
// 将后备存储刷新到窗口
m_backingStore->flush(QRegion(windowRect));
// 如果需要,安排更新以确保连续渲染
requestUpdate();
}
// 处理窗口大小调整事件以更新后备存储
void resizeEvent(QResizeEvent *event) override {
m_backingStore->resize(size());
QWindow::resizeEvent(event);
}
// 处理鼠标点击事件
void mousePressEvent(QMouseEvent *event) override {
QRect activeArea(50, 50, 300, 200); // 定义可点击区域
if (activeArea.contains(event->pos())) {
qDebug() << "点击了有效区域!";
} else {
qDebug() << "点击了透明区域!";
}
}
private:
QBackingStore *m_backingStore; // 用于渲染的后备存储
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
TransparentWindow window;
window.show();
return app.exec();
}
二. 绘图和渲染
提供 2D 绘图功能,包括线条、形状、文本和变换。
-
QPainter: 2D 绘图引擎,支持绘制线条、形状、文本、图像。
-
QPaintDevice: 绘图设备基类(支持 QImage、QPixmap,不包括 QWidget)。
-
QPen: 线条样式(颜色、宽度、样式)。
-
QBrush: 填充样式(颜色、渐变、图案)。
-
QGradient: 渐变填充(包括 QLinearGradient、QRadialGradient、QConicalGradient)。
-
QPaintEngine: 底层绘图引擎抽象,支持不同渲染后端(如 Raster、OpenGL)。
-
QRegion: 2D 区域,用于裁剪和碰撞检测。
-
QPainterPath: 复杂路径绘制(如贝塞尔曲线)。
-
QTransform: 2D 变换(旋转、缩放、平移)。
-
QMatrix4x4, QVector2D, QVector3D, QVector4D: 高级变换和坐标(常用于 OpenGL)。
-
QTextItem: 低级文本渲染(不依赖控件)。
三. 图像处理
支持图像创建、操作和文件读写。
-
QImage: 像素级图像操作,适合图像处理。
-
QPixmap: 优化用于屏幕显示的图像。
-
QBitmap: 单色位图。
-
QPicture: 记录和重放绘图指令。
-
QImageReader, QImageWriter: 图像文件读写(支持 PNG、JPEG 等格式)。
-
QMovie: 动态图像播放(如 GIF)。
-
QImageIOHandler: 自定义图像格式处理。
-
QImageEncoderSettings, QImageDecoder (Qt 6): 图像编码/解码设置。
四. 字体和文本
提供字体管理和低级文本渲染功能。
-
QFont: 字体属性管理(大小、粗细、样式)。
-
QFontMetrics, QFontMetricsF: 字体度量,计算文本尺寸。
-
QFontDatabase: 系统字体资源访问。
-
QTextLayout, QTextOption: 高级文本布局和格式化。
-
QRawFont: 直接访问字体文件数据。
-
QTextFragment, QTextBlock: 低级文本结构(用于复杂文本渲染)。
-
QGlyphRun: 字形级文本渲染。
五. 事件和输入处理
处理 GUI 相关的用户输入和交互事件。
-
QMouseEvent: 鼠标点击、移动事件。
-
QHoverEvent: 鼠标悬停事件。
-
QWheelEvent: 鼠标滚轮事件。
-
QKeyEvent: 键盘输入事件。
-
QTouchEvent: 触摸输入事件。
-
QNativeGestureEvent: 平台特定手势(如 macOS 手势)。
-
QInputMethod, QInputMethodEvent: 输入法支持(虚拟键盘、语言切换)。
-
QDrag, QDropEvent: 拖放操作。
-
QClipboard: 剪贴板访问。
-
QTabletEvent: 数位板输入事件。
-
QEnterEvent (Qt 6): 鼠标进入/离开事件。
-
QExposeEvent: 窗口暴露事件。
-
QPlatformDrag: 平台特定的拖放实现。
六. OpenGL 和硬件加速
支持 OpenGL 和 Vulkan 渲染,适用于高性能图形。
-
QOpenGLContext: OpenGL 上下文管理。
-
QOpenGLFunctions, QOpenGLExtraFunctions: OpenGL API 封装。
-
QOpenGLFramebufferObject: 帧缓冲对象,用于离屏渲染。
-
QOpenGLShader, QOpenGLShaderProgram: 着色器支持。
-
QOpenGLTexture: 纹理管理。
-
QOpenGLBuffer: 顶点和索引缓冲区。
-
QOpenGLVertexArrayObject: 顶点数组对象。
-
QOpenGLTimerQuery, QOpenGLTimeMonitor: OpenGL 性能监控。
-
QAbstractOpenGLFunctions (Qt 6): 抽象化的 OpenGL 函数接口。
-
QVulkanInstance, QVulkanWindow (Qt 6): Vulkan 渲染支持。
七. 颜色和外观
管理颜色和外观设置。
-
QColor: 颜色表示(支持 RGB、HSV、CMYK)。
-
QPalette: 颜色方案管理(前景、背景等)。
-
QColorSpace (Qt 6): 颜色空间管理(支持 ICC 配置文件)。
-
QColormap: 颜色映射(主要用于旧平台)。
八. 图标和光标
支持图标和鼠标光标管理。
-
QIcon: 图标管理,支持多分辨率和状态。
-
QCursor: 鼠标光标样式和自定义形状。
-
QIconEngine: 自定义图标渲染引擎。
九. 平台和渲染后端
提供平台特定集成和渲染后端支持。
-
QPlatformIntegration: 平台特定的窗口系统集成(Windows、X11、Wayland 等)。
-
QRasterPaintEngine: 软件光栅化渲染引擎。
-
QPlatformSurface: 平台特定的渲染表面。
-
QPlatformTheme: 平台主题(如按钮样式、对话框风格)。
-
QPlatformGraphicsBuffer: 平台特定的图形缓冲区。
-
QPlatformSharedGraphicsCache: 共享图形缓存,加速渲染。
十. 国际化(GUI 相关)
支持 GUI 相关的字符编码和区域设置。
-
QTextCodec(部分):字符编码支持(仅限 GUI 文本显示)。
-
QLocale(部分):区域设置(仅限 GUI 格式,如日期、数字显示)。