zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt双缓冲机制

Qt 机制 缓冲
2023-09-14 09:05:11 时间

所谓双缓冲机制,是指在绘制控件时,首先将要绘制的内容绘制在一个图片中,再将图片一次性绘制到控件上。在早期的Qt版本中,若直接在控件上进行绘制工作,则在控件重绘时会产生闪烁的现象,控件重绘频繁时,闪烁尤为明显。双缓冲机制可以有效地消除这种闪烁现象。自Qt 5版本之后,​​QWidget​​控件已经能够自动处理闪烁的问题。因此,在控件上直接绘图时,不用再操心显示的闪烁问题,但双缓冲机制在很多场合仍然有其用武之地。当所需绘制的内容较复杂并需要频繁刷新,或者每次只需要刷新整个控件的一小部分时,仍应尽量采用双缓冲机制。

下面通过一个实例来演示双缓冲机制:

1、运行结果

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓ 

2、具体代码

​​drawwidget.h​​

#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H

#include <QWidget>
#include <QtGui>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QColor>
#include <QPixmap>
#include <QPoint>
#include <QPainter>
#include <QPalette>

class DrawWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DrawWidget(QWidget *parent = 0);
    void mousePressEvent(QMouseEvent *);  //重写鼠标按下事件
    void mouseMoveEvent(QMouseEvent *);   //重写鼠标移动事件
    void paintEvent(QPaintEvent *);       //重写绘图事件
    void resizeEvent(QResizeEvent *);     //重写窗体大小变化事件

signals:

public slots:
    void setStyle(int);
    void setWidth(int);
    void setColor(QColor);
    void clear();

private:
    QPixmap *pix;
    QPoint startPos;
    QPoint endPos;
    int style;
    int weight;
    QColor color;
};

#endif // DRAWWIDGET_H

​​drawwidget.cpp​​

#include "drawwidget.h"
#include <QtGui>
#include <QPen>

DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
    setAutoFillBackground(true);
    setPalette(QPalette(Qt::white));
    pix = new QPixmap(size());  //获取当前窗体的大小新建一个QPixmap对象
    pix->fill(Qt::white);       //将其填充为白色
    setMinimumSize(60,400);     //设置窗体的最小值
}

void DrawWidget::setStyle(int s)
{
    style = s;
}

void DrawWidget::setWidth(int w)
{
    weight = w;
}

void DrawWidget::setColor(QColor c)
{
    color = c;
}

void DrawWidget::mousePressEvent(QMouseEvent *event)
{
    startPos = event->pos();
}

void DrawWidget::mouseMoveEvent(QMouseEvent *event)  //注(1)
{
    QPainter *painter = new QPainter;
    QPen pen;
    pen.setStyle((Qt::PenStyle)style);
    pen.setWidth(weight);
    pen.setColor(color);
    painter->begin(pix);  //注(2)
    painter->setPen(pen);
    painter->drawLine(startPos,event->pos());
    painter->end();
    startPos = event->pos();
    update();
}

void DrawWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0,0),*pix);
}

void DrawWidget::resizeEvent(QResizeEvent *evnet)  //注(3)
{
    if(height() > pix->height() || width() > pix->width())
    {
        QPixmap *newPix = new QPixmap(size());  //创建一个新的QPixmap对象
        newPix->fill(Qt::white);  //填充QPixmap对象newPix的颜色为白色背景色
        QPainter painter(newPix);
        painter.drawPixmap(QPoint(0,0),*pix);  //在newPix中绘制原pix中的内容
        pix = newPix;  //将newPix赋值给pix作为新的绘制图形接收对象
    }
    QWidget::resizeEvent(evnet);  //完成其余的工作
}

void DrawWidget::clear()  //以当前窗口大小创建一个QPixmap对象,然后更新pix,重绘
{
    QPixmap *clearPix = new QPixmap(size());
    clearPix->fill(Qt::white);
    pix = clearPix;
    update();
}

注:以上类是继承至QWidget,将其设为QMainWindow的中心区域作为画板

注(1):重定义鼠标移动事件​​mouseMoveEvent()​​​,鼠标移动事件在默认情况下,在鼠标按键被按下的同时拖拽鼠标时被触发。QWidget的​​mouseTracking​​​属性指示是否追踪鼠标,默认为false(不追踪),即在至少有一个鼠标按键被按下的前提下移动鼠标才触发​​mouseMoveEvent()​​​事件,可以通过​​setMouseTracking(bool enable)​​​方法对该属性值进行设置。如果设置为追踪,则无论鼠标按键是否按下,只要鼠标移动,就会触发​​mouseMoveEvent()​​事件。

注(2):​​painter->begin(pix)、painter->end()​​​:以QPixmap对象为QPaintDevice参数绘制。在构造一个QPainter对象时,就立即开始对绘画设置进行绘制。此构造QPainter对象是短时期的,如应定义在​​QWidget::paintEvent()​​​中,并只能调用一次。此构造函数调用开始与​​begin()​​​函数,并且在QPainter的析构函数中自动调用​​end()​​​函数。由于当一个QPainter对象的初始化失败是构造函数不能提供反馈信息,所以在绘制外部设备时应使用​​begin()​​​和​​end()​​函数,如打印机等外部设备。

下面是使用​​begin()​​​和​​end()​​的一个例子

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p;
    p.begin(this);
    p.drawLine(...);
    p.end();
}

类似于下面的形式:

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);    
    p.drawLine(...);
}

注(3):调整绘制区大小函数​​resizeEvent()​​,当窗体的大小发送改变是,效果看起来虽然像是绘制区大小改变了,但实际能够进行绘制的区域仍然没有改变。因为绘图的大小并没有改变,还是原来绘制区窗体的大小,所以在窗体尺寸改变时应及时调整用于绘制的QPixmap对象的大小。

​​mainwindow.h​​

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void createToolBar();

public slots:
    void ShowStyle();
    void ShowColor();

private:
    DrawWidget *drawWidget;
    QLabel *styleLabel;
    QComboBox *styleComboBox;
    QLabel *widthLabel;
    QSpinBox *widthSpinBox;
    QToolButton *colorBtn;
    QToolButton *clearBtn;
};

#endif // MAINWINDOW_H

​​mainwindow.cpp​​

#include "mainwindow.h"
#include <QToolBar>
#include <QColorDialog>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    drawWidget = new DrawWidget;
    setCentralWidget(drawWidget);
    createToolBar();
    setMinimumSize(600,400);
    ShowStyle();
    drawWidget->setWidth(widthSpinBox->value());
    drawWidget->setColor(Qt::black);
}

MainWindow::~MainWindow()
{

}

void MainWindow::createToolBar()
{
    QToolBar *toolBar = addToolBar("Tool");
    styleLabel = new QLabel(tr("线型风格"));
    styleComboBox = new QComboBox;
    styleComboBox->addItem(tr("SolodLine"),static_cast<int>(Qt::SolidLine));
    styleComboBox->addItem(tr("DashLine"),static_cast<int>(Qt::DashLine));
    styleComboBox->addItem(tr("DotLine"),static_cast<int>(Qt::DotLine));
    styleComboBox->addItem(tr("DashDotLine"),static_cast<int>(Qt::DashDotLine));
    styleComboBox->addItem(tr("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));
    connect(styleComboBox,SIGNAL(activated(int)),this,SLOT(ShowStyle()));
    widthLabel = new QLabel(tr("线宽"));
    widthSpinBox = new QSpinBox;
    connect(widthSpinBox,SIGNAL(valueChanged(int)),drawWidget,SLOT(setWidth(int)));
    colorBtn = new QToolButton;
    QPixmap pixmap(20,20);
    pixmap.fill(Qt::black);
    colorBtn->setIcon(QIcon(pixmap));
    connect(colorBtn,SIGNAL(clicked(bool)),this,SLOT(ShowColor()));
    clearBtn = new QToolButton();
    clearBtn->setText(tr("清除"));
    connect(clearBtn,SIGNAL(clicked(bool)),drawWidget,SLOT(clear()));
    toolBar->addWidget(styleLabel);
    toolBar->addWidget(styleComboBox);
    toolBar->addWidget(widthLabel);
    toolBar->addWidget(widthSpinBox);
    toolBar->addWidget(colorBtn);
    toolBar->addWidget(clearBtn);
}

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

void MainWindow::ShowColor()
{
    QColor color = QColorDialog::getColor(static_cast<int>(Qt::black),this);
    if(color.isValid())
    {
        drawWidget->setColor(color);
        QPixmap p(20,20);
        p.fill(color);
        colorBtn->setIcon(QIcon(p));
    }
}

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓