《Qt5.9 C++ 开发指南》8.2 坐标系统和坐标变换 笔记

10 篇文章 0 订阅

示例1:绘制3个五角星

// Widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

protected:
	// 先在Widget.h里声明paintEvent()函数的重载,权限protected
    void paintEvent(QPaintEvent *event) override;  
    
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
// Widget.cpp
#include <QPaintEvent>
#include <QPainter>
#include <math.h>

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setPalette(QPalette(Qt::green));   // 设置窗口背景
    setAutoFillBackground(true);
    resize(600, 300);   // 固定初始化窗口大小
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);
    
    // 生成五角星5个顶点的坐标,假设原点在五角星中心
    qreal R = 100;
    const qreal Pi = 3.14159;
    qreal deg = Pi * 72 / 180;
    QPoint points[5] = {
        QPoint(R, 0),   // 从x轴正半轴开始,x轴y轴方向是一般直角坐标系方向
        QPoint(R * std::cos(deg), -R * std::sin(deg)),
        QPoint(R * std::cos(2 * deg), -R * std::sin(2 * deg)),
        QPoint(R * std::cos(3 * deg), -R * std::sin(3 * deg)),
        QPoint(R * std::cos(4 * deg), -R * std::sin(4 * deg)),
    };

	// 设置字体
    QFont font;
    font.setPointSize(12);
    font.setBold(true);
    painter.setFont(font);
	
	// 设置画笔
    QPen penLine;
    penLine.setWidth(2);   // 线宽
    penLine.setColor(Qt::blue);   // 划线颜色
    penLine.setStyle(Qt::SolidLine);   // 线的类型
    penLine.setCapStyle(Qt::FlatCap);   // 线端点样式
    penLine.setJoinStyle(Qt::BevelJoin);   // 线的连接点样式
    painter.setPen(penLine);
	
	// 设置画刷
	QBrush brush;
    brush.setColor(Qt::yellow);   // 画刷颜色
    brush.setStyle(Qt::SolidPattern);   // 画刷填充样式
    painter.setBrush(brush);
    
    // 设计绘制五角星的PainterPath,以便重复使用
	QPainterPath starPath;
    starPath.moveTo(points[0]);
    starPath.lineTo(points[2]);
    starPath.lineTo(points[4]);
    starPath.lineTo(points[1]);
    starPath.lineTo(points[3]);
    starPath.closeSubpath();   // 闭合路径,最后一个点与第一个点相连
    starPath.addText(points[0], font, "0");
    starPath.addText(points[1], font, "1");
    starPath.addText(points[2], font, "2");
    starPath.addText(points[3], font, "3");
    starPath.addText(points[4], font, "4");

	// 绘图
	painter.save();   // 保存坐标状态
    painter.translate(100, 120);   // 平移
    painter.drawPath(starPath);   // 画星星
    painter.drawText(0, 0, "S1");   // 在坐标的(0, 0)点绘制
    painter.restore();   // 恢复坐标状态

	painter.translate(300, 120);   // 平移
    painter.scale(0.8, 0.8);   // 缩放
    painter.rotate(90);   // 顺时针旋转90度
    painter.drawPath(starPath);   // 画星星
    painter.drawText(0, 0, "S2");
    
    painter.resetTransform();   // 复位所有坐标变换
    painter.translate(500, 120);   // 平移
    painter.rotate(-145);   // 逆时针旋转145度
    painter.drawPath(starPath);   // 画星星
    painter.drawText(0, 0, "S3");
}

8.2.3 视口和窗口
视口表示绘图设备的任意一个矩形区域的物理坐标(就是真实的以像素为单位的坐标),可以只选取物理坐标的一个矩形区域用于绘图。默认情况下,视口等于绘图设备的整个矩形区。
窗口可以和视口是同一个矩形(注意!同一个 QPainter 对象里所 set 的窗口和视口代表了绘图设备的同一个矩形区域!只是你可以用窗口和视口两种不同的坐标表示方法来描述这块矩形。),只不过是用逻辑坐标定义的坐标系。窗口可以直接定义矩形区逻辑坐标范围。

在这里插入图片描述

定义视口可以使用 QPainter 的 setViewport() 函数,原型为:

void QPainter::setViewport(int x, int y, int width, int height)

示例:

painter.setViewport(50, 0, 200, 200);

定义窗口可以使用 QPainter 的 setWindow() 函数,其原型为:

void QPainter::setWindow(int x, int y, int widht, int height)

示例:定义一个窗口,窗口坐标的中心在正方形中心,并设置正方形的逻辑边长为100

painter.setWindow(-50, -50, 100, 100);

使用窗口坐标的优点是,只需按照窗口坐标定义来绘图,而不用管实际的屋里坐标范围的大小。例如在一个固定边长100的正方形窗口内绘图,当实际绘图设备大小变化时,绘制的图形会自动变化大小。这样,就可以将绘图功能与绘图设备隔离开来,使得绘图功能适用于不同大小、不同类型的设备。

视口和窗口的使用实例:

// widget.cpp
#include <QPainter>

#include "widget.h"
#include "ui_widget.h"

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

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    int W = width();
    int H = height();
    int side = qMin(W, H);   // 取长和宽中的较小值
    QRect rect((W - side) / 2, (H - side) / 2, side, side);   // 定义一个用于建立 viewport 的矩形区
    
    painter.drawRect(rect);   // Viewport 的矩形区域
    painter.setViewport(rect);   // 设置Viewport
    painter.setWindow(-100, -100, 200, 200);   // 设置窗口大小,逻辑坐标
    painter.setRenderHint(QPainter::Antialiasing);
    
    // 设置画笔
    QPen pen;
    pen.setWidth(1);
    pen.setColor(Qt::red);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);

    for(int i = 0; i < 36; ++i)
    {
        painter.drawEllipse(QPoint(50, 0), 50, 50);
        painter.rotate(10);
    }
}

其中,painter.drawEllipse(QPoint(50, 0), 50, 50); 在 painter 对象设置的窗口中,以(50,0)为圆心,画了一个长轴50、短轴50的椭圆(圆形)。painter.rotate(10); 把坐标系顺时针旋转了10度。

8.2.4 绘图叠加的效果

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值