目录
前言
消息事件机制 (Event System)
绘图 (Graphics & Drawing)
绘图设备
Qt 提供的主要绘图设备
Qt 主要绘图设备的特点
各个绘图设备的详细介绍
文件处理 (File Handling)
总结
前言
QT 是一个非常强大的图形用户界面(GUI)开发框架,它的消息事件机制、绘图功能以及文件处理能力都是其重要组成部分。下面是关于这些部分的一些概述。
消息事件机制 (Event System)
Qt 采用 事件驱动 的机制,即 应用程序的运行是由事件触发的。所有用户交互(如鼠标、键盘)或系统行为(如窗口重绘、计时器触发)都以 事件(Event) 的形式传递到 Qt 应用程序。
工作原理
Qt 通过 事件队列(Event Queue) 和 事件循环(Event Loop) 来处理事件:
- 用户或系统产生事件(如鼠标点击)。
- 事件被添加到 Qt 的事件队列(
QApplication::exec()
进入事件循环)。 - Qt 事件分发机制 将事件发送给对应的
QObject
处理(如mousePressEvent()
、keyPressEvent()
)。 - 组件根据事件执行相应的逻辑。
QT 使用事件驱动的方式来管理应用程序的操作。每个 UI 元素(如按钮、窗口、文本框等)都会生成事件,这些事件会被送到事件队列中,并由应用程序的事件循环(Event Loop)逐一处理。基本上,QT 的事件机制涉及以下几个方面:
- 事件循环:QT 应用程序的主线程通常会有一个事件循环,负责处理来自用户的输入事件(如鼠标点击、键盘输入等)以及其他系统事件(如定时器触发)。
- 事件处理:UI 元素的类(如
QWidget
、QPushButton
)可以重写事件处理函数(如mouseEvent
、keyEvent
),从而对不同类型的事件作出响应。 - 事件传播:事件可以通过父子组件链传播。例如,点击事件先在子组件中处理,如果没有处理,才会传递到父组件。
- 自定义事件:你可以通过继承
QEvent
类和QCoreApplication::postEvent
函数来创建并发送自定义事件。
常见的事件类型
在Qt中,QWidget
类定义了很多事件处理函数,这些函数都是protected virtual
的,意味着我们可以在子类中重写它们来响应特定的事件。常见的事件包括:
- keyPressEvent():键盘按键按下事件。
- keyReleaseEvent():键盘按键松开事件。
- mouseDoubleClickEvent():鼠标双击事件。
- mouseMoveEvent():鼠标移动事件。
- mousePressEvent():鼠标按键按下事件。
- mouseReleaseEvent():鼠标按键松开事件。
事件处理的例子
下面是一个基于QLabel
的事件处理示例,它演示了如何响应鼠标事件(鼠标按下、鼠标移动、鼠标释放):
- 打开 Qt Creator。
- 选择 File -> New File or Project,然后选择 Application -> Qt Widgets Application。
- 输入项目名称(例如
MouseEventDemo
)并选择保存路径。- 点击 Next,然后 Finish。
- 右键点击项目名,选择 Add New,然后选择 C++ Class,并命名为
EventLabel
。- 将上述的头文件 (
EventLabel.h
) 和实现文件 (EventLabel.cpp
) 复制到EventLabel.h
和EventLabel.cpp
中。- 在
main.cpp
中包含EventLabel.h
并按照上述代码实现主程序。- 最后点击 Run 或者 ctrl+R 来运行应用程序。
main.cpp
#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);// 创建自定义标签EventLabel *label = new EventLabel;label->setWindowTitle("MouseEvent Demo");label->resize(300, 200);label->show();return app.exec();
}
mainwindow.h
#ifndef EVENTLABEL_H
#define EVENTLABEL_H#include <QLabel>
#include <QMouseEvent>class EventLabel : public QLabel
{Q_OBJECTpublic:// 构造函数explicit EventLabel(QWidget *parent = nullptr);protected:// 重写事件处理函数void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;
};#endif // EVENTLABEL_H
mainwindow.cpp
#include "mainwindow.h"
#include <QString>// 构造函数
EventLabel::EventLabel(QWidget *parent) : QLabel(parent)
{setAlignment(Qt::AlignCenter); // 设置文本居中setText("<h1>Move the mouse here</h1>"); // 初始文本
}// 处理鼠标按下事件
void EventLabel::mousePressEvent(QMouseEvent *event)
{setText(QString("<h1>Press: (%1, %2)</h1>").arg(event->x()).arg(event->y()));
}// 处理鼠标移动事件
void EventLabel::mouseMoveEvent(QMouseEvent *event)
{setText(QString("<h1>Move: (%1, %2)</h1>").arg(event->x()).arg(event->y()));
}// 处理鼠标释放事件
void EventLabel::mouseReleaseEvent(QMouseEvent *event)
{setText(QString("<h1>Release: (%1, %2)</h1>").arg(event->x()).arg(event->y()));
}
运行效果
- 在 Qt Creator 中创建并运行这个项目后,你会看到一个窗口,显示有一个标签。
- 当你点击鼠标、移动鼠标或者释放鼠标时,标签上的文本会相应地更新,显示鼠标的当前坐标。
这样,你就能够在 Qt Creator 中创建并运行一个带有事件处理的简单应用程序了!
mouseMoveEvent()
默认情况下只会在按下鼠标后触发,因为 QWidget
的 mouseTracking
属性默认是 false
。如果你希望鼠标在移动时无需点击就触发 mouseMoveEvent()
,可以在 EventLabel
的构造函数中启用鼠标追踪功能:
修改 mainwindow.cpp 使鼠标追踪生效
// 构造函数
EventLabel::EventLabel(QWidget *parent) : QLabel(parent)
{setAlignment(Qt::AlignCenter); // 设置文本居中setText("<h1>Move the mouse here</h1>"); // 初始文本setMouseTracking(true); // 启用鼠标追踪
}
解释
- 默认情况下 (
mouseTracking = false
)- 只有当鼠标按下并拖动时,
mouseMoveEvent()
才会被触发。
- 只有当鼠标按下并拖动时,
- 启用
mouseTracking = true
- 只要鼠标移动到
QWidget
上,就会触发mouseMoveEvent()
,即使没有点击鼠标。
- 只要鼠标移动到
消息事件机制和信号和槽机制的关系
信号和槽机制(异步回调)
Qt 的 信号和槽(Signal & Slot) 机制是一种 高级的消息通信机制,用于对象之间解耦的事件处理。它是一种 基于发布-订阅模式的回调机制,允许不同对象之间进行交互,而不需要显式调用对方的方法。
工作原理
- 信号(Signal):对象 A 发送一个信号,例如按钮被点击
clicked()
。 - 槽(Slot):对象 B 连接了 A 的信号,并定义了相应的槽函数(例如
onButtonClicked()
)。 - Qt 内部管理信号-槽连接,当信号被触发时,Qt 事件系统会自动调用对应的槽函数。
特性 | 消息事件机制(Event) | 信号和槽机制(Signal & Slot) |
---|---|---|
触发方式 | 事件循环调度 | 直接调用 |
传输机制 | 事件队列 | 直接/异步调用 |
是否跨线程 | 不能 | 可以 |
是否解耦 | 否,需要重写 | 是,对象不直接依赖 |
适用场景 | 低级事件(鼠标、键盘、窗口重绘) | 高级对象交互(按钮点击、线程通信) |
- 事件机制 适用于 GUI 组件(鼠标、键盘、窗口重绘),需要重写
QEvent
处理函数。 - 信号-槽机制 适用于对象间的通信,更高级,更解耦,可以跨线程。
- 二者可以结合使用,在事件触发后发射信号,供其他组件监听。
🎯 应用建议
- 简单交互(鼠标、键盘) → 事件处理
mousePressEvent()
- 按钮点击、跨对象交互 →
connect(signal, slot)
- 复杂任务、跨线程 → 信号-槽机制
绘图 (Graphics & Drawing)
Qt 的绘图系统允许开发者使用相同的 API 在屏幕、打印设备等不同目标上绘制图形。其核心组成部分包括:
- QPainter(画笔):执行绘制操作。
- QPaintDevice(绘图设备):提供绘制的空间,例如窗口、图片、打印机等。
- QPaintEngine(绘图引擎):连接
QPainter
和QPaintDevice
,提供底层绘图支持(通常无需手动使用)。
QPainter(绘图核心)
QPainter
是 Qt 的 绘图核心类,它提供了一组 API 用于 绘制线条、文本、图片、形状等。
基本用法
要在 QWidget
组件上绘制,需要重写 paintEvent()
事件,并在其中使用 QPainter
:
#include <QApplication>
#include <QWidget>
#include <QPainter>class MyWidget : public QWidget {
protected:void paintEvent(QPaintEvent *) override {QPainter painter(this); // 绑定当前窗口painter.setPen(Qt::blue);painter.setFont(QFont("Arial", 20));painter.drawText(50, 50, "Hello Qt!");painter.drawRect(20, 70, 100, 50); // 绘制矩形painter.drawEllipse(150, 70, 50, 50); // 绘制圆}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);MyWidget w;w.resize(300, 200);w.show();return app.exec();
}
📌 要点:
QPainter
需要绑定this
(当前窗口)。setPen()
设置画笔颜色,setFont()
设置字体。- 使用
drawText()
、drawRect()
、drawEllipse()
等方法绘制不同图形。
QPaintDevice(绘图目标)
Qt 提供了多个 QPaintDevice
,QPainter
需要在这些设备上绘制:
QPaintDevice 子类 | 描述 |
---|---|
QWidget | 用于窗口、按钮等组件 |
QPixmap | 用于绘制离屏位图(更高效) |
QImage | 用于像素级操作(如滤镜、图像处理) |
QPicture | 用于存储绘图命令(可回放) |
QPrinter | 用于打印支持 |
在 QPixmap 上绘制
QPixmap pixmap(300, 200);
pixmap.fill(Qt::white);
QPainter painter(&pixmap);
painter.setPen(Qt::red);
painter.drawLine(10, 10, 100, 100);
pixmap.save("output.png"); // 保存为图片
📌 适用场景:
QPixmap
适合 高效绘制(用于 界面)。QImage
适合 逐像素操作(用于 图像处理)。
QPaintEngine(绘图引擎)
QPaintEngine
负责将 QPainter
的绘图指令翻译成底层的 平台绘图调用(如 OpenGL、Raster、Direct2D)。
📌 你通常不需要直接使用 QPaintEngine
,除非你要 自定义绘图设备。
绘图事件与交互
QPainter
主要在 paintEvent()
事件中使用,而绘图交互通常涉及:
- 鼠标事件(mousePressEvent、mouseMoveEvent)
- 定时器事件(QTimer) 实现动画
- 自定义控件绘制(QCustomPlot 等)
示例:鼠标拖动绘制线条
- 打开 Qt Creator。
- 选择 New Project,然后选择 Qt Widgets Application。
- 设置项目名称和路径,点击 Next,然后选择合适的构建套件。
- 点击 Finish 完成创建。
mainwindow.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H#include <QWidget>
#include <QPoint>
#include <QVector>class DrawWidget : public QWidget
{Q_OBJECTpublic:explicit DrawWidget(QWidget *parent = nullptr);~DrawWidget();protected:void paintEvent(QPaintEvent *event) override; // 重写绘图事件void mousePressEvent(QMouseEvent *event) override; // 鼠标按下事件void mouseMoveEvent(QMouseEvent *event) override; // 鼠标移动事件void mouseReleaseEvent(QMouseEvent *event) override; // 鼠标释放事件private:QVector<QPoint> points; // 用来存储鼠标点击的点bool isDrawing = false; // 标记是否正在绘制
};#endif // DRAWWIDGET_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>
#include <QMouseEvent>DrawWidget::DrawWidget(QWidget *parent): QWidget(parent)
{setWindowTitle("Draw with Mouse");setFixedSize(400, 300); // 设置窗口大小
}DrawWidget::~DrawWidget()
{
}void DrawWidget::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.setPen(Qt::black); // 设置画笔颜色为黑色// 绘制已存储的所有点for (int i = 1; i < points.size(); ++i) {painter.drawLine(points[i - 1], points[i]); // 绘制线条}
}void DrawWidget::mousePressEvent(QMouseEvent *event)
{// 当鼠标按下时,开始绘制isDrawing = true;points.clear(); // 清除之前的点points.append(event->pos()); // 记录鼠标按下的位置update(); // 更新窗口,触发重绘
}void DrawWidget::mouseMoveEvent(QMouseEvent *event)
{if (isDrawing) {points.append(event->pos()); // 记录鼠标拖动时的位置update(); // 更新窗口,触发重绘}
}void DrawWidget::mouseReleaseEvent(QMouseEvent *event)
{if (isDrawing) {points.append(event->pos()); // 记录鼠标释放的位置isDrawing = false; // 结束绘制update(); // 更新窗口,触发重绘}
}
主文件:main.cpp
#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);// 创建窗口并显示DrawWidget w;w.show();return a.exec();
}
运行项目
- 在 Qt Creator 中构建并运行项目。
- 鼠标点击并拖动窗口,你将看到鼠标拖动的路径逐渐绘制出来。
mousePressEvent
:当鼠标按下时,记录当前位置,并清空之前的点,开始绘制。mouseMoveEvent
:鼠标拖动时,不断记录新的点,并更新绘制区域。mouseReleaseEvent
:鼠标释放时,结束当前绘制过程,并记录最后一个点。
在窗口中实现动态绘制线条的效果
mainwindow.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H#include <QWidget>
#include <QVector>
#include <QPoint>class DrawWidget : public QWidget
{Q_OBJECTpublic:explicit DrawWidget(QWidget *parent = nullptr);~DrawWidget();protected:void paintEvent(QPaintEvent *event) override; // 绘图事件void mousePressEvent(QMouseEvent *event) override; // 鼠标按下事件void mouseMoveEvent(QMouseEvent *event) override; // 鼠标移动事件void mouseReleaseEvent(QMouseEvent *event) override; // 鼠标释放事件private:QVector<QVector<QPoint>> lines; // 存储所有绘制的线条QVector<QPoint> currentLine; // 当前绘制的线条
};#endif // DRAWWIDGET_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>
#include <QMouseEvent>DrawWidget::DrawWidget(QWidget *parent): QWidget(parent)
{setWindowTitle("动态鼠标绘制");setFixedSize(600, 400); // 设置窗口大小
}DrawWidget::~DrawWidget()
{
}void DrawWidget::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.setPen(QPen(Qt::black, 2)); // 设置黑色画笔,线宽 2// 绘制所有历史线条for (const auto &line : lines) {for (int i = 1; i < line.size(); ++i) {painter.drawLine(line[i - 1], line[i]);}}// 绘制当前线条for (int i = 1; i < currentLine.size(); ++i) {painter.drawLine(currentLine[i - 1], currentLine[i]);}
}void DrawWidget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {currentLine.clear(); // 清空当前线条currentLine.append(event->pos()); // 记录鼠标按下的点update(); // 触发重绘}
}void DrawWidget::mouseMoveEvent(QMouseEvent *event)
{if (!currentLine.isEmpty()) {currentLine.append(event->pos()); // 记录鼠标移动轨迹update(); // 触发重绘,实现动态绘制}
}void DrawWidget::mouseReleaseEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton && !currentLine.isEmpty()) {lines.append(currentLine); // 将当前线条加入历史线条currentLine.clear();update(); // 触发重绘}
}
main.cpp
#include <QApplication>
#include "mainwindow.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);DrawWidget w;w.show();return a.exec();
}
✅ 实时绘制:鼠标移动时,线条立即更新,无需等待鼠标释放。
✅ 多段绘制:支持多次绘制,每次释放鼠标都会存入历史线条。
✅ 动态更新:每次 mouseMoveEvent()
都会触发 update()
,保证实时绘制效果。
小结
- QPainter 是 Qt 的核心绘图 API,必须在
paintEvent()
或QPaintDevice
绑定后使用。 - QPaintDevice 提供绘图目标,如 窗口(QWidget)、位图(QPixmap)、图片(QImage)。
- QPaintEngine 负责底层绘图,通常无需直接操作。
- 事件机制(如
mouseMoveEvent()
)可用于绘图交互。
绘图设备
在 Qt 中,绘图设备(QPaintDevice) 是用于支持 QPainter
进行绘制的对象。它提供了一个二维的绘图表面,可以是窗口、图片、缓冲区等。所有可以绘制的对象都继承自 QPaintDevice
,例如 QWidget
、QPixmap
、QImage
等。
QPaintDevice
本身是一个基类,不能直接使用,而是通过其子类来提供不同的绘图方式和特性。
Qt 提供的主要绘图设备
Qt 提供了四种常见的绘图设备,分别是:
- QPixmap - 适用于屏幕显示的优化图像。
- QBitmap -
QPixmap
的子类,仅支持单色位图(1 位深度)。 - QImage - 适用于像素级访问的图像数据。
- QPicture - 记录和重放
QPainter
命令的设备。
Qt 主要绘图设备的特点
绘图设备 | 特点 | 适用场景 |
---|---|---|
QPixmap | 适用于屏幕显示,底层优化,存储格式与设备相关 | UI 组件绘制、按钮、标签、绘制缓冲 |
QBitmap | 单色位图 (1-bit ),是 QPixmap 的子类 | 绘制蒙版、遮罩、位操作 |
QImage | 支持像素级访问,可独立于设备存储 | 图像处理、滤波、像素操作 |
QPicture | 记录 QPainter 命令,适用于重放绘图操作 | 矢量绘图、回放绘制 |
各个绘图设备的详细介绍
① QPixmap
(屏幕优化的图像)
QPixmap
是一种高效的图像存储方式,它主要用于 屏幕显示,在底层进行了特定优化,能在不同操作系统上实现最快的绘制效果。QPixmap
不能 直接访问像素数据,因此 不适合像素级操作,如果需要操作像素,可以使用 QImage
。
示例:加载并显示一张图片
创建 Qt Widgets 应用程序
在 Qt Creator 中,新建一个 Qt Widgets Application 项目,并选择QMainWindow
作为主窗口类型。修改
mainwindow.h
在mainwindow.h
文件中,添加QLabel
作为图片显示组件。修改
mainwindow.cpp
在mainwindow.cpp
文件中,加载并显示图片。运行程序,窗口中会显示
image.png
这张图片。
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QLabel>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:QLabel *imageLabel; // 用于显示图片的 QLabel
};#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPixmap>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{// 创建 QLabel 用于显示图片imageLabel = new QLabel(this);// 加载图片QPixmap pixmap("image.png"); // 确保 image.png 在可访问的路径if (pixmap.isNull()) {imageLabel->setText("图片加载失败");} else {imageLabel->setPixmap(pixmap);imageLabel->setScaledContents(true); // 让图片适应 QLabel 大小}// 设置 QLabel 作为主窗口的中心组件setCentralWidget(imageLabel);resize(600, 400); // 设置窗口大小
}MainWindow::~MainWindow()
{
}
main.cpp
#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication app(argc, argv);MainWindow window;window.show();return app.exec();
}
如果路径不对
绘制图片
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QPixmap>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();protected:void paintEvent(QPaintEvent *event) override; // 监听绘制事件private:QPixmap pixmap;
};#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{// 加载图片pixmap.load("D:/PIC/01.png"); // 替换为你的图片路径// 设置窗口大小resize(400, 300);
}// 监听绘制事件,使用 QPainter 进行绘制
void MainWindow::paintEvent(QPaintEvent *event)
{QMainWindow::paintEvent(event); // 调用基类的 paintEvent 以确保正常绘制QPainter painter(this);// 确保图片加载成功再绘制if (!pixmap.isNull()) {painter.drawPixmap(0, 0, pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));}
}MainWindow::~MainWindow()
{
}
main.cpp
#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
修改mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{// 加载图片pixmap.load("D:/PIC/01.png"); // 替换为你的图片路径// 设置窗口大小resize(800, 400); // 调整窗口大小以适应对比显示
}// 监听绘制事件,绘制原图和缩放后的图
void MainWindow::paintEvent(QPaintEvent *event)
{QMainWindow::paintEvent(event); // 调用基类 paintEvent 确保正常绘制QPainter painter(this);if (!pixmap.isNull()) {// 1. 绘制原图(左侧)painter.drawPixmap(10, 10, pixmap); // 原图按原始大小绘制// 2. 绘制缩放后的图(右侧)QPixmap scaledPixmap = pixmap.scaled(size() / 2, Qt::KeepAspectRatio, Qt::SmoothTransformation);int x = width() / 2; // 放在右侧int y = (height() - scaledPixmap.height()) / 2; // 居中对齐painter.drawPixmap(x, y, scaledPixmap);}
}MainWindow::~MainWindow()
{
}
✅ 左侧:按原始大小显示 原图
✅ 右侧:自适应窗口大小的 缩放图
✅ 缩放窗口时,右侧图像会随窗口大小变化
如果希望固定原图的位置或大小,可以手动调整 drawPixmap()
的 x, y
坐标。
QImage 和 QPixmap 的区别
QImage 和 QPixmap 都用于处理图像,但它们的用途不同。
1. 用途
- QPixmap:用于屏幕显示,针对 GUI 绘图进行了优化,通常用于 QPainter 进行高效绘制。
- QImage:用于图像处理,支持像素级修改,适合I/O 读写、图像转换、过滤处理等。
2. 平台依赖
- QPixmap:依赖于 底层平台的绘图引擎,在不同系统上可能会有不同的显示效果(如 Windows、Linux、Mac)。
- QImage:完全基于 Qt 自身的绘图引擎,在不同平台上的显示效果 一致。
3. 线程
- QPixmap:不能在非 GUI 线程 中操作,因为它依赖于 底层绘图系统。
- QImage:可以在非 GUI 线程 操作,因此适用于 多线程图像处理。
4. 像素操作
- QPixmap:不支持直接像素访问,如果需要修改像素,必须先转换为
QImage
。 - QImage:支持 像素级别访问,可以用
setPixel()
和pixel()
操作单个像素。
适用场景
QPixmap | QImage | |
---|---|---|
用途 | 绘图 & 显示 | 处理 & 操作 |
优化 | 屏幕绘制优化 | 像素处理优化 |
像素级操作 | ❌ 不能直接访问像素 | ✅ 可直接操作像素 |
线程支持 | 仅 GUI 线程 | 可用于非 GUI 线程 |
跨平台显示 | 可能不同 | 保持一致 |
- 如果只是显示图片,使用
QPixmap
(性能更好) - 如果要修改图片像素,使用
QImage
- 如果要在多线程中操作图片,使用
QImage
-
如果要在绘图中使用
QImage
,先转换为QPixmap
② QBitmap
QBitmap
是 QPixmap
的子类,表示 单色(黑白)位图,用于 遮罩(mask)和透明度处理。
特点
- 仅支持 1-bit 深度(0 = 黑色,1 = 白色)。
- 用于透明遮罩,例如创建窗口的 不规则形状 或 按钮透明背景。
- 继承
QPixmap
,受 GPU 加速,在绘制时效率较高。
示例:创建一个黑白遮罩
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QBitmap>class BitmapWidget : public QWidget
{
public:BitmapWidget(QWidget *parent = nullptr) : QWidget(parent) {}protected:void paintEvent(QPaintEvent *event) override{QPainter painter(this);// 创建 QBitmap(黑白位图)QBitmap bitmap(100, 100);bitmap.fill(Qt::color0); // 全部填充为黑色// 在 QBitmap 上绘制白色图形QPainter bmpPainter(&bitmap);bmpPainter.setBrush(Qt::color1);bmpPainter.drawEllipse(20, 20, 60, 60);bmpPainter.end();// 显示位图painter.drawPixmap(50, 50, bitmap);}
};int main(int argc, char *argv[])
{QApplication app(argc, argv);BitmapWidget w;w.resize(200, 200);w.show();return app.exec();
}
应用场景
场景 | 说明 |
---|---|
遮罩效果 | 例如 透明窗口、按钮背景透明化 |
简单二值化图像 | 处理 黑白图形,如 OCR 预处理 |
高效绘制 | 由于 QBitmap 继承 QPixmap ,它使用 GPU 进行加速绘制 |
③ QImage
QImage
是 Qt 提供的 通用图像处理类,用于 像素级 访问和 图像文件读写。
特点
- 支持多种格式(RGB、灰度、ARGB、CMYK)。
- 可直接操作像素数据(
setPixel()
、pixel()
)。 - 支持
QPainter
进行绘制。 - 可独立于 GUI 线程,适合 后台线程 进行图像处理。
- 支持 Alpha 透明度,适用于 复杂的图像编辑。
示例:加载 QImage 并修改像素
#include <QApplication>
#include <QWidget>
#include <QImage>
#include <QPainter>class ImageWidget : public QWidget
{
public:ImageWidget(QWidget *parent = nullptr) : QWidget(parent){// 加载图片image = QImage("D:/PIC/01.png").scaled(300, 200, Qt::KeepAspectRatio);}protected:void paintEvent(QPaintEvent *event) override{QPainter painter(this);// 修改像素值(将左上角 50x50 区域变红)for (int y = 0; y < 50; ++y){for (int x = 0; x < 50; ++x){image.setPixel(x, y, qRgb(255, 0, 0));}}// 绘制 QImagepainter.drawImage(50, 50, image);}private:QImage image;
};int main(int argc, char *argv[])
{QApplication app(argc, argv);ImageWidget w;w.resize(400, 300);w.show();return app.exec();
}
应用场景
场景 | 说明 |
---|---|
图像处理 | 进行 滤波、变换、像素修改 |
图片加载与保存 | QImage::load() / QImage::save() 支持 BMP, JPG, PNG 等格式 |
多线程处理 | 可以在 后台线程 进行图像计算 |
透明度处理 | QImage::Format_ARGB32 处理带透明通道的图像 |
QBitmap vs QImage vs QPixmap
特性 | QBitmap | QImage | QPixmap |
---|---|---|---|
颜色深度 | 1-bit (黑白) | 8-bit, 16-bit, 32-bit (支持透明) | 受 平台优化 |
用途 | 遮罩、透明背景 | 像素级处理、文件读写 | 高效屏幕绘制 |
像素操作 | ❌(不可修改像素) | ✅ setPixel() / pixel() | ❌(不能修改) |
存储方式 | GPU | 内存 | GPU |
支持 Alpha 透明 | ❌ | ✅(ARGB) | ✅(但像素不可直接操作) |
多线程支持 | ❌ | ✅ | ❌ |
④ QPicture 介绍
QPicture
是 Qt 提供的一种绘图设备,它可以 记录 和 重现 QPainter
的绘图命令。
特点
- 记录绘图操作:可以存储
QPainter
的绘制命令,并在稍后回放。 - 跨平台:使用 平台无关的二进制格式,与 Windows、Linux、Mac 兼容。
- 支持多种设备:可以绘制到 屏幕、SVG、PDF、PS、打印机等 设备上。
- 高效存储:不像
QPixmap
或QImage
存储像素数据,QPicture
仅存储绘图命令,占用的存储空间较小。 - 适用于复杂绘制:在需要 多次重复相同绘制 时,
QPicture
可以减少 绘图计算量,提高效率。
QPicture 的使用
1. 记录绘制命令
使用 QPainter::begin()
让 QPicture
记录绘制命令,使用 end()
停止记录。
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QPicture>
#include <QPushButton>class PictureWidget : public QWidget
{
public:PictureWidget(QWidget *parent = nullptr) : QWidget(parent){setFixedSize(400, 300);// 创建 QPicture 并记录绘制操作QPicture picture;QPainter painter;painter.begin(&picture); // 开始记录绘图命令painter.setPen(Qt::blue);painter.setFont(QFont("Arial", 20));painter.drawText(50, 50, "Hello QPicture");painter.drawRect(100, 100, 200, 100);painter.end(); // 结束记录// 保存到文件picture.save("drawing.dat");}protected:void paintEvent(QPaintEvent *event) override{QPainter painter(this);// 读取 QPicture 并绘制QPicture picture;picture.load("drawing.dat");painter.drawPicture(0, 0, picture);}
};int main(int argc, char *argv[])
{QApplication a(argc, argv);PictureWidget w;w.show();return a.exec();
}
QPicture 使用流程
- 创建
QPicture
对象。 - 使用
QPainter::begin(&picture)
开始记录绘图命令。 - 执行
QPainter
相关绘图操作(如drawText()
、drawLine()
)。 - 使用
QPainter::end()
结束绘制,记录保存。 - 调用
QPicture::save("filename")
保存到文件(可选)。 - 使用
QPicture::load("filename")
重新加载绘图数据。 - 在
paintEvent()
里调用QPainter::drawPicture()
进行绘制。
适用场景
适用情况 | 说明 |
---|---|
重复绘制相同图形 | QPicture 存储的是绘制命令,不占用大量存储空间,提高效率。 |
存储复杂绘图 | 适合用于 矢量图形存储,可以绘制到 屏幕、PDF、SVG、打印机 等不同设备上。 |
减少 CPU 计算 | 直接回放绘图命令,而不是重新计算图形,减少 QPainter 计算量。 |
QPicture
适用于 记录和回放绘图操作,节省资源。QPixmap
适用于 高效屏幕绘制,但不易存储和修改。QImage
适用于 像素级处理和 I/O 读写,可以直接访问像素数据。
如果你需要在 多个设备上显示相同的矢量图形,或者需要 保存绘图过程,QPicture
是一个很好的选择!
文件处理 (File Handling)
QT 提供了一些类来帮助你处理文件读写、文件选择、目录遍历等操作。
- QFile:用来处理文件的基本操作,如打开文件、读取、写入、关闭文件等。
QFile file("example.txt");
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {QTextStream in(&file);QString content = in.readAll();qDebug() << content;file.close();
}
- QFileDialog:用于显示文件对话框,允许用户选择文件或目录。
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Text Files (*.txt)");
if (!fileName.isEmpty()) {// 处理文件
}
- QDir:用于处理目录的操作,如列出目录中的文件、创建目录等。
QDir dir("/path/to/directory");
QStringList files = dir.entryList(QDir::Files);
for (const QString &file : files) {qDebug() << file;
}
总结
- 消息事件机制:通过事件循环和事件处理函数来响应用户输入。
- 绘图:使用
QPainter
、QPixmap
和QGraphicsView
等类绘制图形、文本和图像。 - 文件操作:通过
QFile
、QFileDialog
和QDir
类来处理文件和目录的读写及选择。
这些功能为你在 QT 中开发丰富的 GUI 应用程序提供了强大的支持。