QPainter偏移原点、旋转、缩放功能Demo【3】 原创
QPainter偏移原点、旋转、缩放功能Demo【3】
更多精彩内容 |
---|
👉个人内容分类汇总 👈 |
1、概述
-
Qt版本:V5.12.5
-
本文内容
- 使用QPainterPath设置绘制较复杂的图案;
- 演示绘图时偏移坐标轴原点、选择、缩放操作。
-
整体效果
2、关键代码
-
renderarea.h
#ifndef RENDERAREA_H #define RENDERAREA_H #include <QWidget> // 绘图操作类型 enum Operation { NoOperation, // 没有进行操作 Translate, // 偏移绘图坐标原点 Rotate, // 以坐标原点为中心进行旋转 Scale // 将绘制图案按比例缩放 }; class RenderArea : public QWidget { Q_OBJECT public: explicit RenderArea(QWidget *parent = nullptr); void setShape(const QPainterPath& shape); void setOperations(const QList<Operation>& operations); protected: void paintEvent(QPaintEvent *event) override; void drawOutline(QPainter& painter); void transformPainter(QPainter& painter); void drawCoordinates(QPainter& painter); public slots: private: QList<Operation> m_operations; // 保存所有的缩放、偏移、旋转操作 QRect m_fontRectX; // X轴字体矩形范围 QRect m_fontRectY; // Y轴字体矩形范围 QPainterPath m_shape; // 用于绘制图案的路径 }; #endif // RENDERAREA_H
-
renderarea.cpp
#include "renderarea.h" #include <QDebug> #include <qpainter.h> RenderArea::RenderArea(QWidget *parent) : QWidget(parent) { this->setMinimumSize(200, 200); // 设置背景填充色 this->setBackgroundRole(QPalette::Base); this->setAutoFillBackground(true); QFont newFont = this->font(); newFont.setPixelSize(20); // 设置字体大小 this->setFont(newFont); // 设置当前类使用的字体 QFontMetrics fontMetrics(newFont); // QFontMetrics 类提供字体度量信息。 m_fontRectX = fontMetrics.boundingRect("X"); // 返回由 text 指定的字符串中字符的边界矩形 m_fontRectY = fontMetrics.boundingRect("Y"); } /** * @brief 设置用于绘制的图案路径 * @param shape */ void RenderArea::setShape(const QPainterPath &shape) { this->m_shape = shape; this->update(); } /** * @brief 设置绘制图案的操作 * @param operations */ void RenderArea::setOperations(const QList<Operation> &operations) { this->m_operations = operations; this->update(); } /** * @brief 重绘事件函数 * @param event */ void RenderArea::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter painter(this); // 创建一个画家对象 painter.setRenderHint(QPainter::Antialiasing); // 设置抗锯齿 painter.translate(60, 60); // 坐标原点偏移到(60, 60)位置 drawOutline(painter); // 画一个虚线矩形框 painter.save(); // 保存当前绘制状态,save()后所有QPainter设置在restore()后将失效(比如画笔设置) transformPainter(painter); // 设置偏移、缩放、旋转 drawCoordinates(painter); // 绘制坐标系 painter.fillPath(m_shape, Qt::blue); painter.restore(); } /** * @brief 画一个虚线矩形框 * @param painter */ void RenderArea::drawOutline(QPainter &painter) { painter.save(); // 将QPainter状态保存,后面的设置不会产生影响 painter.setPen(Qt::darkBlue); // 设置画笔颜色 painter.setPen(Qt::DashLine); // 画笔样式为虚线 painter.drawRect(0, 0, 100,100); // 画虚线矩形 painter.restore(); } /** * @brief 在这个函数中设置画家对象的坐标原点偏移、旋转、缩放 * @param painter */ void RenderArea::transformPainter(QPainter &painter) { for(auto operation : m_operations) { switch (operation) { case Translate: painter.translate(50, 50); // 坐标原点偏移 50 像素 break; case Scale: painter.scale(0.75, 0.75); // 缩小到原来的75%大小 break; case Rotate: painter.rotate(60); // 顺时针旋转60度 break; default:break; } } } /** * @brief 绘制当前画图使用的坐标系 * @param painter */ void RenderArea::drawCoordinates(QPainter &painter) { painter.save(); painter.setPen(Qt::red); painter.drawLine(0, 0, 50, 0); // 绘制X轴直线 painter.drawLine(45, -3, 50, 0); // 画X轴箭头 painter.drawLine(45, 3, 50, 0); painter.drawText(QRect(50, 0, m_fontRectX.width(), -m_fontRectX.height()), Qt::AlignCenter, "X"); painter.drawLine(0, 0, 0, 50); // 绘制Y轴 painter.drawLine(3, 45, 0, 50); // 画Y轴箭头 painter.drawLine(-3, 45, 0, 50); painter.drawText(QRect(0, 50, -m_fontRectX.width(), m_fontRectX.height()), Qt::AlignCenter, "Y"); painter.restore(); }
-
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE class QComboBox; class RenderArea; QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: void initUI(); void setupShapes(); private slots: void shapeSelected(int index); void operationChanged(int index); private: enum {NumTransformendAreas = 3}; // 定义一个常量,等同于宏常量【枚举常量可设置私有】 QComboBox* m_comShape = nullptr; // 绘制图案选择 QComboBox* m_comOperation[NumTransformendAreas]; // 包含多个QComboBox指针的指针数组 QList<QPainterPath> m_shapes; // 绘制图案 RenderArea* m_originalRenderArea = nullptr; // 原始渲染区域 RenderArea* m_transformedRenderAreas[NumTransformendAreas]; // 可进行缩放、偏移、旋转的区域 }; #endif // WIDGET_H
-
widget.cpp
#include "widget.h" #include "renderarea.h" #include <qcombobox.h> #include <qdebug.h> #include <qgridlayout.h> Widget::Widget(QWidget *parent): QWidget(parent) { this->setWindowTitle("QPainter偏移原点、旋转、缩放功能Demo"); initUI(); setupShapes(); // 设置形状 } Widget::~Widget() { } void Widget::initUI() { m_originalRenderArea = new RenderArea(this); m_comShape = new QComboBox(this); m_comShape->addItem("卡车图案"); m_comShape->addItem("时钟图案"); m_comShape->addItem("房子图案"); m_comShape->addItem("文字图案"); // 这里可以用activated也可以用currentIndexChanged,由于这两个信号都有重载,所以需要加上QOverload connect(m_comShape, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Widget::shapeSelected); // 添加布局 QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_originalRenderArea, 0, 0); layout->addWidget(m_comShape, 1, 0); for(int i = 0; i < NumTransformendAreas; i++) { m_transformedRenderAreas[i] = new RenderArea(this); m_comOperation[i] = new QComboBox(this); m_comOperation[i]->addItem("默认状态"); m_comOperation[i]->addItem("坐标原点偏移(50,50)"); m_comOperation[i]->addItem("旋转60度"); m_comOperation[i]->addItem("缩小75%"); connect(m_comOperation[i], QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Widget::operationChanged); // 添加布局 layout->addWidget(m_transformedRenderAreas[i], 0, i + 1); layout->addWidget(m_comOperation[i], 1, i + 1); } } void Widget::setupShapes() { // 绘制卡车图案的路径 QPainterPath truck; truck.setFillRule(Qt::WindingFill); // 设置填充规则 truck.moveTo(0.0, 87.0); // 将绘制起点移动到给定点,隐式启动新的子路径并关闭前一个子路径。 truck.lineTo(0.0, 60.0); // 添加从当前位置到给定端点的直线。绘制线后,当前位置将更新为线的端点。 truck.lineTo(10.0, 60.0); truck.lineTo(35.0, 35.0); truck.lineTo(100.0, 35.0); truck.lineTo(100.0, 87.0); truck.lineTo(0.0, 87.0); truck.moveTo(17.0, 60.0); truck.lineTo(55.0, 60.0); truck.lineTo(55.0, 40.0); truck.lineTo(37.0, 40.0); truck.lineTo(17.0, 60.0); truck.addEllipse(17.0, 75.0, 25.0, 25.0); // 添加一个椭圆,椭圆由一条【顺时针曲线】组成,起点和终点为零度(3点钟位置) truck.addEllipse(63.0, 75.0, 25.0, 25.0); // 绘制时钟的路径 QPainterPath clock; clock.addEllipse(-50.0, -50.0, 100.0, 100.0); clock.addEllipse(-48.0, -48.0, 96.0, 96.0); clock.moveTo(0.0, 0.0); clock.lineTo(-2.0, -2.0); clock.lineTo(0.0, -42.0); clock.lineTo(2.0, -2.0); clock.lineTo(0.0, 0.0); clock.moveTo(0.0, 0.0); clock.lineTo(2.732, -0.732); clock.lineTo(24.495, 14.142); clock.lineTo(0.732, 2.732); clock.lineTo(0.0, 0.0); // 绘制房子路径 QPainterPath house; house.moveTo(-45.0, -20.0); house.lineTo(0.0, -45.0); house.lineTo(45.0, -20.0); house.lineTo(45.0, 45.0); house.lineTo(-45.0, 45.0); house.lineTo(-45.0, -20.0); house.addRect(15.0, 5.0, 20.0, 35.0); // 添加一个矩形,矩形被添加为一组顺时针方向的直线。添加矩形后,绘制路径的当前位置位于矩形的【左上角】 house.addRect(-35.0, -15.0, 25.0, 25.0); // 绘制文本路径 QPainterPath text; QFont font; font.setPixelSize(50); // 设置文字大小 QRect fontRect = QFontMetrics(font).boundingRect("1a你好"); // 计算输入字符串在指定的font字体时所占的矩形大小 text.addText(-QPointF(fontRect.center()), font, "1a你好"); // 添加需要绘制的字体 // 将创建的绘画路径添加进列表 m_shapes.append(truck); m_shapes.append(clock); m_shapes.append(house); m_shapes.append(text); shapeSelected(0); // 显示第一个图案 } /** * @brief 当下拉框选择图案后通过信号修改显示的图案路径 * @param index */ void Widget::shapeSelected(int index) { QPainterPath shape = m_shapes.at(index); m_originalRenderArea->setShape(shape); for(int i = 0; i < NumTransformendAreas; i++) { m_transformedRenderAreas[i]->setShape(shape); } } /** * @brief 设置绘制图案的原点偏移、旋转、缩放 */ void Widget::operationChanged(int index) { Q_UNUSED(index) QList<Operation> operations; for(int i = 0; i < NumTransformendAreas; i++) { operations.append(Operation(m_comOperation[i]->currentIndex())); m_transformedRenderAreas[i]->setOperations(operations); // 第一个绘图operations长度为1,第二个operations为2,第三个operations长度为3 } }
3、源代码
💡💡💡💡💡💡💡💡💡💡💡💡💡💡