文章目录

  • 1 Qt中的基础图形绘制
  • 2 Qt基础图形绘制中的视口和窗口
  • 3 综合实例开发:简易绘图程序
    • 3.1 需求分析
    • 3.2 设计分析

1 Qt中的基础图形绘制

Qt图形系统中的关键角色:

  • QPainter:

    • Qt中的画家,能够绘制各种基础图形。
    • 拥有绘图所需的画笔(QPen)、画刷(QBrush)、字体(QFont)。
  • QPaintDevice:
    • Qt中的画布,画家(QPainter)的绘图板。
    • 所有的QWidget类都继承自QPaintDevice。


画家QPainter所使用的工具角色:

  • QPen:

    • 用于绘制几何图形的边缘,由颜色、宽度、线风格参数组成。
  • QBrush:
    • 用于填充几何图形的调色板,由颜色和填充风格组成。
  • QFont:
    • 用于文本绘制,由字体属性组成。

QPainter的基本绘图能力:

重要规则:

  • 只能QWidget::paintEvent中绘制图形。

问题:如何动态绘制需要的图形?

工程中的解决方案:

  1. 根据需要确定参数对象(绘图类型、点坐标、角度,等)。
  2. 将参数对象存入数据集合中(如:链表)。
  3. 在paintEvnet函数中遍历数据集合。
  4. 根据参数对象绘制图形(update())。

Widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QtGui/QWidget>
#include <QPushButton>
#include <QPoint>
#include <QList>class Widget : public QWidget
{Q_OBJECTenum{LINE,RECT,ELLIPSE};struct DrawParam{int type;Qt::PenStyle pen;QPoint begin;QPoint end;};QPushButton m_testBtn;QList<DrawParam> m_list;protected slots:void onTestBtnClicked();
protected:void paintEvent(QPaintEvent *);
public:Widget(QWidget *parent = 0);~Widget();
};#endif // WIDGET_H

Widget.cpp:

#include "Widget.h"
#include <QPainter>
#include <QPoint>Widget::Widget(QWidget *parent): QWidget(parent)
{m_testBtn.setParent(this);m_testBtn.move(400, 300);m_testBtn.resize(70, 30);m_testBtn.setText("Test");resize(500, 350);connect(&m_testBtn, SIGNAL(clicked()), this, SLOT(onTestBtnClicked()));
}void Widget::onTestBtnClicked()
{DrawParam dp ={qrand() % 3,static_cast<Qt::PenStyle>(qrand() % 5 + 1),QPoint(qrand() % 400, qrand() % 300),QPoint(qrand() % 400, qrand() % 300)};if( m_list.count() == 5 ){m_list.clear();}m_list.append(dp);update();
}void Widget::paintEvent(QPaintEvent *)
{QPainter painter;painter.begin(this);for(int i=0; i<m_list.count(); i++){int x = (m_list[i].begin.x() < m_list[i].end.x()) ? m_list[i].begin.x() : m_list[i].end.x();int y = (m_list[i].begin.y() < m_list[i].end.y()) ? m_list[i].begin.y() : m_list[i].end.y();int w = qAbs(m_list[i].begin.x() - m_list[i].end.x()) + 1;int h = qAbs(m_list[i].begin.y() - m_list[i].end.y()) + 1;painter.setPen(m_list[i].pen);switch(m_list[i].type){case LINE:painter.drawLine(m_list[i].begin, m_list[i].end);break;case RECT:painter.drawRect(x, y, w, h);break;case ELLIPSE:painter.drawEllipse(x, y, w, h);break;default:break;}}painter.end();
}Widget::~Widget()
{}

main.cpp:

#include <QtGui/QApplication>
#include "Widget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

2 Qt基础图形绘制中的视口和窗口

首先来看下Qt图形系统中的坐标系:

  • 物理坐标系(设备坐标系):

    • 原点(0, 0)在左上角的位置,单位:像素(点)。
    • x坐标向右增长,y坐标向下增长。
  • 逻辑坐标系:
    • 数学模型中的抽象坐标系,单位由具体问题决定。
    • 坐标轴的增长方向由具体问题决定。

我们必须知道的事实:

  • QPainter使用逻辑坐标系绘制图形。
  • 逻辑坐标系中图形的大小和位置经由转换后绘制于具体设备。
  • 默认情况下的逻辑坐标系与物理坐标系完全一致。

小例子:

  • A4纸的大小是固定的,但可以用于绘制任意类型的曲线图。

视口与窗口的概念:

  • 视口(view port):

    • 物理坐标系中一个任意指定的矩形。
  • 窗口(window):
    • 逻辑坐标系下对应到物理坐标系中的相同矩形。

站在不同的角度看同一个矩形,就有了视口和窗口。

深入理解视口和窗口:

  • 视口与窗口是不同坐标系中的同一个矩形。
  • 视口与窗口中的坐标点存在一一映射的关系。
  • 视口与窗口能够通过坐标变换而相互转换。

视口与窗口的变换方法:

  • 定义视口(setViewPort):

    • 左上角坐标,右下角坐标,计算宽度和高度。
  • 定义窗口(setWindow):
    • 左上角坐标,右下角坐标,计算宽度和高度。

下面看一下正弦波形绘图实例:

Widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QtGui/QWidget>class Widget : public QWidget
{Q_OBJECTprotected:void paintEvent(QPaintEvent *);
public:Widget(QWidget *parent = 0);~Widget();
};#endif // WIDGET_H

Widget.cpp:

#include "Widget.h"
#include <QPainter>
#include <QPointF>
#include <QPen>
#include <qmath.h>Widget::Widget(QWidget *parent): QWidget(parent)
{}void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this);QPen pen;pen.setColor(Qt::green);pen.setStyle(Qt::SolidLine);pen.setWidthF(0.01);painter.setPen(pen);painter.setViewport(50, 50, width()-100, height()-100);painter.setWindow(-10, 2, 20, -4); // (-10, 2)    (10, -2)painter.fillRect(-10, 2, 20, -4, Qt::black);painter.drawLine(QPointF(-10, 0), QPointF(10, 0));   // xpainter.drawLine(QPointF(0, 2), QPointF(0, -2));     // yfor(float x=-10; x<10; x+=0.01){float y = qSin(x);painter.drawPoint(QPointF(x, y));}}Widget::~Widget()
{}

main.cpp:

#include <QtGui/QApplication>
#include "Widget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

3 综合实例开发:简易绘图程序

3.1 需求分析

功能需求:

  • 自由图形绘制。
  • 基本图形绘制(直线、矩形、椭圆)。
  • 能够选择图形绘制颜色。

3.2 设计分析

界面解决方案:

  1. 以QWidget为基类创建绘图主窗口。
  2. 使用QGroupBox创建图形设置区域。
  3. 使用QRadioBox实现目标图形的选择。
  4. 使用组合框QCombox实现绘图颜色的选择。

自由绘图分析:

  • 自由绘图的本质是跟踪鼠标的移动轨迹;因此,必须考虑什么时候开始?什么时候结束?如何记录鼠标移动?

要点:

  • 从绘图参数的角度,可以将已经绘制结束的图形与正在绘制的图形分开处理。
  • 自由绘图必须记录鼠标移动时经过的所有点坐标。因此,绘图参数必须有能力保存多个坐标值。

自由绘图解决方案:

基础图形动态绘制分析:

  • 基础图形的目标是固定的,但是开始点与结束点的不同会导致最终形状的差异;因此,鼠标移动时根据当前坐标实时绘图,鼠标松开时确定最终图形。
  • 基本图形绘制需要在鼠标按下并移动时进行动态绘图;但是,无论何时都只需要记录两个坐标值。

基础图形绘制解决方案:

总结一下:

  • 绘图程序需要重写鼠标事件处理函数。
  • 模型视图的思想适用于绘图程序。
  • 所有图形的绘制由paintEvent函数完成。
  • 工程中需要避免在绘制时进行浮点运算。

Widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QtGui/QWidget>
#include <QRadioButton>
#include <QComboBox>
#include <QGroupBox>
#include <QList>
#include <QPoint>class Widget : public QWidget
{Q_OBJECTenum DrawType{NONE,FREE,LINE,RECT,ELLIPSE};struct DrawParam{DrawType type;Qt::GlobalColor color;QList<QPoint> points;};QGroupBox m_group;QRadioButton m_freeBtn;QRadioButton m_lineBtn;QRadioButton m_rectBtn;QRadioButton m_ellipseBtn;QComboBox m_colorBox;QList<DrawParam> m_drawList;DrawParam m_current;DrawType drawType();Qt::GlobalColor drawColor();void draw(QPainter& painter, DrawParam& param);void append(QPoint p);
protected:void mousePressEvent(QMouseEvent *evt);void mouseMoveEvent(QMouseEvent *evt);void mouseReleaseEvent(QMouseEvent *evt);void paintEvent(QPaintEvent *);
public:Widget(QWidget *parent = 0);~Widget();
};#endif // WIDGET_H

Widget.cpp:

#include "Widget.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPen>
#include <QBrush>Widget::Widget(QWidget *parent): QWidget(parent)
{m_group.setParent(this);m_group.setTitle("Setting");m_group.resize(600, 65);m_group.move(20, 20);m_freeBtn.setParent(&m_group);m_freeBtn.setText("Free");m_freeBtn.resize(70, 30);m_freeBtn.move(35, 20);m_freeBtn.setChecked(true);m_lineBtn.setParent(&m_group);m_lineBtn.setText("Line");m_lineBtn.resize(70, 30);m_lineBtn.move(140, 20);m_rectBtn.setParent(&m_group);m_rectBtn.setText("Rect");m_rectBtn.resize(70, 30);m_rectBtn.move(245, 20);m_ellipseBtn.setParent(&m_group);m_ellipseBtn.setText("Ellipse");m_ellipseBtn.resize(70, 30);m_ellipseBtn.move(350, 20);m_colorBox.setParent(&m_group);m_colorBox.resize(80, 25);m_colorBox.move(480, 23);m_colorBox.addItem("Black");m_colorBox.addItem("Blue");m_colorBox.addItem("Green");m_colorBox.addItem("Red");m_colorBox.addItem("Yellow");setFixedSize(width(), 600);m_current.type = NONE;m_current.color = Qt::white;m_current.points.clear();
}Widget::DrawType Widget::drawType()
{DrawType ret = NONE;if( m_freeBtn.isChecked() )    ret = FREE;if( m_lineBtn.isChecked() )    ret = LINE;if( m_rectBtn.isChecked() )    ret = RECT;if( m_ellipseBtn.isChecked() ) ret = ELLIPSE;return ret;
}Qt::GlobalColor Widget::drawColor()
{Qt::GlobalColor ret = Qt::black;if( m_colorBox.currentText() == "Black")    ret = Qt::black;if( m_colorBox.currentText() == "Blue")     ret = Qt::blue;if( m_colorBox.currentText() == "Green")    ret = Qt::green;if( m_colorBox.currentText() == "Red")      ret = Qt::red;if( m_colorBox.currentText() == "Yellow")   ret = Qt::yellow;return ret;
}void Widget::mousePressEvent(QMouseEvent *evt)
{m_current.type = drawType();m_current.color = drawColor();m_current.points.append(evt->pos());
}void Widget::mouseMoveEvent(QMouseEvent *evt)
{append(evt->pos());update();
}void Widget::mouseReleaseEvent(QMouseEvent *evt)
{append(evt->pos());m_drawList.append(m_current);m_current.type = NONE;m_current.color = Qt::white;m_current.points.clear();update();
}void Widget::append(QPoint p)
{if( m_current.type != NONE ){if( m_current.type == FREE ){m_current.points.append(p);}else{if( m_current.points.count() == 2 ){m_current.points.removeLast();}m_current.points.append(p);}}
}void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this);for(int i=0; i<m_drawList.count(); i++){draw(painter, m_drawList[i]);}draw(painter, m_current);
}void Widget::draw(QPainter& painter, DrawParam& param)
{if( (param.type != NONE) && (param.points.count() >= 2) ){int x = (param.points[0].x() < param.points[1].x()) ? param.points[0].x() : param.points[1].x();int y = (param.points[0].y() < param.points[1].y()) ? param.points[0].y() : param.points[1].y();int w = qAbs(param.points[0].x() - param.points[1].x()) + 1;int h = qAbs(param.points[0].y() - param.points[1].y()) + 1;painter.setPen(QPen(param.color));painter.setBrush(QBrush(param.color));switch(param.type){case FREE:for(int i=0; i<param.points.count()-1; i++){painter.drawLine(param.points[i], param.points[i+1]);}break;case LINE:painter.drawLine(param.points[0], param.points[1]);break;case RECT:painter.drawRect(x, y, w, h);break;case ELLIPSE:painter.drawEllipse(x, y, w, h);break;default:break;}}
}Widget::~Widget()
{}

main.cpp:

#include <QtGui/QApplication>
#include "Widget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

参考资料:

  1. QT实验分析教程

Qt中的基础图形绘制相关推荐

  1. python Numpy 的基础用法以及 matplotlib 基础图形绘制

    python Numpy 的基础用法以及 matplotlib 基础图形绘制 1. 环境搭建 1.1 Anaconda ​ anaconda 集成了数据分析,科学计算相关的所有常用安装包,比如Numo ...

  2. SVG.js 基础图形绘制整理(二)

    一.折线 var draw = SVG('svg1').size(300, 300); //画折线 //使用字符串点 // var polyline=draw.polyline('0,0 100,50 ...

  3. 安卓自定义View基础05-Canvas之基础图形绘制,点,线,矩形,圆,椭圆,弧形等

    一.Canvas简介 Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础, 源码中关于Canvas的解释: The Canvas class holds the &q ...

  4. python turtle库画图案-Python基础图形绘制库——turtle

    (1).介绍 turtle库也叫海龟库,是turtle绘图体系的Python实现.turtle库是Python语言的标准库之一,是入门级的图形绘制函数库. turtle绘图体系:也叫海龟绘图系统,它是 ...

  5. Qt中的图像处理与绘制

    文章目录 1 图像处理与绘制 1.1 QImage和QPixImage 1.2 简单图像处理 1.3 屏幕截图 1 图像处理与绘制 1.1 QImage和QPixImage 设备无关图像类-QImag ...

  6. R语言基础图形绘制——箱线图

    R语言绘制箱线图 简介 1. 基础函数-`boxplot()` 2. `ggplot()`函数 简介 箱线图主要是通过四分位数描述数据分布,通过最大值,上四分位数,中位数,下四分位数,最小值五处位置描 ...

  7. OpenGL 基础图形绘制与投影变换

    本文参考<Computer Graphics Using OpenGL>,第一个例子绘制了 1. 参数定义的House 2. a flurry of filled rectangles 3 ...

  8. turtle基础图形绘制2-同心圆套娃正方形蟒蛇连体五角星

    1.同心圆 circle函数 import turtle turtle.pensize(2) turtle.circle(10) turtle.circle(40) turtle.circle(80) ...

  9. QT中使用OpenGL绘制图形

    Qt Creator中的3D绘图及动画教程(参照NeHe) 刚刚学习了Qt Creator,发现Qt提供了QtOpenGL模块,对OpenGL做了不错的封装,这使得我们可以很轻松地在Qt程序中使用Op ...

最新文章

  1. python-docx 使用教程_python docx 中文字体设置的操作方法
  2. NumPy 生成全0矩阵,全1矩阵,随机矩阵,求平均数,求方差的方法
  3. 核心动画--基本动画
  4. python配置pip_Python pip源配置
  5. python __slots__ [转]
  6. python http请求_python模拟http请求
  7. windows process activation service不能安装或启动的解决办法
  8. tinyxml读xml
  9. Levis(李维斯)网上专卖店 - 不讲信用,请大家一定注意!
  10. 大漠插件:找图位置偏移(超出界面边界)
  11. “数据科学”课程群与 “数据科学导论”课程建设初探
  12. node处理图片和PDF文件方法
  13. Node+puppeteer学习笔记(五)--API问题解决--使用功能强大的“ eval ”函数
  14. 在腾讯云上申请一个免费的centos系统,将编好的python程序和c程序上载到centos系统,
  15. ArcEngine符号化——点密度符号
  16. python是一种解释型、面向什么的计算机程序设计语言_python语言是一种什么类型...
  17. 一次线上的502错误排查问题
  18. MySQL的循环语句使用总结
  19. python发送邮件封装
  20. C#垃圾回收机制GC

热门文章

  1. 前端dashboard框架_微前端在网易七鱼的实践
  2. 3.10 程序示例--神经网络设计-机器学习笔记-斯坦福吴恩达教授
  3. [python] import后的模块是否能del移除掉
  4. Android ramdisk.img system.img userdata.img 介绍与使用
  5. 基于FPGA的LED点阵系统开发
  6. vue.js组件学习(上)
  7. Citrix Port(常用端口)
  8. Swift - static和class的使用
  9. sscanf函数—(sprintf的反)
  10. poj 1789 Truck History(最小生成树 prim)