目录
2D Painting Example
QPainter类将2D的绘图给QpaintDevice的子类,这个子类包括QWidget和QImage。
QGLWidget是QWidget的子类,所以他可以重写paintEvent或Qpainter在设备上画图。但是这个painteEvent和QPainter和普通的QWidget是不同的,如果本机的OpenGL支持绘图,那么将会得到硬件的加速支持。
本例中,QWidget和QGLWidget的绘图,并且QWidget还抗锯齿,QGLWidget如果硬件支持,也能抗锯齿。
Overview
这里使用了QGLWidget和QWidget描绘的界面进行对比,并且,这个对比很直观,就放在旁边,这里使用Helper类去画相同的画面。
Helper Class Definition
在这个例子,为了描绘相同的动画效果,用了Helper类去画相同的功能。
Helper类:
class Helper
{
public:
Helper();
public:
void paint(QPainter *painter, QPaintEvent *event, int elapsed);
private:
QBrush background;
QBrush circleBrush;
QFont textFont;
QPen circlePen;
QPen textPen;
};
除了构造函数,helper类还提供了painter函数去画东西。
Helper Class Implementation
构造函数的作用是初始化各个变量。
Helper::Helper()
{
QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));
background = QBrush(QColor(64, 32, 64));
circleBrush = QBrush(gradient);
circlePen = QPen(Qt::black);
circlePen.setWidth(1);
textPen = QPen(Qt::white);
textFont.setPixelSize(50);
}
绘制在paint()函数中使用QPainter类去在设备上画图。QPaintEvent提供了绘制区域的问题。
void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
painter->fillRect(event->rect(), background);
painter->translate(100, 100);
在转换坐标前,首先填充下painter的区域,这样其余的画图都会从被转换坐标开始。
画一个螺旋,指定时间做指定的动作,让看的人感觉它是向外旋转。
painter->save();
painter->setBrush(circleBrush);
painter->setPen(circlePen);
painter->rotate(elapsed * 0.030);
qreal r = elapsed / 1000.0;
int n = 30;
for (int i = 0; i < n; ++i) {
painter->rotate(30);
qreal factor = (i + r) / n;
qreal radius = 0 + 120.0 * factor;
qreal circleRadius = 1 + factor * 20;
painter->drawEllipse(QRectF(radius, -circleRadius,
circleRadius * 2, circleRadius * 2));
}
painter->restore();
在这个坐标系统中旋转了很多次,所以调用save()在让其复原,调用restore()。
painter->setPen(textPen);
painter->setFont(textFont);
painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter, QStringLiteral("Qt"));
}
Widget Class Definition
Widget使用helper类去绘画
class Helper;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(Helper *helper, QWidget *parent);
public slots:
void animate();
protected:
void paintEvent(QPaintEvent *event) override;
private:
Helper *helper;
int elapsed;
};
除了构造函数,还有paintEvent()函数,elapsed用于记录上次更新时间。
Widget Class Implementation
构造函数初始化各个成员。
Widget::Widget(Helper *helper, QWidget *parent)
: QWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(200, 200);
}
animate()槽函数在任一时间被调用。
void Widget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
update();
}
在paintEvent()中调用Helper类实现重绘。
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}
GLWidget Class Definition
GLWidget用于展示OpenGL绘图界面。
class Helper;
class GLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
GLWidget(Helper *helper, QWidget *parent);
public slots:
void animate();
protected:
void paintEvent(QPaintEvent *event) override;
private:
Helper *helper;
int elapsed;
};
Helper类绘图,elapsed记录上一次更新的时间。
GLWidget Class Implementation
构造函数与Widget的构造函数是有差异的。
GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QOpenGLWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(200, 200);
setAutoFillBackground(false);
}
QGL::SampleBuffers这个标识可以设置OpenGL抗锯齿,如果系统没有OpenGLDriver话是开启不成功的。可以设置OpenGL抗锯齿,如果系统没有OpenGLDriver话是开启不成功的。
animate()和widget一样。
void GLWidget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
update();
}
paintEvent()和widget一样。
void GLWidget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}
Window Class Definition
window类:
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private:
Helper helper;
};
包含一个Helper用于传给上面的两个界面。
Window Class Implementation
构造函数初始化,构造界面,以及布局:
Window::Window()
{
setWindowTitle(tr("2D Painting on Native and OpenGL Widgets"));
Widget *native = new Widget(&helper, this);
GLWidget *openGL = new GLWidget(&helper, this);
QLabel *nativeLabel = new QLabel(tr("Native"));
nativeLabel->setAlignment(Qt::AlignHCenter);
QLabel *openGLLabel = new QLabel(tr("OpenGL"));
openGLLabel->setAlignment(Qt::AlignHCenter);
QGridLayout *layout = new QGridLayout;
layout->addWidget(native, 0, 0);
layout->addWidget(openGL, 0, 1);
layout->addWidget(nativeLabel, 1, 0);
layout->addWidget(openGLLabel, 1, 1);
setLayout(layout);
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, native, &Widget::animate);
connect(timer, &QTimer::timeout, openGL, &GLWidget::animate);
timer->start(50);
}
每50毫秒重绘一下,大约每秒20帧。