使用Qt的QPainter类,我们很容易就可以实现一个类似于画笔的功能,再重载QPaintEvent函数我们就可以使用这个画笔绘制图形到界面上。
界面设计
我主要实现的功能就是画笔绘制功能,擦除功能,保存功能,调节字体颜色,字体大小功能,所以主界面使用的是QMainWIndow。
左侧是QGroupBox类里面有三个按钮分别对应的功能是画笔,擦除,选择颜色,滚动条是用来调节字体大小的,右侧是一个QScrollArea类,当图片较大的时候该类会自己生成滚动条。
绘制类
由于我们需要重载重绘事件,所以我们需要重写QWidget类。
这边我们定义类名为XImage。
首先我们需要一个QImage用于绘制打开的图片。
打开图片和重绘事件
void XImage::paintEvent(QPaintEvent * ev)
{
QPainter p(this);
if (!out.isNull())
p.drawImage(0, 0, out);
}
void XImage::open()
{
QString filename = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("打开图片"),"","(*.gif *.png)");
if (filename.isEmpty())return;
if (!src.load(filename))return;
out = src.copy();
resize(src.size());
mpos = QPoint();
}
绘制功能
绘制功能主要就是重载鼠标点击事件和鼠标移动事件。
主要的逻辑就是,当鼠标移动的时候保存上一次的移动点和当前的移动点绘制直线就可以实现。
void XImage::mouseMoveEvent(QMouseEvent* ev)
{
//绘制到原图
if (out.isNull())return;
QPainter p(&out);
//开启抗锯齿
p.setRenderHint(QPainter::Antialiasing);
p.setPen(pen);
if (mpos.isNull())mpos = ev->pos();
p.drawLine(QLine(mpos, ev->pos()));
mpos = ev->pos();
update();
}
void mouseReleaseEvent(QMouseEvent* ev)
{
mpos = QPoint();
}
擦除功能
擦除功能主要就是将画刷修改为以图片为颜料来进行绘制就可以擦除绘制后图形。
//原图像
QImage src;
QImage out;
这边我们会保存原图像和绘制的图像,当我们使用擦除功能的时候画刷使用的颜料就是原图像。
void XImage::setEraser(int size)
{
pen.setWidth(size);
pen.setBrush(QBrush(src));
}
修改颜色、字体大小
主要就是设置画笔的属性
void XImage::setPen(int size, QColor color)
{
pen.setWidth(size);
pen.setBrush(color);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
}
保存功能
void XImage::save()
{
if (out.isNull())return;
QString filename = QFileDialog::getSaveFileName(this, QString::fromLocal8Bit("保存文件"), "(*.gif *.png)");
if (filename.isEmpty())return;
if (!out.save(filename))return;
}
源码
ximage.h
#pragma once
#include <QWidget>
#include <QPen>
class XImage : public QWidget
{
Q_OBJECT
public:
XImage(QWidget* parent = nullptr);
~XImage();
void paintEvent(QPaintEvent* ev);
void mouseMoveEvent(QMouseEvent* ev);
void mouseReleaseEvent(QMouseEvent* ev)
{
mpos = QPoint();
}
public slots:
void open();
void setPen(int size, QColor color);
void setEraser(int size);
void save();
protected:
//原图像
QImage src;
QImage out;
//记录上一次的位置
QPoint mpos;
QPen pen;
};
ximage.cpp
#include "ximage.h"
#include <QFileDialog>
#include <QPainter>
#include <QMouseEvent>
XImage::XImage(QWidget *parent)
: QWidget(parent)
{}
XImage::~XImage()
{}
void XImage::paintEvent(QPaintEvent * ev)
{
QPainter p(this);
if (!out.isNull())
p.drawImage(0, 0, out);
}
void XImage::open()
{
QString filename = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("打开图片"),"","(*.gif *.png)");
if (filename.isEmpty())return;
if (!src.load(filename))return;
out = src.copy();
resize(src.size());
mpos = QPoint();
}
void XImage::mouseMoveEvent(QMouseEvent* ev)
{
//绘制到原图
if (out.isNull())return;
QPainter p(&out);
//开启抗锯齿
p.setRenderHint(QPainter::Antialiasing);
p.setPen(pen);
if (mpos.isNull())mpos = ev->pos();
p.drawLine(QLine(mpos, ev->pos()));
mpos = ev->pos();
update();
}
void XImage::setPen(int size, QColor color)
{
pen.setWidth(size);
pen.setBrush(color);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
}
void XImage::setEraser(int size)
{
pen.setWidth(size);
pen.setBrush(QBrush(src));
}
void XImage::save()
{
if (out.isNull())return;
QString filename = QFileDialog::getSaveFileName(this, QString::fromLocal8Bit("保存文件"), "(*.gif *.png)");
if (filename.isEmpty())return;
if (!out.save(filename))return;
}
xps.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_xps.h"
class XPS : public QMainWindow
{
Q_OBJECT
public:
XPS(QWidget *parent = nullptr);
~XPS();
public slots:
void setPen();
void setColor();
void setEraser();
void save();
private:
Ui::XPSClass ui;
QColor col;
};
xps.cpp
#include "xps.h"
#include <QColorDialog>
#include <QButtonGroup>
XPS::XPS(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.openaction, &QAction::triggered, ui.image, &XImage::open);
connect(ui.saveaction, &QAction::triggered, ui.image, &XImage::save);
col = QColor(255, 0, 0, 255);
setPen();
QButtonGroup* group = new QButtonGroup(this);
group->addButton(ui.penButton);
group->addButton(ui.eraseButton);
group->setExclusive(true);
}
XPS::~XPS()
{}
void XPS::setColor()
{
col = QColorDialog::getColor(Qt::red, this);
QString style = QString("background-color:rgba(%1,%2,%3,%4);").arg(col.red()).arg(col.green()).arg(col.blue()).arg(col.alpha());
setPen();
}
void XPS::setEraser()
{
ui.image->setEraser(ui.penSize->value());
ui.eraseButton->setChecked(true);
}
void XPS::save()
{
ui.image->save();
ui.statusBar->showMessage(QString::fromLocal8Bit("保存结束"), 5000);
}
void XPS::setPen()
{
ui.image->setPen(ui.penSize->value(), col);
ui.penButton->setChecked(true);
}
main.cpp
#include "xps.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
XPS w;
w.show();
return a.exec();
}