Qt5 双缓冲机制

1.所谓双缓冲机制,即在绘制控件时,首先要将绘制的内容绘制在一个图片上,再将图片一次性绘制到控件上。

DrawWidget.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H

#include <QWidget>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QColor>
#include <QPixmap>
#include <QPoint>
#include <QPainter>
#include <QPalette>
#include <QtGui>
class DrawWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DrawWidget(QWidget *parent = nullptr);

signals:
public:
     void  mousePressEvent(QMouseEvent *); //鼠标按压和移动
     void  mouseMoveEvent(QMouseEvent *);

     void paintEvent(QPaintEvent *); //重画事件
     void resizeEvent(QResizeEvent *);  //尺寸变化事件

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

     void setWidth(int);
     void clear();

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

#endif // DRAWWIDGET_H

.cpp

#include "drawwidget.h"
#include <QtGui>
#include <QPen>
#include <QWidget>
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::mousePressEvent(QMouseEvent* e)
{
    startPos = e->pos();  //当按下鼠标时,记录当前鼠标位置值startPos
}

//鼠标移动事件在默认情况下,在鼠标按下的同时拖曳鼠标时被出发
void DrawWidget::mouseMoveEvent(QMouseEvent *e)
{
    QPainter *painter=new QPainter;
    QPen pen;
    pen.setStyle((Qt::PenStyle)style);  //设置画笔的线型,style表示当前选择的线型是Qt::PenStyle枚举数据中的第几个元素
    pen.setColor(color);
    pen.setWidth(weight);

    painter->begin(pix);
    painter->setPen(pen);
    painter->drawLine(startPos,e->pos());//绘制从 startPos到鼠标当前位置的直线
    painter->end();
    startPos =e->pos();
    update();
}

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

//用于调控绘制去的大小。当窗体的大小发生改变时,效果看起来虽然像是绘制区大小改变了,
//但实际能够进行绘制的区域仍然没有改变,还是原来绘制区窗口的大小,
//所以在窗体尺寸变化时应及时调整用于绘制的QPixmap对象尺寸的大小
void DrawWidget::resizeEvent(QResizeEvent *event)
{
    if(height()>pix->height()||width()>pix->width())
    {
        QPixmap *newPix=new QPixmap(size()); //创建一个新的QPixmap对象
        newPix->fill(Qt::white);
        QPainter p(this);
        p.drawPixmap(QPoint(0,0),*pix); //在newPix中绘制原pix中的内容
        pix=newPix;                     //将newPix赋给pix 作为新的绘制图形接收的对象
    }

   QWidget::resizeEvent(event);  //完成其余工作
}


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

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

void DrawWidget::setWidth(int w)
{

    weight = w;
}

void DrawWidget::clear()
{
    QPixmap *clearPix=new QPixmap(size());
    clearPix->fill(Qt::white);
    pix=clearPix;
    update(); //使用update进行重绘
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QToolButton>
#include <QPushButton>
#include "drawwidget.h"
class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void   handleEvents();// 信号与槽处理
    void  createToolBar();

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

private:
    QLabel *lab_style;
    QComboBox *combox_style;

    QLabel  *lab_width;
    QSpinBox  *spinbox_width;

    QToolButton  *btn_color;
    QToolButton  *btn_clear;

    DrawWidget *drawWidget;

};
#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "drawwidget.h"
#include <QToolBar>
#include <QColorDialog>
#include <QToolButton>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    drawWidget=new DrawWidget;  //新建一个DrawWidget绘图区的对象
    setCentralWidget(drawWidget); //将其作为主窗口的中央窗口
    createToolBar();  //实现一个工具栏
    setMinimumSize(600,400);  //设置主窗口的最小尺寸
    ShowStyle();  //初始化线型,设置控件中的当前值作为初始值
    drawWidget->setWidth(spinbox_width->value()); //初始化线宽
    drawWidget->setColor(Qt::black);  //初始化颜色
    handleEvents();

}

void MainWindow::createToolBar()
{
    QToolBar *toolBar=addToolBar(QStringLiteral("Tool")); //为主窗口新建一个工具栏对象

    lab_style=new QLabel(QStringLiteral("线性风格"));    //创建线性选择控件
    combox_style=new QComboBox;
    combox_style->addItem(QStringLiteral("SolidLine"),static_cast<int>(Qt::SolidLine));
    combox_style->addItem(QStringLiteral("DashLine"),static_cast<int>(Qt::DashLine));
    combox_style->addItem(QStringLiteral("DotLine"),static_cast<int>(Qt::DotLine));
    combox_style->addItem(QStringLiteral("DashDotLine"),static_cast<int>(Qt::DashDotLine));
    combox_style->addItem(QStringLiteral("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));

    lab_width=new QLabel(QStringLiteral("线宽"));  //创建线宽选择控件
    spinbox_width=new QSpinBox;

    btn_color=new QToolButton;        //创建颜色选择控件
    QPixmap pixmap(20,20);
    pixmap.fill(Qt::black);
    btn_color->setIcon(QIcon(pixmap));

    btn_clear=new QToolButton;         //创建清除按钮
    btn_clear->setText(QStringLiteral("清除"));

    toolBar->addWidget(lab_style);
    toolBar->addWidget(combox_style);
    toolBar->addSeparator();//增加竖线,将其隔开
    toolBar->addWidget(lab_width);
    toolBar->addWidget(spinbox_width);
    toolBar->addSeparator();
    toolBar->addWidget(btn_color);
    toolBar->addWidget(btn_clear);

}

//信号与槽处理
void MainWindow::handleEvents()
{

    //没有注意到线宽和清除都是drawWidget上的动作  不是当前mainWindow,所以不能用this
    connect(combox_style,SIGNAL(activated(int)),this,SLOT(ShowStyle()));
    connect(spinbox_width,SIGNAL(valueChanged(int)),drawWidget,SLOT(setWidth(int)));

    connect(btn_color,SIGNAL(clicked()),this,SLOT(ShowColor()));

    connect(btn_clear,SIGNAL(clicked()),drawWidget,SLOT(clear()));
}



MainWindow::~MainWindow()
{  
}

void MainWindow::ShowStyle()
{
   drawWidget->setStyle(combox_style->itemData(combox_style->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);
      btn_color->setIcon(QIcon(p));
  }

}


效果:

 过程中遇到的问题:

 首先发现自己没有将槽函数添加至public slots中,而是直接写在public下面。其次,我没有在activated中添加int

有两种参数

最后,线宽清除没有找到,因为我关联时写的是this,但是这两个执行动作的对象都是在DrawWidget界面上,而不是在mainwindow上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Qt C++ 中使用双缓冲技术进行绘图,可以按照以下步骤进行操作: 1. 创建一个自定义的 QWidget 子类,例如 MyPaintWidget,用于绘制图形。 ```cpp class MyPaintWidget : public QWidget { Q_OBJECT public: explicit MyPaintWidget(QWidget *parent = nullptr); protected: void paintEvent(QPaintEvent *event) override; private: QImage buffer; // 双缓冲区 }; MyPaintWidget::MyPaintWidget(QWidget *parent) : QWidget(parent) { // 设置窗口属性,启用双缓冲绘制 setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_NoSystemBackground); } void MyPaintWidget::paintEvent(QPaintEvent *event) { // 创建绘图对象,并将其绑定到双缓冲区 QPainter painter(&buffer); // 在双缓冲区上进行绘制 painter.fillRect(rect(), Qt::white); // 绘制白色背景 painter.setPen(Qt::black); // 设置画笔颜色为黑色 painter.drawLine(0, 0, width(), height()); // 绘制一条线段 // 将双缓冲区的内容绘制到窗口上 painter.begin(this); painter.drawImage(0, 0, buffer); painter.end(); } ``` 2. 在主窗口的构造函数中创建 MyPaintWidget 对象,并将其添加到布局中。 ```cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { MyPaintWidget *paintWidget = new MyPaintWidget(this); setCentralWidget(paintWidget); } ``` 通过以上步骤,我们创建了一个自定义的 QWidget 子类,并在其中实现了双缓冲绘图的功能。在 paintEvent 函数中,首先将绘图操作绘制在双缓冲区(buffer)上,然后再将双缓冲区的内容绘制到窗口上。这样可以避免图形闪烁的问题,并提高绘图的效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值