QT_绘图原理双缓冲机制

QT 绘图原理与双缓冲机制


文章目录

  • [QT 绘图原理与双缓冲机制](#QT 绘图原理与双缓冲机制)
    • [一、Qt 窗口 API 基础知识](#一、Qt 窗口 API 基础知识)
      • [1.1 窗口显示与关闭](#1.1 窗口显示与关闭)
      • [1.2 窗口尺寸](#1.2 窗口尺寸)
      • [1.3 窗口位置](#1.3 窗口位置)
      • [1.4 窗口标题与图标](#1.4 窗口标题与图标)
      • [1.5 窗口标志与状态](#1.5 窗口标志与状态)
      • [1.6 窗口刷新](#1.6 窗口刷新)
      • [1.7 父子关系](#1.7 父子关系)
      • [1.8 常用事件处理函数](#1.8 常用事件处理函数)
      • [1.9 对象名称与属性](#1.9 对象名称与属性)
      • [1.10 案例:窗口 API 位置函数测试](#1.10 案例:窗口 API 位置函数测试)
    • [二、Qt 绘图框架设计(QPainter 绘图)](#二、Qt 绘图框架设计(QPainter 绘图))
      • [2.1 案例:QPainter 基本形状绘制](#2.1 案例:QPainter 基本形状绘制)
    • [三、Qt 双缓冲机制](#三、Qt 双缓冲机制)
      • [3.1 传统绘制(单缓冲)的问题](#3.1 传统绘制(单缓冲)的问题)
      • [3.2 双缓冲的解决方案](#3.2 双缓冲的解决方案)
      • [3.3 案例:手绘板双缓冲实现](#3.3 案例:手绘板双缓冲实现)
    • 小结

一、Qt 窗口 API 基础知识

Qt 中所有可视控件均继承自 QWidget,因此以下 API 对 QWidgetQDialogQMainWindow 等窗口类均适用。

1.1 窗口显示与关闭

方法 说明
show() 以非模态方式显示窗口
hide() 隐藏窗口
close() 关闭窗口(触发 closeEvent
exec() 以模态方式显示对话框(阻塞调用,仅 QDialog 可用)
open() 以非模态方式显示对话框(不阻塞)
isVisible() 判断窗口是否可见
setModal(bool) 设置是否模态(仅 QDialog
setWindowModality(Qt::WindowModal) 设置模态级别

1.2 窗口尺寸

方法 说明
resize(w, h) 设置窗口大小(用户可通过拖拽改变)
setFixedSize(w, h) 设置固定大小(禁止拖拽改变)
setMinimumSize(w, h) 设置最小尺寸
setMaximumSize(w, h) 设置最大尺寸
size() 获取当前尺寸,返回 QSize
width() / height() 获取宽度 / 高度
setGeometry(x, y, w, h) 同时设置位置和大小

1.3 窗口位置

方法 说明
move(x, y) 移动窗口到指定坐标
pos() 获取窗口位置,返回 QPoint
x() / y() 获取窗口左上角坐标
frameGeometry() 获取包含边框的完整几何信息
geometry() 获取客户区几何信息(不含边框)

1.4 窗口标题与图标

方法 说明
setWindowTitle("标题") 设置窗口标题
windowTitle() 获取窗口标题
setWindowIcon(QIcon("图标路径")) 设置窗口图标

1.5 窗口标志与状态

方法 说明
setWindowFlags(Qt::FramelessWindowHint) 去掉窗口边框
setWindowFlags(Qt::WindowStaysOnTopHint) 窗口置顶
setWindowOpacity(0.5) 设置窗口透明度(0.0 ~ 1.0)
showFullScreen() 全屏显示
showMaximized() 最大化显示
showMinimized() 最小化显示
showNormal() 恢复普通显示
isMaximized() 判断是否已最大化
isMinimized() 判断是否已最小化
isFullScreen() 判断是否已全屏

1.6 窗口刷新

方法 说明
update() 请求重绘,自动合并多次调用,推荐使用
repaint() 立即强制重绘(不经过事件队列,慎用)
updateGeometry() 通知布局系统重新计算控件几何

1.7 父子关系

方法 说明
setParent(parent) 设置父控件
parent() 获取父控件
findChild<T*>("objectName") 按对象名称查找子控件
findChildren<T*>() 查找所有匹配类型的子控件

说明: 子控件的坐标相对于父控件;父控件移动时子控件跟随移动;父控件销毁时子控件自动销毁。

1.8 常用事件处理函数

虚函数 触发时机
paintEvent(QPaintEvent *) 需要重绘时
resizeEvent(QResizeEvent *) 窗口大小改变时
closeEvent(QCloseEvent *) 窗口关闭时
mousePressEvent(QMouseEvent *) 鼠标按下时
mouseMoveEvent(QMouseEvent *) 鼠标移动时
mouseReleaseEvent(QMouseEvent *) 鼠标释放时
keyPressEvent(QKeyEvent *) 键盘按下时
keyReleaseEvent(QKeyEvent *) 键盘释放时
enterEvent(QEvent *) 鼠标进入控件时
leaveEvent(QEvent *) 鼠标离开控件时
focusInEvent(QFocusEvent *) 获得焦点时
focusOutEvent(QFocusEvent *) 失去焦点时

1.9 对象名称与属性

方法 说明
setObjectName("名称") 设置对象名称(可供 findChild 查找)
objectName() 获取对象名称
setProperty("属性名", 值) 动态设置属性(可用于样式表选择器)
property("属性名") 获取属性值
setEnabled(bool) 启用 / 禁用控件
setVisible(bool) 设置可见性

1.10 案例:窗口 API 位置函数测试

dialog.h

cpp 复制代码
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QLabel>
#include <QGridLayout>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

private:
    QGridLayout *glayout;

    QLabel *labelgeometry;
    QLabel *labelgeometryvalue;
    QLabel *labelwidth;
    QLabel *labelwidthvalue;
    QLabel *labelheight;
    QLabel *labelheightvalue;
    QLabel *labelrect;
    QLabel *labelrectvalue;
    QLabel *labelsize;
    QLabel *labelsizevalue;

    // 窗口大小变化事件
    void resizeEvent(QResizeEvent *);
    // 窗口移动事件
    void moveEvent(QMoveEvent *);

public:
    // 更新各 Label 显示值
    void UpdateLabelFunc();
};

#endif // DIALOG_H

dialog.cpp

cpp 复制代码
#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(300, 160);
    setWindowTitle("Qt窗口常用的API位置函数测试");

    glayout = new QGridLayout(this);

    labelgeometry      = new QLabel("函数geometry():");
    labelgeometryvalue = new QLabel;

    labelwidth      = new QLabel("函数width():");
    labelwidthvalue = new QLabel;

    labelheight      = new QLabel("函数height():");
    labelheightvalue = new QLabel;

    labelrect      = new QLabel("函数rect():");
    labelrectvalue = new QLabel;

    labelsize      = new QLabel("函数size():");
    labelsizevalue = new QLabel;

    glayout->addWidget(labelgeometry,      0, 0);
    glayout->addWidget(labelgeometryvalue, 0, 1);
    glayout->addWidget(labelwidth,         1, 0);
    glayout->addWidget(labelwidthvalue,    1, 1);
    glayout->addWidget(labelheight,        2, 0);
    glayout->addWidget(labelheightvalue,   2, 1);
    glayout->addWidget(labelrect,          3, 0);
    glayout->addWidget(labelrectvalue,     3, 1);
    glayout->addWidget(labelsize,          4, 0);
    glayout->addWidget(labelsizevalue,     4, 1);

    UpdateLabelFunc();
}

Dialog::~Dialog()
{
}

// 窗口大小变化时刷新 Label 显示
void Dialog::resizeEvent(QResizeEvent *)
{
    UpdateLabelFunc();
}

// 窗口移动时刷新 Label 显示
void Dialog::moveEvent(QMoveEvent *)
{
    UpdateLabelFunc();
}

// 更新所有 Label 的值
void Dialog::UpdateLabelFunc()
{
    // geometry() 返回相对父窗口的 x, y, width, height
    QString strGeom;
    QString s1, s2, s3, s4;
    strGeom = s1.setNum(geometry().x()) + ","
            + s2.setNum(geometry().y()) + ","
            + s3.setNum(geometry().width()) + ","
            + s4.setNum(geometry().height());
    labelgeometryvalue->setText(strGeom);

    // width() / height()
    QString strW, strH;
    labelwidthvalue->setText(strW.setNum(width()));
    labelheightvalue->setText(strH.setNum(height()));

    // rect() 始终从 (0,0) 开始,表示客户区矩形
    QString strRect;
    QString r1, r2, r3, r4;
    strRect = r1.setNum(rect().x()) + ","
            + r2.setNum(rect().y()) + ","
            + r3.setNum(rect().width()) + ","
            + r4.setNum(rect().height());
    labelrectvalue->setText(strRect);

    // size() 返回客户区宽高
    QString strSize;
    QString sz1, sz2;
    strSize = sz1.setNum(size().width()) + ","
            + sz2.setNum(size().height());
    labelsizevalue->setText(strSize);
}

二、Qt 绘图框架设计(QPainter 绘图)

Qt 的绘图系统是一套成熟、跨平台的二维图形渲染体系,核心围绕 QPainter / QPaintDevice / QPaintEngine 三层架构展开。以下从架构设计、核心机制、坐标系统、性能优化等维度进行系统梳理。

2.1 案例:QPainter 基本形状绘制

painterarea.h

cpp 复制代码
#ifndef PAINTERAREA_H
#define PAINTERAREA_H

#include <QWidget>
#include <QPen>      // 画笔:绘制直线、曲线、多边形轮廓
#include <QBrush>    // 画刷:填充矩形、多边形等形状内部
#include <QPainter>

class PainterArea : public QWidget
{
    Q_OBJECT

public:
    explicit PainterArea(QWidget *parent = nullptr);

    // 可绘制形状枚举
    enum shape {
        Line,       // 直线
        Rectangle,  // 矩形
        RoundRect,  // 圆角矩形
        Ellipse,    // 椭圆
        Polygon,    // 多边形
        Polyline,   // 折线(不闭合)
        Arc,        // 弧线
        Chord,      // 弦
        Pie,        // 扇形
        Path        // 自定义路径
    };

    void setShape(shape);
    void setPen(QPen);
    void setBrush(QBrush);
    void setFillRule(Qt::FillRule); // 设置填充规则

protected:
    void paintEvent(QPaintEvent *) override; // 重绘事件

signals:

public slots:

private:
    shape        shp;
    QPen         pen;
    QBrush       brsh;
    Qt::FillRule fillrle;
};

#endif // PAINTERAREA_H

painterarea.cpp

cpp 复制代码
#include "painterarea.h"

PainterArea::PainterArea(QWidget *parent)
    : QWidget(parent)
{
    setPalette(QPalette(Qt::white));
    setAutoFillBackground(true);
    setMinimumSize(410, 410);
}

void PainterArea::setShape(shape sh)
{
    shp = sh;
    update(); // 请求重绘
}

void PainterArea::setPen(QPen sh)
{
    pen = sh;
    update();
}

void PainterArea::setBrush(QBrush sh)
{
    brsh = sh;
    update();
}

void PainterArea::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.setPen(pen);
    p.setBrush(brsh);

    QRect rect(55, 110, 290, 180);

    switch (shp) {
    case Line:
        p.drawLine(rect.topLeft(), rect.bottomRight());
        break;

    case Rectangle:
        p.drawRect(rect);
        break;

    case RoundRect:
        p.drawRoundedRect(rect, 25, 25);  // 圆角半径 25px
        break;

    case Ellipse:
        p.drawEllipse(rect);
        break;

    case Polygon: {
        QPolygon polygon;
        polygon << QPoint(200, 110)
                << QPoint(345, 200)
                << QPoint(290, 290)
                << QPoint(110, 290)
                << QPoint(55, 200);
        p.drawPolygon(polygon);
        break;
    }

    case Polyline: {
        QPolygon polyline;
        polyline << QPoint(55, 290)
                 << QPoint(130, 110)
                 << QPoint(200, 250)
                 << QPoint(270, 110)
                 << QPoint(345, 290);
        p.drawPolyline(polyline);
        break;
    }

    case Arc:
        // 起始角 0°,跨度 270°(Qt 角度单位为 1/16 度)
        p.drawArc(rect, 0 * 16, 270 * 16);
        break;

    case Chord:
        p.drawChord(rect, 0 * 16, 270 * 16);
        break;

    case Pie:
        p.drawPie(rect, 0 * 16, 270 * 16);
        break;

    case Path: {
        QPainterPath path;
        path.moveTo(55, 200);
        path.cubicTo(130, 110, 270, 290, 345, 200);  // 三次贝塞尔曲线
        p.drawPath(path);
        break;
    }

    default:
        break;
    }
}

void PainterArea::setFillRule(Qt::FillRule rle)
{
    fillrle = rle;
    update();
}

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QComboBox>
#include <QGridLayout>
#include <QColorDialog>
#include "painterarea.h"

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    PainterArea *labelshapeArea;
    QLabel      *labelshape;
    QComboBox   *comboxboxshape;
    QGridLayout *glayout;

private slots:
    void dispShapeFunc(int);
};

#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    labelshapeArea = new PainterArea;
    labelshapeArea->setPen(QPen(Qt::blue, 4));

    glayout = new QGridLayout;

    setWindowTitle("Qt绘图框架测试 --- QPainter类");

    labelshape     = new QLabel("绘制形状:");
    comboxboxshape = new QComboBox;

    comboxboxshape->addItem("Line",      PainterArea::Line);
    comboxboxshape->addItem("Rectangle", PainterArea::Rectangle);
    comboxboxshape->addItem("RoundRect", PainterArea::RoundRect);
    comboxboxshape->addItem("Ellipse",   PainterArea::Ellipse);
    comboxboxshape->addItem("Polygon",   PainterArea::Polygon);
    comboxboxshape->addItem("Polyline",  PainterArea::Polyline);
    comboxboxshape->addItem("Arc",       PainterArea::Arc);
    comboxboxshape->addItem("Chord",     PainterArea::Chord);
    comboxboxshape->addItem("Pie",       PainterArea::Pie);
    comboxboxshape->addItem("Path",      PainterArea::Path);

    connect(comboxboxshape, SIGNAL(currentIndexChanged(int)),
            this,           SLOT(dispShapeFunc(int)));

    // 启动时默认选择 Line
    dispShapeFunc(0);

    glayout->addWidget(labelshape,     0, 0);
    glayout->addWidget(comboxboxshape, 0, 1);

    QHBoxLayout *mainlayout = new QHBoxLayout(this);
    mainlayout->addWidget(labelshapeArea);
    mainlayout->addLayout(glayout);
}

Widget::~Widget()
{
}

void Widget::dispShapeFunc(int v)
{
    PainterArea::shape sp = PainterArea::shape(
        comboxboxshape->itemData(v, Qt::UserRole).toInt());
    labelshapeArea->setShape(sp);
}

三、Qt 双缓冲机制

核心思想: "先在图片上画,再贴到控件上。"

3.1 传统绘制(单缓冲)的问题

如果直接在屏幕控件上绘图,当图形复杂或刷新频率较高时,人眼可能会看到绘制的中间过程------比如先画了一条线,再画一个圆,再填充颜色------这会导致画面闪烁,体验很差。

3.2 双缓冲的解决方案

步骤一:后台绘制(Off-Screen Buffer)

先在内存中创建一个不可见的"图片"(离屏缓冲区 / Buffer Image)。所有的绘图操作(画线、填充颜色等)都在这张内存图片上完成。因为是在内存中操作,速度极快,且用户完全看不见中间过程。

步骤二:前台显示(Flip / Blit)

待所有复杂的绘制工作在内存图片上全部完成后,再一次性将这张完整图片"复制"(绘制)到屏幕上的控件中。用户看到的始终是完整的最终结果,从而彻底消除闪烁。

3.3 案例:手绘板双缓冲实现

drawwidget.h

cpp 复制代码
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H

#include <QWidget>
#include <QtGui>
#include <QMouseEvent>   // 鼠标事件
#include <QPaintEvent>   // 绘制事件
#include <QResizeEvent>  // 窗口尺寸变化事件
#include <QColor>
#include <QPixmap>       // 离屏画布(双缓冲核心)
#include <QPainter>      // 绘图引擎
#include <QPalette>
#include <QPen>

class DrawWidget : public QWidget
{
    Q_OBJECT

public:
    explicit DrawWidget(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *) override;
    void mouseMoveEvent(QMouseEvent *)  override;
    void paintEvent(QPaintEvent *)      override;
    void resizeEvent(QResizeEvent *)    override;

public slots:
    void setStyle(int s);        // 设置画笔线型风格
    void setWidth(int w);        // 设置画笔线宽
    void setColor(QColor c);     // 设置画笔颜色
    void clearFunc();            // 清除画布

signals:

private:
    QPixmap *pix;        // 离屏画布(双缓冲缓冲区)
    QPoint   startPos;   // 线段起点
    QPoint   endPos;     // 线段终点
    int      style;      // 线型
    int      widthss;    // 线宽
    QColor   color;      // 颜色
};

#endif // DRAWWIDGET_H

drawwidget.cpp

cpp 复制代码
#include "drawwidget.h"

// 构造函数:初始化画板控件
DrawWidget::DrawWidget(QWidget *parent)
    : QWidget(parent)
{
    setAutoFillBackground(true);      // 允许自动填充背景色
    setPalette(QPalette(Qt::white));  // 设置背景色为白色

    // 创建与控件等大的离屏画布(双缓冲关键:后续所有绘制先画到这里)
    pix = new QPixmap(size());
    pix->fill(Qt::white);            // 初始填充白色背景

    // 初始化绘图参数
    style   = Qt::SolidLine;         // 默认线型:实线
    widthss = 2;                     // 默认线宽:2px
    color   = Qt::black;             // 默认颜色:黑色

    setMinimumSize(600, 400);
}

// 设置画笔线型风格
void DrawWidget::setStyle(int s)
{
    style = s;
}

// 设置画笔线宽
void DrawWidget::setWidth(int w)
{
    widthss = w;
}

// 设置画笔颜色
void DrawWidget::setColor(QColor c)
{
    color = c;
}

// 清除画布:重新创建空白离屏缓冲区
void DrawWidget::clearFunc()
{
    QPixmap *cPix = new QPixmap(size());
    cPix->fill(Qt::white);
    pix = cPix;       // 替换为新画布
    update();         // 触发 paintEvent 刷新界面
}

// 鼠标按下:记录起始点
void DrawWidget::mousePressEvent(QMouseEvent *e)
{
    startPos = e->pos();
}

// 鼠标移动:在离屏画布上绘制线段(双缓冲第一步)
void DrawWidget::mouseMoveEvent(QMouseEvent *e)
{
    QPainter painter;
    QPen     pen;

    pen.setStyle((Qt::PenStyle)style);
    pen.setWidth(widthss);
    pen.setColor(color);

    painter.begin(pix);                           // 在离屏画布 pix 上开始绘制
    painter.setPen(pen);
    painter.drawLine(startPos, e->pos());         // 从上一个点到当前鼠标位置画线
    painter.end();                                // 结束绘制

    startPos = e->pos();                          // 更新起点,保证下一段线首尾相连
    update();                                     // 触发 paintEvent,将离屏画布刷新到屏幕
}

// 绘制事件:将离屏画布一次性贴到控件上(双缓冲第二步)
void DrawWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0, 0), *pix);       // 整张图片一次贴出,彻底消除闪烁
}

// 窗口尺寸改变:扩展画布并保留已有内容
void DrawWidget::resizeEvent(QResizeEvent *event)
{
    // 仅当窗口比当前画布大时才需要重建
    if (height() > pix->height() || width() > pix->width()) {
        QPixmap *newPix = new QPixmap(size());    // 创建新尺寸的画布
        newPix->fill(Qt::white);                  // 填充白色背景

        QPainter ps(newPix);
        ps.drawPixmap(QPoint(0, 0), *pix);        // 将旧画布内容复制到新画布上

        pix = newPix;                             // 替换为新画布
    }

    QWidget::resizeEvent(event);                  // 调用父类方法,保证正常行为
}

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QComboBox>
#include <QToolBar>
#include <QToolButton>
#include <QSpinBox>
#include <QGridLayout>
#include <QColorDialog>
#include "drawwidget.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    void CreateToolBarFunc();

    QGridLayout *glayout;
    DrawWidget  *drawWidget;

    QLabel    *labelstyle;
    QComboBox *comboboxstyle;
    QLabel    *labelwidth;
    QSpinBox  *spinboxlabelwidth;
    QToolButton *colorbutton;
    QToolButton *clearbutton;

private slots:
    void dispstyle();
    void dispcolor();
};

#endif // MAINWINDOW_H

mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle("图形绘制 --- 双缓冲机制");
    drawWidget = new DrawWidget;
    setCentralWidget(drawWidget);
    CreateToolBarFunc();

    setMinimumSize(600, 400);

    dispstyle();
    drawWidget->setWidth(spinboxlabelwidth->value());  // 初始化线宽
    drawWidget->setColor(Qt::blue);                    // 初始化颜色
}

MainWindow::~MainWindow()
{
}

void MainWindow::CreateToolBarFunc()
{
    QToolBar *toolBar = addToolBar("Tool");

    // 线型选择
    labelstyle     = new QLabel("线型风格:");
    comboboxstyle  = new QComboBox;
    comboboxstyle->addItem("SolidLine", static_cast<int>(Qt::SolidLine));
    comboboxstyle->addItem("DotLine",   static_cast<int>(Qt::DotLine));
    connect(comboboxstyle, SIGNAL(activated(int)), this, SLOT(dispstyle()));

    // 线宽选择
    labelwidth         = new QLabel("线型宽度:");
    spinboxlabelwidth  = new QSpinBox;
    connect(spinboxlabelwidth, SIGNAL(valueChanged(int)),
            drawWidget,        SLOT(setWidth(int)));

    // 颜色选择按钮
    colorbutton = new QToolButton;
    QPixmap pixmap(20, 20);
    pixmap.fill(Qt::blue);               // 与初始化颜色一致
    colorbutton->setIcon(QIcon(pixmap));
    colorbutton->setToolTip("选择颜色");
    connect(colorbutton, SIGNAL(clicked()), this, SLOT(dispcolor()));

    // 清除按钮
    clearbutton = new QToolButton;
    clearbutton->setText("清除绘制");
    connect(clearbutton, SIGNAL(clicked()), drawWidget, SLOT(clearFunc()));

    // 加入工具栏
    toolBar->addWidget(labelstyle);
    toolBar->addWidget(comboboxstyle);
    toolBar->addWidget(labelwidth);
    toolBar->addWidget(spinboxlabelwidth);
    toolBar->addWidget(colorbutton);
    toolBar->addWidget(clearbutton);
}

void MainWindow::dispstyle()
{
    drawWidget->setStyle(
        comboboxstyle->itemData(comboboxstyle->currentIndex(),
                                Qt::UserRole).toInt());
}

void MainWindow::dispcolor()
{
    QColor color = QColorDialog::getColor(static_cast<int>(Qt::black), this);
    if (color.isValid()) {
        drawWidget->setColor(color);

        // 同步更新颜色按钮图标
        QPixmap ps(20, 20);
        ps.fill(color);
        colorbutton->setIcon(QIcon(ps));
    }
}

小结

本文从 Qt 窗口 API 基础出发,逐步深入到 QPainter 绘图框架,最后通过手绘板案例完整演示了双缓冲机制的设计与实现。核心要点回顾:

  1. Qt 窗口 APIQWidget 为基类,提供了显示、尺寸、位置、事件处理等完整的方法体系
  2. QPainter 绘图框架 基于 QPainter / QPaintDevice / QPaintEngine 三层架构,支持直线、矩形、椭圆、多边形、贝塞尔曲线等多种形状
  3. 双缓冲机制 通过 QPixmap 离屏画布先完成所有绘制操作,再一次性贴到屏幕------避免了逐笔绘制导致的闪烁问题
相关推荐
想要入门的程序猿1 小时前
Qt插件QPluginLoader
开发语言·qt
一条闲鱼_mytube2 小时前
深入理解 Pinecone 向量数据库:从云服务到索引原理,一篇讲透
数据库
许彰午2 小时前
政务低代码平台实战⑤:双输出模式——存DB与导出JSP的完整链路
数据库·低代码·政务
南京码讯光电技术有限公司2 小时前
What Does Ex tb IIIC T80°C Db Mean?
服务器·网络·数据库
长江&后浪2 小时前
华为wlan实验-三层旁挂
运维·服务器·网络·华为
xiaoxiangsiyan3 小时前
机房交换机交换技术与服务器链路聚合深度指南
运维·服务器·网络·学习·自动化·bond
大白同学4213 小时前
初始Qt——了解Qt背景
开发语言·qt
GoKu~3 小时前
Qt图形渲染相关例子
qt
2501_937860943 小时前
MySQL CRUD 增删改查
数据库·mysql