1. 本章介绍Qt的二维图形引擎,Qt的二维图形引擎是基于QPainter类的。<span style="color:#ff0000;">QPainter既可以绘制几何图形(点、线、矩形等),也可以绘制像素映射、图像和文字。此外QPainter还支持一些高级特性,例如反走样、像素混合、渐变填充和矢量路径等。QPainter也支持线性变换,例如平移、旋转、错切和缩放。</span>

QPainter可以画在“绘图设备”(QWidget、QPixmap、QImage和QSvgGenerator)上,也可以与QPrinter一起使用来打印文件和创建PDF文档。

重新实现QWidget::PaintEvent()可用于定制窗口部件,随心所欲的控制他们的外观

一项普通的需求是在二维画板上显示大量的、轻量级的、可以用户交互的、任意形状的项。

可使用OpenGL命令来代替QPainter。OPenGL是一个绘制三维图形的标准库。

8.1用QPainter绘图

想要在绘图设备上绘图,只需要创建一个QPainter,在将指针传到该设备中。

使用QPainter的draw...()函数,可以绘制各种各样的形状。绘制的效果取决于QPainter的设置。三个主要的设置是画笔、画刷、字体:

①画笔用来画线和边缘。QPen,设置属性setPen()

②画刷用来填充几何形状的图案。QBrush,设置属性setBrush()

③字体用来绘制文字。QFont,设置属性setFont()

绘制椭圆:

  1. <span style="color:#33cc00;BACKGROUND-COLOR: #ffffff">QPainter painter(this);
  2. painter.setRenderHint(QPainter::Antialiasing,true);
  3. painter.setPen(QPen(Qt::black,12,Qt::DashDotLine,Qt::RoundCap));
  4. painter.setBrush(QBrush(Qt::green,Qt::SolidPattern));
  5. painter.drawEllipse(80,80,400,240);</span>

setRenderHint(QPainter::Antialiasing,true)可以启用反走样,可在支持这一特性的平台和设备上得到平滑的边缘。

QPainterPath类可以通过连接基本的图形元素来确定任意的矢量图形:直线、椭圆、多边形等绘制路径。绘制路劲是基本的图元,任何图形或图形组合都可以用绘制路径描述。路径可以确定一个边缘,由边缘锁定的区域可以用画刷来填充。

在现代应用中,渐变填充已成为单色填充的流行替代品。渐变填充利用颜色差值使得两个或更多颜色之间能够平滑的过度。

Qt支持3种类型的渐变:

线性渐变,由两个控制点定义,连接这两点的线上有一系列的颜色断点。

锥形渐变,由一个中心点和一个角度定义。

辐射渐变,由一个中心点、半径、一个焦点,以及颜色断点定义。颜色由焦点向外扩散,焦点可以是中心点或者圆内的其他点。

QPainter还有其他影响图形和文字绘制方式的设置这里不详细介绍了。

8.2坐标系统变换       
        在QPainter的默认坐标系中,点(0,0)位于绘图设备的左上角,x坐标向右增长,y坐标向下增长。默认坐标系的每个像素占1x1大小的区域。

理论上像素的中心取决于半像素坐标,一个像素正好位于四个像素的重合处。如果不需要这种效果,可以通过制定半像素坐标或者通过便宜QPainter(+0.5,+0.5)来避免这种效果的出现。

QPainter的视口,是物理坐标系下制定的任意矩形。

QPainter的窗口也是指同一矩形,只不过是在逻辑坐标系下。这种窗口-视口机制对于编写独立于绘制设备大小和分辨率的绘制代码是有用的。

世界变换是在窗口-视口转换之外使用的变换矩阵。它允许移动、缩放、旋转或者拉伸绘制的项。

OvenTimer窗口部件代码

这个OvenTimer模仿烤箱的定时器,它是烤箱内置的钟表。用户可以单击刻度来设置持续时间。转轮会自动的逆时针转到0,OvenTimer在这一点发射timeout()信号。

ovenTimer.h

  1. #ifndef OVENTIMER_H
  2. #define OVENTIMER_H
  3. #include <QDateTime>
  4. #include <QWidget>
  5. class QTimer;
  6. class OvenTimer : public QWidget
  7. {
  8. Q_OBJECT
  9. public:
  10. OvenTimer(QWidget *parent = 0);
  11. void setDuration(int secs);
  12. int duration() const;
  13. void draw(QPainter *painter);
  14. signals:
  15. void timeout();
  16. protected:
  17. void paintEvent(QPaintEvent *event);
  18. void mousePressEvent(QMouseEvent *event);
  19. private:
  20. QDateTime finishTime;
  21. QTimer *updateTimer;
  22. QTimer *finishTimer;
  23. };
  24. #endif

oventimer.cpp

  1. #include <QtGui>
  2. #include <cmath>
  3. #ifndef M_PI
  4. #define M_PI 3.14159265359
  5. #endif
  6. #include "oventimer.h"
  7. const double DegreesPerMinute = 7.0;
  8. const double DegreesPerSecond = DegreesPerMinute / 60;
  9. const int MaxMinutes = 45;
  10. const int MaxSeconds = MaxMinutes * 60;
  11. const int UpdateInterval = 5;
  12. OvenTimer::OvenTimer(QWidget *parent)
  13. : QWidget(parent)
  14. {
  15. finishTime = QDateTime::currentDateTime();  //获取当前时间
  16. updateTimer = new QTimer(this);
  17. connect(updateTimer, SIGNAL(timeout()), this, SLOT(update()));
  18. finishTimer = new QTimer(this);
  19. finishTimer->setSingleShot(true);
  20. connect(finishTimer, SIGNAL(timeout()), this, SIGNAL(timeout()));
  21. connect(finishTimer, SIGNAL(timeout()), updateTimer, SLOT(stop()));
  22. QFont font;
  23. font.setPointSize(8);   //设置窗口字体的大小
  24. setFont(font);
  25. }
  26. void OvenTimer::setDuration(int secs)   //设置了烤箱定时器的持续时间为给定的秒数。
  27. {
  28. secs = qBound(0, secs, MaxSeconds); //防止越界0~MaxSeconds
  29. finishTime = QDateTime::currentDateTime().addSecs(secs);
  30. if (secs > 0) {
  31. updateTimer->start(UpdateInterval * 1000);
  32. finishTimer->start(secs * 1000);
  33. } else {
  34. updateTimer->stop();
  35. finishTimer->stop();
  36. }
  37. update();
  38. }
  39. int OvenTimer::duration() const //获取定时器完成前剩余的秒数。
  40. {
  41. int secs = QDateTime::currentDateTime().secsTo(finishTime);
  42. if (secs < 0)
  43. secs = 0;
  44. return secs;
  45. }
  46. void OvenTimer::mousePressEvent(QMouseEvent *event)
  47. {
  48. QPointF point = event->pos() - rect().center();
  49. double theta = std::atan2(-point.x(), -point.y()) * 180.0 / M_PI;
  50. setDuration(duration() + int(theta / DegreesPerSecond));
  51. update();
  52. }
  53. void OvenTimer::paintEvent(QPaintEvent * /* event */)
  54. {
  55. QPainter painter(this);
  56. painter.setRenderHint(QPainter::Antialiasing, true);
  57. int side = qMin(width(), height()); //返回两个参数中较小的一个
  58. painter.setViewport((width() - side) / 2, (height() - side) / 2,
  59. side, side);
  60. painter.setWindow(-50, -50, 100, 100);
  61. draw(&painter);
  62. }
  63. void OvenTimer::draw(QPainter *painter)
  64. {
  65. static const int triangle[3][2] = {
  66. { -2, -49 }, { +2, -49 }, { 0, -47 }
  67. };
  68. QPen thickPen(palette().foreground(), 1.5); //palette().foreground()得到笔刷
  69. QPen thinPen(palette().foreground(), 0.5);
  70. QColor niceBlue(150, 150, 200);
  71. painter->setPen(thinPen);
  72. painter->setBrush(palette().foreground());
  73. painter->drawPolygon(QPolygon(3, &triangle[0][0]));
  74. QConicalGradient coneGradient(0, 0, -90.0);
  75. coneGradient.setColorAt(0.0, Qt::darkGray);
  76. coneGradient.setColorAt(0.2, niceBlue);
  77. coneGradient.setColorAt(0.5, Qt::white);
  78. coneGradient.setColorAt(1.0, Qt::darkGray);
  79. painter->setBrush(coneGradient);
  80. painter->drawEllipse(-46, -46, 92, 92);
  81. QRadialGradient haloGradient(0, 0, 20, 0, 0);
  82. haloGradient.setColorAt(0.0, Qt::lightGray);
  83. haloGradient.setColorAt(0.8, Qt::darkGray);
  84. haloGradient.setColorAt(0.9, Qt::white);
  85. haloGradient.setColorAt(1.0, Qt::black);
  86. painter->setPen(Qt::NoPen);
  87. painter->setBrush(haloGradient);
  88. painter->drawEllipse(-20, -20, 40, 40);
  89. QLinearGradient knobGradient(-7, -25, 7, -25);
  90. knobGradient.setColorAt(0.0, Qt::black);
  91. knobGradient.setColorAt(0.2, niceBlue);
  92. knobGradient.setColorAt(0.3, Qt::lightGray);
  93. knobGradient.setColorAt(0.8, Qt::white);
  94. knobGradient.setColorAt(1.0, Qt::black);
  95. painter->rotate(duration() * DegreesPerSecond);
  96. painter->setBrush(knobGradient);
  97. painter->setPen(thinPen);
  98. painter->drawRoundRect(-7, -25, 14, 50, 99, 49);
  99. for (int i = 0; i <= MaxMinutes; ++i) {
  100. if (i % 5 == 0) {
  101. painter->setPen(thickPen);
  102. painter->drawLine(0, -41, 0, -44);
  103. painter->drawText(-15, -41, 30, 30,
  104. Qt::AlignHCenter | Qt::AlignTop,
  105. QString::number(i));
  106. } else {
  107. painter->setPen(thinPen);
  108. painter->drawLine(0, -42, 0, -44);
  109. }
  110. painter->rotate(-DegreesPerMinute);
  111. }
  112. }

8.3用QImage高质量绘图

绘图时,我们可能需要面对速度和准确率的折中问题

C++ GUI Qt4学习笔记08的更多相关文章

  1. C++ GUI Qt4学习笔记01

    C++ GUI Qt4学习笔记01   qtc++signalmakefile文档平台 这一章介绍了如何把基本的C++只是与Qt所提供的功能组合起来创建一些简单的图形用户界面应用程序. 引入两个重要概 ...

  2. C++ GUI Qt4学习笔记03

    C++ GUI Qt4学习笔记03   qtc++spreadsheet文档工具resources 本章介绍创建Spreadsheet应用程序的主窗口 1.子类化QMainWindow 通过子类化QM ...

  3. C++ GUI Qt4学习笔记09

    C++ GUI Qt4学习笔记09   qtc++ 本章介绍Qt中的拖放 拖放是一个应用程序内或者多个应用程序之间传递信息的一种直观的现代操作方式.除了剪贴板提供支持外,通常它还提供数据移动和复制的功 ...

  4. C++ GUI Qt4学习笔记05

    C++ GUI Qt4学习笔记05   qtc++正则表达式 QIntValidator           --  只让用户输入整数 QDoubleValidator     --  只让用户输入浮 ...

  5. C++ GUI Qt4学习笔记07

    C++ GUI Qt4   qtc++scrollobject编程 事件(event)是由串口系统或者Qt自身产生的,用以响应所发生的各类事情.当用户按下或者松开键盘或者鼠标上的按键时,就可以产生一个 ...

  6. 【QT】C++ GUI Qt4 学习笔记1

    Find对话框实现 平台 Qt5.3.2 MinGW4.8.2 注意创建时用QDialog finddialog.h #ifndef FINDDIALOG_H #define FINDDIALOG_H ...

  7. 【QT】C++ GUI Qt4 学习笔记2

    Go To Cell 利用QT Desinger做好界面后加入的代码有 gotocelldialog.h #ifndef GOTOCELLDIALOG_H #define GOTOCELLDIALOG ...

  8. 【QT】C++ GUI Qt4 学习笔记3

    菜单界面的实现. 看书上第三章,好长,好多代码.我敲了半天,想看看效果,结果却显示不出来.仔细一看,发现spreadsheet的实现在第四章.郁闷.... 又到官网上下代码,结果居然不能运行.难道是因 ...

  9. 【QT】C++ GUI Qt4 学习笔记4

    感觉这本书的顺序设计的太不合理了,出现的最多的一句话就是后面会讲.按照使用的顺序讲不行吗?搞得代码都运行不了. 我决定先直接跳到73页,子类化QTableWidgetItem这一节.因为前面功能的实现 ...

随机推荐

  1. C++ STL 关于双向链表list的splice函数

    转载自https://blog.csdn.net/qjh5606/article/details/85881680 list::splice实现list拼接的功能.将源list的内容部分或全部元素删除 ...

  2. Windows命令集锦

    1.用于私网的IP地址段: 10.0.0.0/8: 10.0.0.0-10.255.255.255 172.16.0.0/12: 172.16.0.0-172.31.255.255 192.168.0 ...

  3. 浅谈 JVM 结构体系、类加载、JDK JRE JVM 三者的关系

    一.java类,创建.编译.到运行的工程: 1.随便建一个Java类,保存后就是一个.java文件, 2.然后我们使用 javac命令编译 .java文件,生产 .class文件. 3.再然后使用 j ...

  4. 一次性计划任务at与周期性计划任务crontab

    一.at一次性计划任务使用 at语法格式: at 时间 at设置计划任务 1.下载at程序 [root@li ~]# yum install at -y 2.启动atd服务 [root@li ~]# ...

  5. 20191127 Spring Boot官方文档学习(5)

    5.Spring Boot Actuator:可投入生产的功能 Spring Boot包含许多其他功能,可帮助您在将应用程序投入生产时监控和管理您的应用程序.您可以选择使用HTTP端点或JMX管理和监 ...

  6. MySQL数据类型之整型

    还一个   Decimal 就是这么创建 查看当前数据表 查看tb1得表得所有记录....

  7. [转帖]CentOS 7 使用kubeadm 部署 Kubernetes

    CentOS 7 使用kubeadm 部署 Kubernetes   关闭swap 执行swapoff临时关闭swap. 重启后会失效,若要永久关闭,可以编辑/etc/fstab文件,将其中swap分 ...

  8. bind call apply 的区别和使用

    bind call apply 的区别和使用:https://www.jianshu.com/p/015f9f15d6b3 在讲这个之前要理解一些概念,这些概念很重要,有人说过学会了javascrip ...

  9. gRPC go安装教程

    安装protobuf go get -u github.com/golang/protobuf/proto go get -u github.com/golang/protobuf/protoc-ge ...

  10. P3198 [HNOI2008]遥远的行星

    传送门 发现 $A$ 不大,又允许较大的误差,考虑乱搞 考虑求出每个位置的答案,因为有 $1e5$ 个位置,所以每个位置差不多可以计算 $100$ 次贡献 所以把每个可以贡献的位置尽量均匀分成 $10 ...