原理
- QPainter用来执行绘图操作
- QPaintDevice提供绘图设备,它是一个二维空间的抽象,可以使用QPainter在其上进行绘制
- QPaintEngine介于QPainter和QPaintDevice对象之间,它的存在使得QPainter可以以统一的方法在不同QPaintDevice上绘图
QPainter类
常用函数
1.设置绘图工具
- setPen //设置画笔
- setBrush //设置画刷
- setFont //设置字体
- setBackgroundMode //设置背景模式
2.绘制图形和文字
- drawPoint() //点
- drawPoints() //多个点
- drawLine() //线
- drawLines() //多条线
- drawRect() //矩形
- drawRects() //多个矩形
- drawRoundedRect() //圆角矩形
- drawEllipse() //椭圆
- drawArc() //圆弧
- drawPie() //扇形图
- drawPolyline() //多折线
- drawPolygon() //多边形
- drawConvexPolygon() //凸多边形
- drawPixmap()/ drawImage() //位图
- drawText() //文字
- drawPath() //按路径绘制
painter->drawLine(20, 20, 100, 120); //画一条 (20,20) 到 (100,120) 的线段
painter->drawEllipse(20,20,210,160); //椭圆左上角的坐标+椭圆的宽度和高度
painter->drawRect(20,20,210,160); //矩形左上角坐标+宽和高
painter->drawRoundRect(20,20,210,160,50,50); //最后两个参数决定圆角大小,可为0到99的数值(99代表圆)
paint->drawPie(20,20,210,160,0,500); //前四个参数定义与drawEllipse()相同。后两个参数定义圆的样式。0为起始角度(单 位为1/16度),500为扇形所展开的角度(单位也为1/16度)
paint->drawArc(20,20,210,160,500,1000); //drawArc()函数与drawPie()函数的参数完全相同
3.坐标变换
- rotate() //旋转
- translate() //平移
- scale() //缩放
- shear() //扭曲
绘图一般流程
-
定义QPainter对象(变量)
-
在paintEvent函数中,使用对象的方法(成员函数)绘制各种图形或文字
-
也可以在其他事件处理函数中用以上方法绘图,并且调用repaint函数重新刷新屏幕(重绘)
举例
1.Widget.h
protected:
void paintEvent(QPaintEvent *); //函数名和参数不能错,不是自定义函数
2.Widget.cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(Qt::blue); //设置蓝色画笔
painter.setFont(QFont("Arial", 30)); //设置字体
//在客户区中央输出文字
painter.drawText(rect(), Qt::AlignCenter, "Qt");
painter.drawEllipse(QRect(0, 0, width()-1, height()-1));
}
运行结果:
QPen类
点类(QPoint 和 QPointF)
QPoint或QPointF 类代表一个坐标点。它包含一个横坐标和一个纵坐标,前者数值为int型,后者数值为float型。
- void setX(int x); //设置横坐标为 x
- void setY(int y); //设置纵坐标为 y
举例
1.画直线
QPoint p1(0,0), p2(100,100);
painter.drawLine(p1,p2);
2.画多边形
QPoint points[4] = {
QPoint(10,80),QPoint(20,10),
QPoint(80,30),QPoint(90,70)
};
painter.drawPolygon(points, 4);
线段类(QLine 和 QLineF)
Qline 和 QLineF代表一个线段,前者数值为int型,后者数值为float型。
构造函数
-
QLine::QLine(const QPoint & p1,const QPoint & p2) //线段(x1,y1)到(x2,y2)
QLine::QLine(int x1, int y1, int x2, int y2)
其他函数
- void QLine::setP1(const QPoint & p1) //设置点1
- void QLine::setP2(const QPoint & p2) //设置点2
- void QLine::setLine(int x1, int y1, int x2, int y2 //设置点(x1,y1)和(x2,y2)
- int x1() / x2() / y1() / y2() //返回坐标x1,x2,y1,y2
矩形类(QRect 和 QRectF)
构造函数
- QRect r1(100, 200, 110, 160); //矩形对象 r1的左上角为(100,200),宽110、高160
其他函数
- int x(); //获取左上角x坐
- int y(); //获取左上角y坐标
- void setX(int x); //设置左上角x坐标
- void setY(int y); //设置左上角y坐标
- int width(); //获取矩形宽度
- int height(); //获取矩形高度
- void setWidth(int width); //设置矩形宽度
- void setHeight(int height); //设置矩形高度
- void moveTo(int x, int y) //将矩形左上角移动到(x,y)
- void moveTo(const QPoint & pos) //将矩形左上角移动到坐标点pos
- QPoint center () //返回矩形中心点
- bool contains ( int x, int y ) //判断点是否在当前矩形内部
- bool contains(const QPoint &point, bool proper=false)
颜色类(QColor)
QColor支持RGB、HSV、CMYK颜色模型。还支持alpha混合(透明度)的模式。RGB是面向硬件的模型,颜色由红绿蓝三种基色混合而成。
- QColor( 250, 250, 200) //定义颜色对象,红绿蓝分别是250、250、200
- QColor(255, 0, 0, 127) // 第四个为透明度(其中透明度为0~255,0为完全透明、255为不透明)
- QColor(Qt::green) //使用Qt的枚举类型
屏幕重绘
在Qt中,paintEvent函数是进行重绘的。只要出现以下几种情况,系统就会产生屏幕重绘事件,从而自动调用paintEvent方法。
- 当窗口部件第一次显示时;
- 重新调整窗口部件大小,或者窗口从隐藏到显示;
- 当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件。
但是如果遇到如下情况:
-
有些时候,程序窗口并没有发生大小改变或从隐藏到显示等情况(即没有产生屏幕重绘事件),但是由于某种情况的发生也需要对窗口进行重绘。
-
比如要实现用户点击窗口内任意位置就在此处画一个圆,或者随着时间流逝周期性的在窗口中显示时间,这时就需要主动地进行屏幕重绘。
此时就需要QWidget的函数update()或者repaint()可以实现主动屏幕重绘(就是调用一次paintEvent函数?应该是。。)。
update()和 repaint()差别:
- repaint()函数被调用之后,立即执行重绘。因此repaint最快的;
- update()调用后并不立即重绘,而是将重绘事件放入事件循环中,由主窗口的事件循环来统一调度
update()函数
- void QWidget::update(int x, int y, int w, int h) //重绘(x, y)为左上角,w为宽,h为高的区域(重绘一个矩形区域)
- void QWidget::update(const QRect & rect)
除此之外,还有timerEvent函数,它在timer每次到时间时都会被触发一次
简单实例(文字,线段,矩形,椭圆,图片的绘制)
综合实例——时钟的绘制
新建基于QWidget类的程序。创建时取消ui界面
1.Widget.h
float radius; // 时钟半径
//指针针尖坐标
int xSecond, ySecond, xMinute, yMinute, xHour, yHour;
int xCenter, yCenter; //时钟中心坐标
int second,minute,hour; //时分秒的实际数字
void CalcPosition(); //计算三种指针针尖坐标的函数
protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *event);
2.Widget.cpp
#include <qmath.h> // 数学库
#include <QPainter>
#define PI 3.14159265 // 圆周率
void Widget::CalcPosition()
{ float secondHandLen, minuteHandLen, hourHandLen;
secondHandLen = radius*0.8; //计算秒针长度
minuteHandLen = radius*0.65; //计算分针长度
hourHandLen = radius*0.5; //计算时针长度
// 计算秒针针尖位置
xSecond = xCenter+secondHandLen*cos(second*PI/30-PI/2);
ySecond = yCenter+secondHandLen*sin(second*PI/30-PI/2);
// 计算分针针尖位置
xMinute = xCenter+minuteHandLen*cos(minute*PI/30-PI/2);
yMinute = yCenter+minuteHandLen*sin(minute*PI/30-PI/2);
// 计算时针针尖位置
xHour=xCenter + hourHandLen*cos((hour+1.0*minute/60)*PI/6-PI/2);
yHour = yCenter + hourHandLen*sin((hour+1.0*minute/60)*PI/6-PI/2);
}
Widget::Widget(QWidget *parent) : QWidget(parent)
{
radius = 100;
xCenter = 120, yCenter=120;
hour = 3, minute = 56, second = 55; //初始时间 3:56:55
CalcPosition(); //计算初始位置用于第一次显示
startTimer(100); //启动定时器,为了便于观察,加速10倍
}
void Widget::timerEvent(QTimerEvent *e)
{
CalcPosition(); // 计算位置
second++; // 秒增加
if(second==60)
{
second = 0;
minute++; // 分增加
}
if(minute==60) {
minute = 0;
hour++; // 时增加
}
update();
}
void Widget::paintEvent(QPaintEvent *) {
QPainter painter(this);
QPen pen; // 画笔的使用请参考下一节
painter.drawEllipse(QPointF(120.0,120.0),radius,radius);
painter.drawLine(xCenter,yCenter, xSecond,ySecond); //秒针
pen.setWidth(2); // 画笔设置宽度
painter.setPen(pen); //使用画笔
painter.drawLine(xCenter,yCenter, xMinute,yMinute); //分针
pen.setWidth(4);
painter.setPen(pen);
painter.drawLine(xCenter,yCenter, xHour,yHour); // 时针
}
CalcPosition() 函数中计算针尖角度其实可以不用这么绕来绕去,ppt中给出的解释是:
注意,Qt中坐标是x轴横向向右为正,y轴垂直向下为正,所以0度对应水平向右,顺时针方向是度数增加。但是钟表应该是竖直向上位置为0度,顺时针方向为度数增加。所以这里计算旋转度数时减去PI/2弧度(即90度)。
可以画个sin和cos的波浪图,然后看指针转一圈对于x和y轴是要加还是要减,与波浪图相对应即可,不行的话+/- π/2 即可(左加右减)