1、抗锯齿渲染
由于历史原因,QRect::right()和QRect::bottom()的返回值会偏离矩形真实的右下角,推荐使用QRectF来代替QRect,或者使用x() + width()和y() + height()来确定QRect的右下角。
默认情况下,绘制会产生锯齿,可以使用QPainter::setRenderHint(RenderHint hint, bool on = true)来打开抗锯齿渲染,其中hint指定渲染方式,如QPainter::Antialiasing。
例如以下为关闭和打开QPainter::Antialiasing抗锯齿渲染的效果:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawRect(1, 2, 20, 10); QPainter painter(this); painter.drawLine(2, 7, 6, 1); }
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.drawRect(1, 2, 20, 10); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.drawLine(2, 7, 6, 1); }
2、坐标变换
坐标变换有基本变换、窗口-视口变换。
①、基本变换
平移坐标系统:QPainter::translate()
旋转坐标系统:QPainter::rotate()
缩放坐标系统:QPainter::scale()
扭曲坐标系统:QPainter::shear()
保存当前坐标系统:QPainter::save()
恢复保存的坐标系统:QPainter::restore()
下面为使用示例:
void Widget::paintEvent(QPaintEvent * event) { QPainter painter(this); painter.fillRect(rect(), Qt::white); painter.setPen(QPen(Qt::red, 11)); painter.drawLine(QPoint(5, 6), QPoint(100, 99)); painter.translate(200, 150);//将坐标系统平移,使(200, 150)作为坐标原点 //painter.translate(-200, -150);//这样可以还原原点为(0, 0) painter.setPen(QPen(Qt::darkBlue, 11)); painter.setRenderHint(QPainter::Antialiasing); painter.drawLine(QPoint(5, 6), QPoint(100, 99)); painter.save();//保存painter的当前状态 painter.rotate(90);//将坐标系统顺时针旋转90度 painter.setPen(QPen(Qt::cyan, 11)); painter.drawLine(QPoint(5, 6), QPoint(100, 99)); painter.restore();//恢复painter到以前的状态 painter.fillRect(-50, -50, 100, 50, QBrush(Qt::darkGreen)); painter.save(); painter.scale(0.5, 0.4);//将坐标系统进行缩放,水平为0.5倍,垂直为0.4倍 painter.fillRect(-50, -50, 100, 50, QBrush(Qt::yellow)); painter.restore(); painter.setPen(Qt::blue); painter.setBrush(Qt::darkYellow); painter.drawEllipse(QRect(60, -100, 50, 50)); painter.save(); painter.shear(1.5, -0.7);//将坐标系统进行扭曲 painter.setBrush(Qt::darkGray); painter.drawEllipse(QRect(60, -100, 50, 50)); painter.restore(); }
连续进行多个坐标转换的时候使用QTransform会更高效,下面使用QTimer定时器和QTransform坐标转换,模拟了简单时钟显示:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update()));//信号和槽 timer->start(1000); } void Widget::paintEvent(QPaintEvent * event) { static int angle = 0; angle += 10; if(angle == 360) angle = 0; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing);//抗锯齿 int sideMin = qMin(width(), height()); QTransform transform; transform.translate(width() / 2, height() / 2);//移动坐标原点至中心点 transform.rotate(angle);//将坐标系统顺时针旋转, 每次增加10° transform.scale(sideMin / 300, sideMin / 300);//将坐标系统缩放,以适应窗口放大 painter.setWorldTransform(transform);//进行坐标转换 painter.drawEllipse(-120, -120, 240, 240);//画圆 painter.drawLine(0, 0, 100, 0);//画指针 }
②、窗口-视口转换
使用QPainter的绘制函数进行绘制的时候使用的是逻辑坐标,它们最后会被转换为绘图设备的物理坐标来进行绘制。窗口是指逻辑坐标下的一个矩形,视口是物理坐标下的一个矩形。
QPainter::setWindow用来设置窗口的逻辑坐标,QPainter::setViewport用来设置视口物理坐标。