QPainter实现简单的绘图程序(绘图工具)

本文介绍了如何利用QPainter和QImage优化鼠标绘图,避免因点的数量增加导致的图形失真问题。通过创建一个图像作为绘图设备,在鼠标事件中直接在image上绘画,再在重绘时仅显示image,从而保持绘图效率。此外,还展示了根据单选按钮选择绘制矩形、圆形、直线或自由涂鸦的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇:QPainter之绘制鼠标路径(画笔工具)

前言

本篇来完成一个最基本的绘图小程序,能绘制普通的矩形、圆形、直线、以及任意绘图,并且弥补基础教学中示例程序中的一些瑕疵与不足。

一、程序示例

在这里插入图片描述

二、重要步骤

修改画图方式 —— 重构思想

根据上一篇画笔工具的讲解,不论是用多边形边绘图,还是用绘制路径来绘图,程序总是很容易出现以下这种状况:在用鼠标画笔不停画圈时,画的圈数越多,圆圈越是呈现出具有棱角的多边形形态。(此处不贴图了)

有一种解决办法,就是在鼠标绘图时,用image作为绘图设备,然后在重绘函数中只将此image绘制出来,这样就不会因为鼠标点的增多而导致绘图效率降低。

1.拖入控件

在这里插入图片描述
拖入一个goupbox与4个radiobutton
并将其四个单选按钮的whatThis属性分别设置为1、2、3、4.

//添加槽函数来判断单选按钮选了谁
private slots:
    void checkWho();

增加私有成员,image与num,num用来接收单选按钮的序号,image用于绘图。

private:
    Ui::Widget *ui;
    QImage image;
    int num = 1;//默认为1  代表绘制矩形

2.构造函数初始化变量

代码如下:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    for(QRadioButton *bt:ui->groupBox->findChildren<QRadioButton*>()){
        connect(bt,&QRadioButton::clicked,this,&Widget::checkWho);
    }//找出所有单选按钮,为它们绑定到checkWho槽函数上
    image = QImage(1920,1080,QImage::Format_ARGB32);
    image.fill(QColor(255,255,255,0));
}

void Widget::checkWho()
{
	//QObject::sender()判断信号的发出者是谁,
	//通过获取whatthis设置的文本值,可以判断是哪个单选按钮被选中
    this->num = ((QRadioButton*)QObject::sender())->whatsThis().toInt();
}

3.重写事件函数

protected:
    bool event(QEvent *event) override;
//当然,还需要一些其他的私有成员
private:
	QPoint first,before,last;
	QPainter painter;	//画家
	QPainterPath path;	//路径  (只用于基本图形 如矩形、圆形、直线)

重写函数代码如下:

bool Widget::event(QEvent *event)
{
    QMouseEvent *e = static_cast<QMouseEvent*>(event);

    if(event->type()==QEvent::MouseButtonPress){
        first = last = e->pos();	//
        this->update();
    }
    else if(event->type()==QEvent::MouseMove){
        before = last;	//before与last记录鼠标路径的最后两个点
        last = e->pos();
        painter.begin(&image);	//开始画画
        Widget::setPenStyle();	//设置画笔风格
        switch (num) {			//画什么图
        case 1:				//矩形
            path.clear();
            path.addRect(QRect(first,last).normalized());
            break;
        case 2:				//圆形
            path.clear();
            path.addEllipse(QRect(first,last).normalized());
            break;
        case 3:				//直线
            path.clear();
            path = QPainterPath(first);
            path.lineTo(last);
            break;
        case 4:				//画笔涂鸦
            painter.drawLine(before,last);
            break;
        }
        painter.end();		//别忘记结束
        update();			//更新界面
    }
    else if(event->type()==QEvent::MouseButtonRelease){
        painter.begin(&image);
        Widget::setPenStyle();	//设置画笔样式
        painter.drawPath(path);	//松开鼠标后,能才确定路径长什么样子	
        						//此时才将路径画在图片上
        painter.end();
    }

    if(event->type()==QEvent::Paint){
        painter.begin(this);	//屏幕上绘图
        Widget::setPenStyle();	//设置画笔样式 (可以试试不设置会是什么样子)
        painter.drawImage(0,0,image);//画图片 之前的图形都花在了图片上,此时就画图片即可
        if(!path.isEmpty())		//路径未确定时(鼠标未松开时)有值
            painter.drawPath(path);//则画出路径的样子
        painter.end();
    }
    return QWidget::event(event);
}

void Widget::setPenStyle()
{
    QPen pen(QColor(255,0,0));
    pen.setWidth(3);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing, true);
}

时间不是很够,想十分钟草率搞定这文章算了,于是没太细致的讲解,此程序仍是初学者练习程序,后期定然还要改进,比如橡皮擦等等、路径撤回功能等等。


项目地址

项目gitee地址:绘图练习02

下一篇:QPainter绘图工具的完善

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值