【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.4 点、线

本节对应的视频讲解:B_站_视_频

https://www.bilibili.com/video/BV1x14y1J7rn
在这里插入图片描述


完成了界面布局,以及添加了初始化数据,就可以开始真正绘制图形了

本节讲解如何绘制点、线


1. 基本点线的绘制

1.1 为 cboShape 关联信号槽

首先,在 widget.h 中,声明一个槽函数

class Widget : public QWidget
{
private slots:
    void shapeChanged();
};

然后,在 widget.cpp 中,实现这个槽函数,先空着,一会再来实现

void Widget::shapeChanged()
{

}

接着,在 widget.cpp 的构造中,关联信号和槽

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 5. 信号槽
    // 形状
    connect(ui->cboShape, SIGNAL(activated(QString)), this, SLOT(shapeChanged()));  // 槽的参数可以比信号少
}

1.2 实现 shapeChanged 槽函数

shapeChanged 槽函数会调用 PaintWidget 类的方法完成绘制,如下:

void Widget::shapeChanged()
{
    int index = ui->cboShape->currentIndex();
    Shape shape = (Shape)ui->cboShape->itemData(index).toInt();

    ui->paintWidget->setShape(shape);
}

1.3 实现 setShape 函数

接下来,在 PaintWidget 类中,来实现这个 setShape 函数

首先,在 PaintWidget.h 中声明一个该函数,并声明一个成员变量 mShape

class PaintWidget : public QWidget
{
public slots:
    void setShape(Shape shape);

private:
    Shape mShape;
};

然后,实现这个 setShape 函数

void PaintWidget::setShape(Shape shape)
{
    this->mShape = shape;
    update();
}

这里调用 update 函数,会自动调用该类的 paintEvent 函数,paintEvent 是重载的父类的


1.4 重载 paintEvent

接下来,就实现这个 paintEvent 函数,来完成真正的绘制

paintEvent 是什么?

paintEvent 是一个绘图函数,它是并不是由我们手动调用的, 而是由系统自动调用的。

调用时机:

  • 窗口大小变化时

    比如最大化、最小化、缩放窗口时,系统都会调用该函数

  • 手动调用 update

    手动调用 update 函数,同样会触发系统调用 paintEvent,从而完成界面的刷新。

首先,在 paintwidget.h 中声明 paintEvent

class PaintWidget : public QWidget
{
protected:
    void paintEvent(QPaintEvent *event) override;
};

然后,在 paintwidget.cpp 中实现它

#include <QPainter>

void PaintWidget::paintEvent(QPaintEvent *event)
{
    static const QPoint points[4] = {
        QPoint(10, 80),  //
        QPoint(20, 10),  //
        QPoint(80, 30),  //
        QPoint(90, 70)   //
    };

    // 创建画家类的对象,参数为绘图设备。指定为this,表示在当前窗口绘制
    QPainter painter(this);

    switch ( mShape ) {
        // 点、线
        case _Point:
            painter.drawPoints(points, 4);
            break;
        case _Line:
            painter.drawLine(points[0], points[2]);
            break;
    }
}

最后,在 widget.cpp 的构造中,手动调用一个 shapeChanged 槽函数,触发一下绘制

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    shapeChanged();
}

这样就完成了点、线的绘制,如下:

image-20221207164443209

image-20221207164530836


2. 循环绘制

由于在 Qt 中,坐标原点默认在左上角,因此以上将点、线绘制在了 PaintWidget 的左上角

接下来实现:将绘制的点、线铺满整个 PaintWidget,也就是如下效果:

image-20221207165228480

image-20221207165244140

该如何实现呢?

以绘制线为例,由于向右 x 轴坐标增加,向下 y 轴坐标增加。因此,可以依次计算出每根线的两个端点的坐标,如下:

image-20221207170439284


2.1 平移 translate

这种方式肯定可以实现的,不过 QPainter 为我们提供了更加简便的方法:

平移-translate:它的作用是,移动绘图的坐标原点

有了平移的方法,就可以直接移动绘图的坐标原点,这样线段的两个端点的坐标就不需要改变,如下:

image-20221207173806601

绘制线段a时:绘图的坐标原点为A(0, 0),此时,两个线段的两个端点为 (10, 80)、(80, 30)

绘制线段b时:先将绘图的坐标原点移动到B(100, 0),此时,两个线段的两个端点仍然为 (10, 80)、(80, 30)

绘制线段c时:先将绘图的坐标原点移动到C(0, 100),此时,两个线段的两个端点仍然为 (10, 80)、(80, 30)


2.2 QPainter 的保存和恢复

saverestore 用于保存和恢复 QPainter 的状态

状态包括画笔的状态,画刷的状态,以及绘图的坐标原点等

saverestore是一一对应的,要成对出现。一个 save 就要对应一个 restore


2.3 具体实现

具体代码实现如下:

void PaintWidget::paintEvent(QPaintEvent *event)
{
    static const QPoint points[4] = {
        QPoint(10, 80),  //
        QPoint(20, 10),  //
        QPoint(80, 30),  //
        QPoint(90, 70)   //
    };

    // 创建画家类的对象,参数为绘图设备。指定为this,表示在当前窗口绘制
    QPainter painter(this);

    for ( int x = 0; x < width(); x += 100 ) {
        for ( int y = 0; y < height(); y += 100 ) {
            // 先保存原来的状态
            // (0,0),(0,100),(0,200),(0,300)...(0,600)
            // (100,0),(100,100),(100,200),(100,300)...(100,600)
            // ...
            // (800,0),(800,100),(800,200),(800,300)...(800,600)
            painter.save();
            painter.translate(x, y);  // translate 修改的是坐标系

            switch ( mShape ) {
                // 点、线
                case _Point:
                    painter.drawPoints(points, 4);
                    break;
                case _Line:
                    painter.drawLine(points[0], points[2]);
                    break;
            }

            painter.restore();
        }
    }
}

说明:

由于 saverestore要成对出现。一个 save 就要对应一个 restore

因此把它们都放在第二个 for 循环中,这样才能保证,它们的一一对应。

经过以上修改,就可以循环绘制点、线了!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大轮明王讲QT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值