一、描述
1、坐标系由QPainter类控制。QPainter与QPaintDevice和QPaintEngine类一起构成了Qt绘画系统的基础:QPainter用于执行绘制操作,QPaintDevice是可以使用QPainter绘制的二维空间的抽象,QPaintEngine提供了绘制器用来在不同类型的设备上绘制的接口。
2、QPaintDevice类是可以绘制的对象的基类:它的绘制功能由QWidget,QImage,QPixmap,QPicture和QOpenGLPaintDevice类继承。绘画设备的默认坐标系的原点位于左上角。x值向右增加,y值向下增加。在基于像素的设备上,默认单位是一个像素,在打印机上,默认单位是一个点(1/72英寸)。
二、渲染
2.1、走样绘制
QPainter默认是走样绘制的,如使用一像素宽的画笔绘制时:
QPainter painter(this);
painter.setPen(Qt::darkGreen);
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);
painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);
使用像素数为偶数的笔进行渲染时,将在数学定义的点周围对称地渲染像素。
使用像素数为奇数的笔进行渲染时,将在数学点的右边和下方渲染备用像素。
例:绘制如下矩形时:
QRect::right()和QRect::bottom()函数的返回值偏离矩形的真实右下角。
QRect的right()函数返回left()+ width()-1,bottom()函数返回top()+ height()-1。上图中右下角的绿点显示了这些函数的返回坐标。
QRectF类使用浮点坐标定义平面中的矩形可以提高准确性(QRect使用整数坐标),QRectF::right()和QRectF::bottom()函数确实返回真正的右下角。
或者,使用QRect,应用x()+ width()和y()+ height()来找到右下角,并避免使用right()和bottom()函数。
2.2、反走样(抗锯齿)绘制
如果设置QPainter抗锯齿渲染绘制,则像素将在数学定义的点的两侧对称地渲染:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);
三、坐标变换
默认情况下,QPainter在关联设备的坐标系上运行,但它也完全支持仿射坐标变换。
- QPainter::scale()按给定的偏移量缩放坐标系。
- QPainter::rotate()顺时针旋转坐标系。
- QPainter::translate()平移坐标系。
四、窗口-视口转换
使用QPainter进行绘制时,我们使用逻辑坐标指定点,然后将其转换为绘画设备的物理坐标。
逻辑坐标到物理坐标的映射由QPainter::worldTransform()以及QPainter::viewport()和QPainter::window()处理。视口viewport()表示物理坐标。“窗口”window()表示逻辑坐标。默认情况下,逻辑坐标系和物理坐标系重合,并且等效于绘画设备的矩形。例:
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setWindow(QRect(0, 0, 150, 150));
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setPen(QPen(Qt::red, 5, Qt::DashDotLine));
painter.drawLine(QPoint(20,20),QPoint(200,200));
}
设置不管弹窗实际上多大,都将窗口映射为逻辑坐标QRect(0, 0, 150, 150)的范围。效果:
窗口-视口转换只是一个线性变换,即它不执行剪裁。即它将在窗口预计要在窗口坐标显示的内容移到视口区域。例:
void Widget::paintEvent(QPaintEvent *event)
{
auto rect = event->rect();
QPainter painter(this);
painter.setViewport(QRect(20,20,200,200));
painter.setPen(QPen(Qt::red,5));
QFont font;
font.setPixelSize(40);
painter.setFont(font);
painter.drawRect(QRect(0,0,50,50));
painter.drawRect(QRect(300,300,50,50));
painter.drawRect(QRect(600,600,50,50));
painter.setPen(QPen(Qt::cyan,5));
painter.drawRect(rect);
qDebug()<<rect;
}
将逻辑上应该在窗口范围内显示的内容显示到视口设置的矩形范围内。如上图,这个窗口的尺寸是300*300,正常的这时候能看到的矩形是QRect(0,0,50,50)那个,另外的几个拉大窗口才能看到。设置视口矩形之后,根据拖动的窗口大小,这时候根据逻辑坐标应该显示在窗口可见的绘制内容会显示在视口矩形范围之内。
对比查看: