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上