目录
一. 窗口和屏幕管理
请跳转章节,此处不再重复:QtGUI模块功能详细说明,窗口和屏幕管理(一)
二. 绘图和渲染
请跳转章节,此处不再重复:QtGUI模块功能详细说明,图形绘制与渲染(二)
三. 图像处理
请跳转章节,此处不再重复:QtGUI模块功能详细说明,图像处理(三)
四. 字体和文本
请跳转章节,此处不再重复:QtGUI模块功能详细说明, 字体和文本渲染(四)
五. 事件和输入处理
请跳转章节,此处不再重复:QtGUI模块功能详细说明,事件与输入处理(五)
六. OpenGL 和硬件加速
支持 OpenGL 和 Vulkan 渲染,适用于高性能图形。暂不说明。
七. 颜色和外观
请跳转章节,此处不再重复:QtGUI模块功能详细说明,颜色和外观(六)
八. 图标和光标
1、QIcon: 图标管理
1.1、QIcon 简介
QIcon 是一个跨平台的图标管理工具,能够加载和显示图像(例如 PNG、JPG、SVG 等格式)作为应用程序中的视觉元素。QIcon 不直接存储图像数据,而是通过引用图像文件或资源来管理图标的显示。
-
多模式支持:QIcon 支持多种模式(如 QIcon::Normal、QIcon::Disabled、QIcon::Active、QIcon::Selected),允许为不同交互状态指定不同图像。
-
多状态支持:支持 On 和 Off 状态,常用于切换控件(如复选框或按钮)。
-
多种构造方式:可以通过文件路径、资源文件、QPixmap 或 QImage 创建 QIcon。
-
自动缩放:根据控件大小或高 DPI 设置,QIcon 能自动调整图标尺寸。
1.1.1、QIcon 在 Qt 部件中的应用
按钮(QPushButton、QToolButton 等)
-
QPushButton:通过 setIcon() 方法为按钮设置图标。
QPushButton *button = new QPushButton; QIcon icon(":/images/save.png"); // 从资源文件加载图标 button->setIcon(icon); button->setIconSize(QSize(24, 24)); // 设置图标大小
-
QToolButton:工具按钮通常只显示图标,不显示文本,QIcon 是其核心视觉元素。
QToolButton *toolButton = new QToolButton; toolButton->setIcon(QIcon(":/images/open.png"));
-
状态支持:QIcon 可以为按钮的不同状态(如禁用或按下)设置不同图标:
QIcon icon; icon.addFile(":/images/save_normal.png", QSize(), QIcon::Normal); icon.addFile(":/images/save_disabled.png", QSize(), QIcon::Disabled); button->setIcon(icon);
动作(QAction)
QAction 是 Qt 中用于表示菜单项、工具栏按钮等抽象动作的类,QIcon 为其提供视觉标识。
-
菜单项:在 QMenu 中,QAction 使用 QIcon 显示图标。
QAction *openAction = new QAction(QIcon(":/images/open.png"), "Open", this); QMenu *fileMenu = menuBar()->addMenu("File"); fileMenu->addAction(openAction);
-
工具栏:在 QToolBar 中,QAction 的图标由 QIcon 提供,点击工具栏按钮会触发相应的动作。
QToolBar *toolbar = addToolBar("Main Toolbar"); toolbar->addAction(openAction);
窗口图标(QMainWindow、QDialog 等)
QIcon 可用于设置窗口的标题栏图标或任务栏图标,增强应用程序的品牌识别:
-
设置窗口图标:
QMainWindow *window = new QMainWindow; window->setWindowIcon(QIcon(":/images/app_icon.png"));
-
系统托盘图标:在 QSystemTrayIcon 中,QIcon 用于显示托盘图标。
QSystemTrayIcon *trayIcon = new QSystemTrayIcon(QIcon(":/images/tray_icon.png"), this); trayIcon->show();
其他部件
-
QListWidget、QTreeWidget 等:QIcon 用于为列表项或树节点设置图标。
QListWidgetItem *item = new QListWidgetItem(QIcon(":/images/folder.png"), "Folder"); listWidget->addItem(item);
-
QTabBar/QTabWidget:为选项卡设置图标。
QTabWidget *tabWidget = new QTabWidget; tabWidget->addTab(new QWidget, QIcon(":/images/tab.png"), "Tab 1");
-
QLabel:虽然 QLabel 通常显示文本或图像,但可以通过 QIcon 转换为 QPixmap 显示图标。
QLabel *label = new QLabel; label->setPixmap(QIcon(":/images/icon.png").pixmap(32, 32));
1.2、图标的来源与创建
1.2.1、从文件加载(PNG, JPG, SVG 等格式)
QIcon 可以通过文件路径直接加载图像文件,支持多种常见格式,包括 PNG、JPG、SVG、ICO 等。
-
使用 QIcon 的构造函数或 addFile() 方法加载图像文件。
-
可以为不同状态(如 Normal、Disabled)或尺寸指定不同的图像文件。
// 简单加载单个图像文件
QIcon icon("path/to/icon.png"); // PNG 文件
QPushButton *button = new QPushButton;
button->setIcon(icon);
// 为不同状态加载不同图像
QIcon multiStateIcon;
multiStateIcon.addFile("path/to/normal.png", QSize(), QIcon::Normal); // 正常状态
multiStateIcon.addFile("path/to/disabled.png", QSize(), QIcon::Disabled); // 禁用状态
button->setIcon(multiStateIcon);
// 加载 SVG 文件(支持矢量缩放)
QIcon svgIcon("path/to/icon.svg");
button->setIcon(svgIcon);
1.2.2、从 QPixmap 或 QImage 创建
QIcon 可以通过 QPixmap 或 QImage 对象创建,适合需要动态生成图标或从内存中加载图像的场景。QPixmap 适用于与显示设备相关的像素数据,而 QImage 更适合图像处理。
-
使用 QIcon 的构造函数直接从 QPixmap 或 QImage 创建。
-
也可以通过 addPixmap() 方法为不同状态或模式添加图像。
// 从 QPixmap 创建
QPixmap pixmap(32, 32);
pixmap.fill(Qt::red); // 创建一个红色矩形
QIcon icon(pixmap);
QPushButton *button = new QPushButton;
button->setIcon(icon);
// 从 QImage 创建
QImage image(32, 32, QImage::Format_ARGB32);
image.fill(Qt::blue); // 创建一个蓝色矩形
QIcon imageIcon(QPixmap::fromImage(image));
button->setIcon(imageIcon);
// 为不同状态添加不同 QPixmap
QIcon multiIcon;
multiIcon.addPixmap(QPixmap("path/to/normal.png"), QIcon::Normal);
multiIcon.addPixmap(QPixmap("path/to/disabled.png"), QIcon::Disabled);
button->setIcon(multiIcon);
注意事项:
-
性能:QPixmap 与显示设备相关,适合直接渲染;QImage 更适合图像操作(如缩放、滤镜)。
-
格式转换:QImage 需通过 QPixmap::fromImage() 转换为 QPixmap 再创建 QIcon。
-
内存管理:QIcon 内部会对 QPixmap 或 QImage 进行深拷贝,确保原始对象的生命周期不会影响图标。
1.2.3、从 Qt 资源系统 (.qrc) 加载图标
Qt 资源系统允许将图像文件嵌入应用程序的可执行文件中,通过 .qrc 文件管理资源。QIcon 可以直接从资源路径加载图标,路径以 :/ 开头。这种方式适合打包应用程序,确保图标文件不会丢失。
-
创建 .qrc 文件(如 resources.qrc),列出资源文件。
-
使用 QIcon 构造函数或 addFile() 加载资源路径。
创建 .qrc 文件:可直接使用QtCreator 添加资源文件界面操作实现创建
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>images/icon.png</file>
<file>images/icon_disabled.png</file>
</qresource>
</RCC>
编译资源:
在 Qt 项目文件(.pro)中添加:使用 qmake 或 CMake 编译,资源将被嵌入可执行文件。
RESOURCES += resources.qrc
// 加载单个资源图标
QIcon icon(":/images/icon.png");
QPushButton *button = new QPushButton;
button->setIcon(icon);
// 为不同状态加载资源图标
QIcon multiIcon;
multiIcon.addFile(":/images/icon.png", QSize(), QIcon::Normal);
multiIcon.addFile(":/images/icon_disabled.png", QSize(), QIcon::Disabled);
button->setIcon(multiIcon);
1.2.4、QIcon 的拷贝和赋值语义
QIcon 是一个轻量级类,采用隐式共享(copy-on-write)机制,类似于 QString 和 QPixmap。这意味着拷贝和赋值操作非常高效,多个 QIcon 对象可以共享相同的底层数据,直到其中一个对象被修改。
-
拷贝构造:创建 QIcon 的副本时,共享相同的图像数据。
-
赋值操作:将一个 QIcon 赋值给另一个时,共享数据,引用计数增加。
-
修改操作:当修改 QIcon(如调用 addFile() 或 addPixmap())时,触发深拷贝,创建独立的数据副本。
// 拷贝构造
QIcon icon1(":/images/icon.png");
QIcon icon2(icon1); // 共享数据,高效
QPushButton *button1 = new QPushButton;
button1->setIcon(icon2); // 使用拷贝的图标
// 赋值操作
QIcon icon3;
icon3 = icon1; // 共享数据
icon3.addFile(":/images/new_icon.png"); // 触发深拷贝,icon1 不受影响
// 验证共享状态
qDebug() << icon1.isDetached(); // false(共享数据)
qDebug() << icon3.isDetached(); // true(深拷贝后独立)
1.3、多分辨率与 DPI 支持
1.3.1、为不同 DPI 提供多个尺寸的图像
为了支持高 DPI 显示,开发者可以为 QIcon 提供多个分辨率的图像版本(例如 1x、2x、3x),以适应不同的设备像素比。Qt 会根据屏幕的 DPR 和控件的需求尺寸选择最合适的图像。
-
使用 QIcon::addFile() 或 QIcon::addPixmap() 方法,为同一图标的不同分辨率指定图像。
-
通常通过文件名后缀(如 @2x、@3x)或显式指定尺寸来区分不同分辨率的图像。
-
资源文件或文件系统中的图像可以按分辨率组织。
// 为不同分辨率提供图像(通过文件)
QIcon icon;
icon.addFile(":/images/icon.png", QSize(16, 16)); // 1x,标准分辨率
icon.addFile(":/images/icon@2x.png", QSize(32, 32)); // 2x,高分辨率
icon.addFile(":/images/icon@3x.png", QSize(48, 48)); // 3x,超高分辨率
QPushButton *button = new QPushButton;
button->setIcon(icon);
button->setIconSize(QSize(16, 16)); // 控件期望的逻辑尺寸
使用 QPixmap: 如果图标是动态生成的,可以通过 QPixmap 指定不同分辨率:
QIcon icon;
QPixmap pixmap1x(16, 16);
pixmap1x.fill(Qt::red);
QPixmap pixmap2x(32, 32);
pixmap2x.fill(Qt::red);
icon.addPixmap(pixmap1x, QIcon::Normal, QIcon::Off); // 1x
icon.addPixmap(pixmap2x, QIcon::Normal, QIcon::Off); // 2x
QPushButton *button = new QPushButton;
button->setIcon(icon);
button->setIconSize(QSize(16, 16));
1.3.2、Qt 自动选择最佳尺寸图标的机制
Qt 的 QIcon 引擎会根据以下因素自动选择最合适的图标版本:
-
设备像素比(DPR):由 QScreen::devicePixelRatio() 或 QWindow::devicePixelRatio() 提供。
-
控件期望的图标尺寸:由 setIconSize() 或控件的默认尺寸(如按钮的 iconSize 属性)指定。
-
图标状态和模式:如 Normal、Disabled、Active 等。
-
可用图像的分辨率:QIcon 中注册的图像尺寸。
选择机制:
-
计算物理尺寸:
-
Qt 将控件期望的逻辑尺寸(QSize)乘以设备的 DPR,得到物理像素尺寸。
-
例如:控件设置 iconSize 为 16x16 像素,DPR 为 2.0,则 Qt 会寻找接近 32x32 像素的图像。
-
-
匹配最近尺寸:
-
Qt 从 QIcon 中注册的图像列表中选择与目标物理尺寸最接近的图像。
-
如果没有精确匹配,Qt 会选择尺寸稍大的图像并缩放到目标尺寸(以避免模糊)。
-
-
优先级:
-
优先选择与当前状态(如 Normal、Disabled)和模式匹配的图像。
-
如果没有特定状态的图像,Qt 会回退到默认状态(通常是 Normal)。
-
-
缩放处理:
-
如果选择的图像尺寸与目标尺寸不匹配,Qt 会使用高质量缩放算法(如平滑缩放)调整图像。
-
对于 SVG 图像,Qt 会直接渲染到目标尺寸,无需额外图像版本。
-
// 创建一个支持多分辨率的 QIcon
QIcon icon;
icon.addFile(":/images/icon.png", QSize(16, 16)); // 1x
icon.addFile(":/images/icon@2x.png", QSize(32, 32)); // 2x
// 设置按钮图标
QPushButton *button = new QPushButton;
button->setIcon(icon);
button->setIconSize(QSize(16, 16)); // 逻辑尺寸
// 假设设备 DPR = 2.0,Qt 将选择 32x32 的图像(icon@2x.png)
验证 DPR 和选择:
开发者可以通过以下代码检查设备的 DPR 和实际使用的图标尺寸:
qDebug() << "Device Pixel Ratio:" << button->window()->windowHandle()->devicePixelRatio();
QPixmap actualPixmap = icon.pixmap(button->iconSize(), QIcon::Normal);
qDebug() << "Selected Pixmap Size:" << actualPixmap.size();
1.4、图标的状态管理
QIcon 支持为不同的交互状态和控件状态提供不同的图像,从而增强用户界面的动态性和直观性。
1.4.1、QIcon::Mode:图标模式
QIcon::Mode 枚举定义了图标的视觉模式,用于表示控件在不同交互状态下的外观。Qt 会根据控件的状态(如启用、禁用、悬停等)自动选择对应的模式。
-
QIcon::Normal:默认模式,表示控件处于正常、启用状态。
-
QIcon::Disabled:禁用模式,表示控件不可交互(例如按钮被禁用)。
-
QIcon::Active:激活模式,通常在,
-
QIcon::Selected:选中模式,表示控件被选中(如在菜单或列表中选中某项)。
使用场景:
-
按钮在禁用时显示灰色图标(Disabled)。
-
工具栏按钮在悬停或点击时高亮显示(Active)。
-
菜单项选中时显示不同图标(Selected).
QIcon icon;
icon.addFile(":/images/button_normal.png", QSize(), QIcon::Normal); // 正常状态
icon.addFile(":/images/button_disabled.png", QSize(), QIcon::Disabled); // 禁用状态
icon.addFile(":/images/button_active.png", QSize(), QIcon::Active); // 激活状态
QPushButton *button = new QPushButton;
button->setIcon(icon);
button->setEnabled(false); // 禁用按钮,将显示 disabled 图标
1.4.2、QIcon::State:图标状态
QIcon::State 枚举定义了图标的开关状态,主要用于表示可切换控件(切换按钮)的两种状态。
-
QIcon::On:表示控件处于“开启”状态(如复选框被选中)。
-
QIcon::Off:表示控件处于“关闭”状态(如复选框未选中)。
#include <QApplication>
#include <QToolButton>
#include <QIcon>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QIcon icon;
icon.addFile(":/images/checkbox_on.png", QSize(), QIcon::Normal, QIcon::On); // 选中状态
icon.addFile(":/images/checkbox_off.png", QSize(), QIcon::Normal, QIcon::Off); // 未选中状态
QToolButton *toggleButton = new QToolButton;
toggleButton->setCheckable(true); // 启用切换状态
toggleButton->setIcon(icon);
toggleButton->setIconSize(QSize(16, 16));
toggleButton->setText("Toggle");
toggleButton->show();
return app.exec();
}
2、QCursor: 鼠标光标样式和自定义形状
2.1、QCursor 简介
QCursor 用于表示和管理应用程序中的鼠标光标(cursor)。它提供了对光标形状、位置以及行为的控制,允许开发者自定义光标的外观和功能,以适应不同的用户交互场景。
-
设置光标形状:QCursor 允许开发者设置不同的光标形状,例如箭头(Qt::ArrowCursor)、十字(Qt::CrossCursor)、等待(Qt::WaitCursor)等。
-
自定义光标:开发者可以通过加载图像(如位图或图标)创建自定义光标形状,使用 QCursor(QPixmap) 构造函数加载自定义图像。
-
控制光标位置:QCursor 提供方法(如 QCursor::setPos() 和 QCursor::pos())来设置或获取鼠标光标的屏幕位置,常用于需要程序化控制光标移动的场景,如游戏或绘图应用。
-
动态光标管理:支持在特定控件或窗口区域内动态切换光标。通过 QWidget::setCursor() 设置某个控件的光标形状,或者通过 QApplication::setOverrideCursor() 全局覆盖光标。
2.1.1、关键方法与属性:
-
QCursor(Qt::CursorShape shape):基于预定义形状创建光标。
-
QCursor(const QPixmap &pixmap, int hotX = -1, int hotY = -1):基于自定义图像创建光标,指定热点位置。
-
QCursor::pos():获取当前光标在屏幕上的位置。
-
QCursor::setPos(int x, int y):将光标移动到指定屏幕坐标。
-
QWidget::setCursor(const QCursor &cursor):为特定控件设置光标。
-
QApplication::setOverrideCursor(const QCursor &cursor):临时覆盖全局光标。
-
QApplication::restoreOverrideCursor():恢复被覆盖的光标。
#include <QApplication>
#include <QWidget>
#include <QCursor>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
// 设置窗口的光标为手形
window.setCursor(QCursor(Qt::PointingHandCursor));
// 全局设置等待光标
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
window.show();
return app.exec();
}
2.2、预定义光标样式
2.2.1、Qt::CursorShape 枚举的各种标准光标样式
Qt::CursorShape 是 Qt 框架中定义的一个枚举类型,位于 Qt 命名空间内,用于指定预定义的鼠标光标形状。
-
Qt::ArrowCursor:
-
描述:标准的箭头光标,通常为一个向左上方倾斜的箭头。
-
用途:默认光标,用于表示普通选择或导航状态,适用于大多数非特定交互场景(如窗口背景、普通控件)。
-
典型场景:桌面应用程序的主窗口、文件浏览器中的非交互区域。
-
-
Qt::PointingHandCursor:
-
描述:手形光标,显示为一个指向的手指,通常表示可点击的元素。
-
用途:提示用户可以点击某个控件或区域,例如超链接、按钮或可交互的图标。
-
典型场景:Web 浏览器中的超链接、GUI 中的按钮。
-
-
Qt::IBeamCursor:
-
描述:I 形光标(或称文本光标),形似一个垂直的“I”或光标线。
-
用途:表示用户可以选择或编辑文本,常见于文本输入区域。
-
典型场景:文本编辑器、输入框(如 QLineEdit、QTextEdit)。
-
-
Qt::WaitCursor:
-
描述:等待光标,通常显示为沙漏(Windows)或旋转的圆圈(macOS/Linux)。
-
用途:提示用户程序正在执行耗时操作,暂时无法响应用户输入。
-
典型场景:文件加载、数据处理、网络请求期间。
-
-
Qt::BusyCursor:
-
描述:忙碌光标,通常与 Qt::WaitCursor 类似,但可能带有额外的箭头,表示程序忙碌但仍允许部分交互。
-
用途:用于程序忙碌但仍可接受某些输入的场景。
-
典型场景:后台任务运行时,允许用户继续操作其他控件。
-
-
Qt::CrossCursor:
-
描述:十字光标,显示为一个十字形。
-
用途:表示精确选择或定位,常见于绘图或设计工具中。
-
典型场景:图像编辑软件中的选择工具、CAD 软件中的定位操作。
-
-
Qt::OpenHandCursor:
-
描述:张开的手形光标,表示可以抓取或拖动。
-
用途:提示用户可以拖动对象或平移视图。
-
典型场景:地图应用程序中的平移操作、可拖动的界面元素。
-
-
Qt::ClosedHandCursor:
-
描述:握紧的手形光标,表示正在拖动或抓取。
-
用途:表示拖动操作正在进行,通常与 Qt::OpenHandCursor 配合使用。
-
典型场景:拖动窗口、调整图形元素时。
-
-
Qt::SizeVerCursor:
-
描述:垂直双向箭头光标,表示可以上下调整大小。
-
用途:提示用户可以调整控件或窗口的垂直尺寸。
-
典型场景:调整窗口高度、表格行高。
-
-
Qt::SizeHorCursor:
-
描述:水平双向箭头光标,表示可以左右调整大小。
-
用途:提示用户可以调整控件或窗口的水平尺寸。
-
典型场景:调整窗口宽度、表格列宽。
-
-
Qt::SizeFDiagCursor:
-
描述:对角线双向箭头光标(从左上到右下),表示可以沿对角线调整大小。
-
用途:提示用户可以同时调整宽度和高度。
-
典型场景:调整窗口的右下角大小。
-
-
Qt::SizeBDiagCursor:
-
描述:对角线双向箭头光标(从右上到左下),表示可以沿另一对角线调整大小。
-
用途:与 Qt::SizeFDiagCursor 类似,用于调整窗口或控件大小。
-
典型场景:调整窗口的左下角或右上角。
-
-
Qt::UpArrowCursor:
-
描述:向上箭头光标。
-
用途:较少使用,通常用于特定场景,如表示向上选择或导航。
-
典型场景:自定义工具栏或导航控件。
-
-
Qt::BlankCursor:
-
描述:空光标,即隐藏光标。
-
用途:用于完全隐藏光标,常见于全屏游戏或触摸屏应用。
-
典型场景:第一人称射击游戏、视频播放器。
-
-
Qt::DragMoveCursor:
-
描述:表示移动操作的光标,通常为一个箭头加四向箭头图标。
-
用途:提示用户正在执行拖放操作中的移动。
-
典型场景:文件拖放到新文件夹、拖动界面元素。
-
-
Qt::DragCopyCursor:
-
描述:表示复制操作的光标,通常为一个箭头加加号图标。
-
用途:提示用户正在执行拖放操作中的复制。
-
典型场景:文件复制到新位置。
-
-
Qt::ForbiddenCursor:
-
描述:禁止光标,通常为一个圆形加斜杠。
-
用途:提示用户当前操作不被允许。
-
典型场景:尝试将文件拖放到不可写入的区域。
-
2.2.2、如何设置标准光标到部件或应用程序
Qt 提供了灵活的方式来设置标准光标样式,可以针对特定部件(QWidget 及其子类)或整个应用程序进行设置。
为特定部件设置光标
通过 QWidget::setCursor() 方法,可以为特定的控件或窗口设置光标样式。当鼠标进入该控件区域时,光标会自动切换为指定的形状。
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口
QWidget window;
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建按钮并设置不同的光标样式
QPushButton *button1 = new QPushButton("Click Me");
button1->setCursor(QCursor(Qt::PointingHandCursor)); // 手形光标
QPushButton *button2 = new QPushButton("Edit Text");
button2->setCursor(QCursor(Qt::IBeamCursor)); // 文本光标
// 添加按钮到布局
layout->addWidget(button1);
layout->addWidget(button2);
window.setLayout(layout);
window.show();
return app.exec();
}
为整个应用程序设置全局光标
通过 QApplication::setOverrideCursor() 方法,可以临时覆盖整个应用程序的光标样式。这种方法适合在程序执行特定任务(如耗时操作)时统一显示光标。
#include <QApplication>
#include <QPushButton>
#include <QTimer>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口和按钮
QWidget window;
QPushButton *button = new QPushButton("Start Long Task", &window);
// 按钮点击时模拟耗时操作,显示等待光标
QObject::connect(button, &QPushButton::clicked, [&]() {
// 设置全局等待光标
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
// 模拟耗时任务(3秒后恢复光标)
QTimer::singleShot(3000, []() {
QApplication::restoreOverrideCursor();
});
});
window.show();
return app.exec();
}
动态切换光标(结合事件)
在某些场景下,需要根据用户交互动态切换光标样式,例如鼠标悬停或拖放操作。可以通过重写控件的事件处理函数(如 enterEvent、leaveEvent)或使用信号槽机制实现。
#include <QApplication>
#include <QWidget>
#include <QEvent>
class CustomWidget : public QWidget {
protected:
void enterEvent(QEvent *event) override {
setCursor(QCursor(Qt::PointingHandCursor)); // 鼠标进入时设置为手形光标
QWidget::enterEvent(event);
}
void leaveEvent(QEvent *event) override {
unsetCursor(); // 鼠标离开时恢复默认光标
QWidget::leaveEvent(event);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
CustomWidget widget;
widget.resize(200, 200);
widget.show();
return app.exec();
}
2.3、自定义光标形状
2.3.1、使用 QPixmap 和 QBitmap 定义光标图像和掩码
可以通过 QPixmap 创建光标图像,并结合 QBitmap 定义光标的掩码(mask)来控制光标的透明区域和形状。
-
创建光标图像 (QPixmap):使用 QPixmap 加载或绘制光标图像。图像可以是 PNG、BMP 等格式,通常建议大小为 32x32 像素或更小,以符合系统光标大小限制。
-
创建光标掩码 (QBitmap):掩码是一个单色位图,用于指定光标的哪些部分是透明的(黑色表示透明,白色表示不透明)。
-
创建自定义光标 (QCursor):使用 QPixmap 和 QBitmap 创建 QCursor 对象。
-
应用光标:将光标应用到窗口或控件上:
-
注:如果 QPixmap 包含透明通道,掩码可以省略,直接使用 QCursor cursor(pixmap);。
#include <QApplication>
#include <QWidget>
#include <QEvent>
#include <QBitmap>
#include <QPixmap>
#include <QPainter>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
window.resize(300,400);
QPixmap pixmap(":/images/save.png");
//从 QPixmap 生成掩码
QBitmap mask = pixmap.createMaskFromColor(Qt::transparent);
// //手动绘制掩码:
// QBitmap mask(pixmap.size());
// QPainter painter(&mask);
// mask.fill(Qt::color0); // 黑色(透明)
// painter.setBrush(Qt::color1); // 白色(不透明)
// painter.drawEllipse(0, 0, 16, 16); // 绘制圆形不透明区域
QCursor customCursor(pixmap, mask);// 创建自定义光标 (QCursor)
window.setCursor(customCursor); // 设置到当前窗口
window.show();
return app.exec();
}
2.3.2、设置光标热点(Hotspot)
光标热点(Hotspot)是光标图像中表示点击位置的点(x, y 坐标)。例如,箭头光标的热点通常在其尖端,十字光标的热点在其中心。
指定热点坐标:
在创建 QCursor 时,通过参数指定热点的 x 和 y 坐标(相对于光标图像的左上角)。
QPixmap pixmap(":/cursor.png");
QCursor customCursor(pixmap, 16, 16); // 热点位于图像中心(假设图像为 32x32)
动态计算热点:
如果热点位置需要根据图像内容动态计算,可以分析图像的透明区域或关键点。例如,检测图像的最左侧不透明像素作为热点。
int hotX = pixmap.width() / 2;
int hotY = pixmap.height() / 2;
QCursor customCursor(pixmap, hotX, hotY);
注意:热点坐标必须在图像范围内(0 ≤ x < pixmap.width(), 0 ≤ y < pixmap.height()),否则可能导致光标行为异常。
2.3.3、动态或动画光标(通过定时器或事件循环更新)
动态或动画光标通过定时器或事件循环定期更新光标图像,实现光标的动态效果,例如旋转、闪烁或帧动画。
准备多帧图像:
创建一组 QPixmap 图像,用于表示动画的每一帧。例如,旋转光标可能包含 8 个不同角度的图像。
QList<QPixmap> frames;
frames << QPixmap(":/frame1.png") << QPixmap(":/frame2.png") << QPixmap(":/frame3.png");
使用定时器切换帧:
使用 QTimer 定期触发帧切换,更新光标。
class MyWidget : public QWidget {
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent), currentFrame(0) {
frames << QPixmap(":/frame1.png") << QPixmap(":/frame2.png") << QPixmap(":/frame3.png");
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MyWidget::updateCursor);
timer->start(100); // 每 100ms 更新一次
}
private:
void updateCursor() {
currentFrame = (currentFrame + 1) % frames.size(); // 循环切换帧
QCursor cursor(frames[currentFrame]);
setCursor(cursor);
}
QList<QPixmap> frames;
int currentFrame;
};
2.4、光标的设置与管理
2.4.1、部件级别的光标设置 (QWidget::setCursor(), unsetCursor())
件级别的光标设置允许为特定的 QWidget(如窗口、按钮或自定义控件)设置自定义光标或系统预定义光标。QWidget 类提供了 setCursor() 和 unsetCursor() 方法来管理光标。
设置光标 (QWidget::setCursor()):
//设置系统箭头光标:
QWidget *widget = new QWidget;
widget->setCursor(Qt::ArrowCursor);
//设置自定义光标(基于 QPixmap):
QPixmap pixmap(":/cursor.png");
QCursor customCursor(pixmap, 16, 16); // 热点坐标 (16, 16)
widget->setCursor(customCursor);
恢复默认光标 (QWidget::unsetCursor()):
调用 unsetCursor() 移除部件的自定义光标,恢复到父部件或应用程序的默认光标(通常是 Qt::ArrowCursor)。
widget->unsetCursor();
2.4.2、应用程序级别的全局光标设置 (QApplication::setOverrideCursor())
应用程序级别的光标设置允许临时覆盖整个应用程序的所有光标,通常用于表示全局状态(如等待或繁忙状态)。QApplication 类提供了 setOverrideCursor() 和 restoreOverrideCursor() 方法来实现这一功能。
设置全局光标 (QApplication::setOverrideCursor()):
//设置等待光标:
QApplication::setOverrideCursor(Qt::WaitCursor);
//自定义光标
QPixmap pixmap(":/busy_cursor.png");
QCursor customCursor(pixmap, 16, 16);
QApplication::setOverrideCursor(customCursor);
恢复先前光标 (QApplication::restoreOverrideCursor()):
调用 restoreOverrideCursor() 移除当前全局光标,恢复之前的全局光标或部件级光标。
QApplication::restoreOverrideCursor();
光标栈管理:
setOverrideCursor() 支持光标栈,多次调用会将光标压栈,restoreOverrideCursor() 会弹出栈顶光标。
QApplication::setOverrideCursor(Qt::WaitCursor); // 压栈:等待光标
QApplication::setOverrideCursor(Qt::CrossCursor); // 压栈:十字光标
QApplication::restoreOverrideCursor(); // 弹出:恢复到等待光标
QApplication::restoreOverrideCursor(); // 弹出:恢复到默认光标
3、QIconEngine: 自定义图标渲染引擎
3.1、QIconEngine 简介
QIconEngine 是 Qt 中用于渲染 QIcon 对象的底层接口。QIcon 是一个高层次类,用于表示可在不同上下文(如按钮、工具栏、菜单等)中显示的图标,而 QIconEngine 负责实际的图标渲染逻辑。每个 QIcon 实例都关联一个 QIconEngine(或其子类),由 Qt 内部管理。
核心功能
-
图标渲染:根据请求的大小、模式(如正常、禁用、选中)和状态(如激活、悬停)生成图标图像。
-
多分辨率支持:提供不同尺寸或像素密度的图标,适配高 DPI 显示。
-
动态生成:支持运行时生成图标,而非依赖静态图像文件。
内置的 QIconEngine
-
QPixmapIconEngine:基于 QPixmap 的静态图像渲染。
-
QImageIconEngine:基于 QImage 的渲染。
-
QSvgIconEngine:用于 SVG 矢量图标的渲染。
3.2、QIconEngine 的工作原理
QIconEngine 是一个抽象基类,开发者需要实现其核心虚函数以定义图标的渲染逻辑。
3.2.1、抽象基类及其核心虚函数
QIconEngine 定义在 <QIconEngine> 头文件中。
virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0
-
painter:用于绘制的画笔。
-
rect:目标矩形区域,定义图标的绘制大小和位置。
-
mode:图标模式(QIcon::Normal、QIcon::Disabled、 QIcon::Active、QIcon::Selected)。
-
state:图标状态(QIcon::On 或 QIcon::Off,例如复选框的选中/未选中状态)。
virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
-
返回指定大小、模式和状态的图标图像(QPixmap)。
-
默认实现通过调用 paint() 渲染到 QPixmap,通常无需重写。
-
参数同 paint(),但以 QSize 指定尺寸。
virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
-
返回图标的实际大小,可能受限于图标的固有尺寸。
-
默认实现返回请求的 size,可重写以支持特定约束。
virtual QIconEngine *clone() const:
-
创建引擎的副本,用于 QIcon 的复制操作。
-
必须实现,通常返回一个新的引擎实例。
virtual QString key() const:
-
返回引擎的唯一标识符,用于缓存或比较。
-
默认实现返回类名,可重写以提供更具体的值。
virtual void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state):
-
添加静态 QPixmap 作为图标内容(可选)。
-
常用于混合静态和动态渲染。
virtual void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state):
-
从文件加载图标(可选)。
-
常用于支持文件路径的图标加载。
virtual QStringList availableSizes(QIcon::Mode mode, QIcon::State state) const:
-
返回支持的图标尺寸(可选)。
-
用于多分辨率图标支持。
3.2.2、paint() 方法的实现(核心渲染逻辑)
paint() 是 QIconEngine 的核心方法,负责实际的图标绘制。
初始化画笔:配置 QPainter 的属性(如抗锯齿、画刷、笔)以确保高质量渲染。
处理模式和状态:根据 state 切换图标内容(例如开关的开/关状态)。根据 mode 调整渲染效果:
-
QIcon::Normal:标准渲染。
-
QIcon::Disabled:降低透明度或使用灰度。
-
QIcon::Active:高亮或加粗。
-
QIcon::Selected:更改颜色或背景。
绘制图标:使用 QPainter 绘制形状、路径或图像,适配目标 rect。
适配大小:确保绘制内容填充 rect,必要时缩放或裁剪。
3.2.3、pixmap() 方法的实现(获取缓存图像)
pixmap() 方法用于生成指定大小、模式和状态的 QPixmap,通常由 Qt 内部调用以缓存渲染结果。默认实现通过调用 paint() 完成渲染,开发者可以选择重写以优化性能。
默认实现
默认的 pixmap() 方法创建一个 QPixmap,调用 paint() 绘制内容:
QPixmap QIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) {
QPixmap pixmap(size);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
paint(&painter, QRect(QPoint(0, 0), size), mode, state);
return pixmap;
}
自定义实现
如果需要优化(如缓存特定尺寸的图像),可以重写 pixmap():使用 QCache 或 QMap 存储已渲染的 QPixmap,避免重复渲染。
3.2.4、示例代码
展示动态圆形图标的渲染,支持不同模式和状态,并使用缓存优化 pixmap():
#include <QApplication>
#include <QPushButton>
#include <QIconEngine>
#include <QPainter>
#include <QCache>
class CircleIconEngine : public QIconEngine {
public:
CircleIconEngine() = default;
QIconEngine *clone() const override { return new CircleIconEngine(); }
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override {
painter->setRenderHint(QPainter::Antialiasing, true);
// 根据模式和状态调整颜色
QColor color = (mode == QIcon::Disabled) ? Qt::gray :
(mode == QIcon::Selected) ? Qt::blue :
(mode == QIcon::Active) ? Qt::green : Qt::red;
if (mode == QIcon::Disabled) {
painter->setOpacity(0.5);
}
// 根据状态调整形状
if (state == QIcon::On) {
painter->setBrush(color);
painter->drawEllipse(rect); // 实心圆
} else {
painter->setPen(QPen(color, 2));
painter->setBrush(Qt::NoBrush);
painter->drawEllipse(rect); // 空心圆
}
}
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override {
QString cacheKey = QString("%1_%2_%3_%4")
.arg(size.width()).arg(size.height()).arg(mode).arg(state);
if (cache.contains(cacheKey)) {
return *cache.object(cacheKey);
}
QPixmap pixmap(size);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
paint(&painter, QRect(QPoint(0, 0), size), mode, state);
cache.insert(cacheKey, new QPixmap(pixmap));
return pixmap;
}
private:
static QCache<QString, QPixmap> cache;
};
QCache<QString, QPixmap> CircleIconEngine::cache(100);
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建 QIcon 使用自定义引擎
QIcon icon(new CircleIconEngine());
// 创建按钮并设置图标
QPushButton button;
button.setIcon(icon);
button.setIconSize(QSize(64, 64));
button.setText("Dynamic Icon");
button.setCheckable(true); // 支持 On/Off 状态
button.resize(200, 100);
button.show();
return app.exec();
}
3.3、实现自定义图标引擎
3.3.1、子类化 QIconEngine
要创建自定义图标引擎,需要继承 QIconEngine 并实现其核心虚函数,尤其是 paint() 和 clone()。
-
继承 QIconEngine:创建一个新类,继承自 QIconEngine
-
实现核心虚函数:
-
paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state):定义图标的绘制逻辑。
-
clone() const:返回引擎的副本,用于 QIcon 复制。
-
可选实现 pixmap()、actualSize() 等函数以优化性能或支持特定功能。
-
-
添加自定义逻辑:根据需求添加成员变量或构造函数,用于存储图标的参数(如形状、颜色)。
#include <QIconEngine>
#include <QPainter>
class CustomIconEngine : public QIconEngine {
public:
CustomIconEngine() = default;
QIconEngine *clone() const override {
return new CustomIconEngine(*this);
}
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override {
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setBrush(Qt::red);
painter->drawEllipse(rect); // 示例:绘制红色圆形
}
};
3.3.2、集成第三方 SVG 渲染库或字体图标库
假设使用 Font Awesome 字体,需先将字体文件(如 fa-solid-900.ttf)加载到应用中。确保字体文件已经拷贝到执行目录下:
#include <QApplication>
#include <QPushButton>
#include <QIconEngine>
#include <QPainter>
#include <QCache>
#include <QPainter>
#include <QFontDatabase>
#include <QFont>
class FontIconEngine : public QIconEngine {
public:
FontIconEngine(const QString &iconCode, const QColor &color, qreal size)
: iconCode_(iconCode), color_(color), size_(size) {
// 加载字体
QFontDatabase db;
int fontId = db.addApplicationFont("fa-solid-900.ttf");
fontFamily_ = db.applicationFontFamilies(fontId).first();
}
QIconEngine *clone() const override {
return new FontIconEngine(iconCode_, color_, size_);
}
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override {
painter->setRenderHint(QPainter::Antialiasing, true);
// 设置字体
QFont font(fontFamily_);
font.setPixelSize(qMin(rect.width(), rect.height()) * 0.8);
painter->setFont(font);
// 根据模式调整颜色
QColor renderColor = color_;
if (mode == QIcon::Disabled) {
renderColor = renderColor.lighter(150);
painter->setOpacity(0.5);
} else if (mode == QIcon::Selected) {
renderColor = Qt::blue;
}
painter->setPen(renderColor);
// 居中绘制图标
painter->drawText(rect, Qt::AlignCenter, iconCode_);
}
private:
QString iconCode_; // 字体图标的 Unicode 码点(如 "\uf015" 表示家图标)
QColor color_;
qreal size_;
QString fontFamily_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建 Font Awesome 家图标,
QIcon homeIcon(new FontIconEngine(QString(QChar(0xf015)), Qt::black, 32));
// 创建按钮并设置图标
QPushButton button;
button.setIcon(homeIcon);
button.setIconSize(QSize(64, 64));
button.setText("Home Icon");
button.resize(200, 100);
button.show();
return app.exec();
}
效果:
3.4、将自定义引擎与 QIcon 关联使用
创建引擎实例:实例化自定义的 QIconEngine 子类。
DynamicIconEngine *engine = new DynamicIconEngine(DynamicIconEngine::Circle, Qt::red);
创建 QIcon:使用 QIcon(QIconEngine *engine) 构造函数,将引擎传递给 QIcon。
QIcon icon(engine);
应用到控件:将 QIcon 设置到按钮、工具栏或其他支持图标的控件上。
QPushButton button;
button.setIcon(icon);
button.setIconSize(QSize(64, 64));
九. 平台和渲染后端
提供平台特定集成和渲染后端支持。
-
QPlatformIntegration: 平台特定的窗口系统集成(Windows、X11、Wayland 等)。
-
QRasterPaintEngine: 软件光栅化渲染引擎。
-
QPlatformSurface: 平台特定的渲染表面。
-
QPlatformTheme: 平台主题(如按钮样式、对话框风格)。
-
QPlatformGraphicsBuffer: 平台特定的图形缓冲区。
-
QPlatformSharedGraphicsCache: 共享图形缓存,加速渲染。
十. 国际化(GUI 相关)
支持 GUI 相关的字符编码和区域设置。
-
QTextCodec(部分):字符编码支持(仅限 GUI 文本显示)。
-
QLocale(部分):区域设置(仅限 GUI 格式,如日期、数字显示)。