Qt5开发从入门到精通——第六篇三节( 图像与图片——双缓冲机制)

欢迎小伙伴的点评✨✨,相互学习、互关必回、全天在线🍳🍳🍳
博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩‍🚀


前言

本章首先介绍几种主要位置函数及其之间的区别,以及各种与位置相关函数的使用场合;然后,通过一个简单绘图工具实例,介绍利用 QPainter 和 QPainterPath 两种方法绘制各种基础图形。


一、双缓冲机制概述

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

二、效果实例

图一
在这里插入图片描述
图二
在这里插入图片描述


三、原码实例

drawwidget.h

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

class DrawWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DrawWidget(QWidget *parent = nullptr);
    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

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QToolButton>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QToolBar>
#include "drawwidget.h"
#include <QColorDialog>
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

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFont font("ZYSongl8030",12);    //设置字体
    a.setFont(font);
    MainWindow w;
    w.show();

    return a.exec();
}

drawwidget.cpp

#include "drawwidget.h"

DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
    setAutoFillBackground (true);      //对窗体背景色的设置
    setPalette(QPalette(Qt::white));
    pix =new QPixmap (size());         //对此QPixmap对象用于准备随时接收绘制的内容
    pix->fill(Qt::white);             //填充背景色为白色
    setMinimumSize(600,400);          //设置绘制区窗体的最小尺寸

}
void DrawWidget::setStyle(int s)     //setStyle() 函数接收主窗口传来的线型风格参数
{
    style = s;

}
void DrawWidget::setWidth(int w)    //setWidth() 函数接收主窗口传来的线宽参数值
{
    weight = w;
}
void DrawWidget::setColor(QColor c)  //setColor() 函数接收主窗口传来的画笔颜色值
{
    color = c;

}
void DrawWidget::mousePressEvent(QMouseEvent *e) //重定义鼠标按下事件 mousePressEvent() , 在按下鼠标按键时,记录当前的鼠标位置值startPos 。
{
    startPos = e->pos();
}

void DrawWidget::mouseMoveEvent(QMouseEvent *e)
{
    QPainter *painter= new QPainter;   //新建一个 QPainter 对象
    QPen pen;                          //新建一个 QPen 对象
    pen.setStyle((Qt::PenStyle)style);//设置画笔的线型, style 表示当前选择的线型是Qt::PenStyle 枚举数据中的第几个元素。
    pen.setWidth(weight);                 //设置画笔的线宽值
    pen.setColor(color);                  //设置画笔的颜色
    painter->begin(pix);                  
    /*以 QPixmap 对象为 QPaintDevice 参数绘制。在构
造一个 QPainter 对象时,就立即开始对绘画设备进行绘制。此构造 QPainter 对象是短时期的,
如应定义在 QWidget: :paintEvent()中,并只能调用一次。此构造函数调用开始千 begin()函数,并
且在 QPainter 的析构函数中自动调用 end()函数。由于当一个 QPainter 对象的初始化失败时构造函
数不能提供反馈信息,所以在绘制外部设备时应使用 begin()和 end()函数,如打印机等外部设备。*/
    painter->setPen(pen);                 //将 QPen 对象应用到绘制对象中
    //绘制从 startPos 到鼠标当前位置的直线
    painter->drawLine (startPos, e->pos ());
    painter->end();
    startPos=e->pos();                   //更新鼠标的当前位置,为下次绘制做准备
    update();                            //重绘绘制区窗体


}
void DrawWidget::paintEvent(QPaintEvent *)  //重绘函数 paintEventO完成绘制区窗体的更新工作,只需调用 drawPixmap()函数将用千接收
                                           //图形绘制的 QPixmap 对象绘制在绘制区窗体控件上即可。
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0,0),*pix);
}
void DrawWidget::resizeEvent(QResizeEvent *event)
{
    if(height()>pix->height()||width()>pix->width())  //判断改变后的窗体长或宽是否大于原窗体的长和宽 。 
                                                      //若大于则进行相应的调整,否则直接调用 QWidget 的 resizeEvent()函数返回。
    {
        QPixmap *newPix = new QPixmap (size());   //创建一个新的 QPixmap 对象
        newPix->fill(Qt::white);     //填充新 QPixmap 对象 newPix 的颜色为白色背景色
        QPainter p(newPix);
        p.drawPixmap(QPoint(0,0),*pix);  //在 newPix 中绘制原 pix 中的内容
        pix = newPix;                    //将 newPix 赋值给 pix 作为新的绘制图形接收对象

    }
    QWidget::resizeEvent(event);        ///完成其余的工作
}
void DrawWidget::clear()      //clear() 函数完成绘制区的清除工作,只需调用一个新的、
                             //干净的 QPixmap 对象来代替 pix,并调用 update()函数重绘即可
{
    QPixmap *clearPix =new QPixmap (size());
    clearPix->fill (Qt::white);
    pix= clearPix;
    update();
}

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    drawWidget =new DrawWidget; //新建一个 DrawWidget 对象
    setCentralWidget(drawWidget); //新建的 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("SolidLine"),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()),this,SLOT(ShowColor()));
    clearBtn =new QToolButton();               //创建“清除”按钮
    clearBtn->setText(tr("清除"));
    connect(clearBtn,SIGNAL(clicked()),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);
    ///使用标准颜色对话框 QColorDialog 获得一个颜色值
    if(color.isValid())
    {
        ///将新选择的颜色传给绘制区,用千改变画笔的颜色值
        drawWidget->setColor(color);
        QPixmap p(20,20);
        p. fill (color);
        colorBtn->setIcon(QIcon(p));    //更新颜色选择按钮上的颜色显示
    }
}

四、总结

图像与图片的双缓冲机制会在应用程序开发中经常用到的

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东.'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值