2D 페인팅 예제
이 2D 페인팅 예제는 QPainter 및 QOpenGLWidget 을 함께 사용하여 지원되는 하드웨어에서 가속화된 2D 그래픽을 표시하는 방법을 보여줍니다.

QPainter 클래스는 QWidget 및 QImage 와 같이 QPaintDevice 의 서브클래스가 제공하는 페인트 장치에 2D 그래픽 프리미티브를 그리는 데 사용됩니다.
QOpenGLWidget 는 QWidget 의 하위 클래스이므로, QWidget 에서와 마찬가지로 paintEvent() 메서드를 재구현하고 QPainter 를 사용하여 디바이스에 그리기를 수행할 수 있습니다. 유일한 차이점은 시스템의 OpenGL 드라이버가 이를 지원하는 경우, 그리기 작업이 하드웨어에서 가속화된다는 점입니다.
이 예제에서는 QWidget 와 QOpenGLWidget 에서 동일한 그리기 작업을 수행합니다. QWidget 는 앤티앨리어싱이 활성화된 상태로 표시되며, QOpenGLWidget 도 시스템의 OpenGL 드라이버가 필요한 확장 기능을 지원하는 경우 앤티앨리어싱을 사용합니다.
개요
QOpenGLWidget 의 서브클래스에 대한 페인팅 결과와 QWidget 의 서브클래스에서 수행되는 네이티브 드로잉 결과를 비교할 수 있도록, 두 종류의 위젯을 나란히 표시하고자 합니다. 이를 위해 QWidget 과 QOpenGLWidget 의 서브클래스를 파생시키고, 별도의 Helper 클래스를 사용하여 각 클래스에 대해 동일한 페인팅 작업을 수행한 뒤, Window 클래스가 제공하는 최상위 위젯에 배치합니다.
헬퍼 클래스 정의
이 예제에서는 헬퍼 클래스가 그리기 작업을 수행합니다. 이는 QWidget 하위 클래스와 QOpenGLWidget 하위 클래스 모두에 대해 동일한 그리기 작업이 수행되도록 하기 위함입니다.
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;
};생성자를 제외하면, 위젯 하위 클래스 중 하나가 제공하는 페인터를 사용하여 그리기 작업을 수행하는 ` paint() ` 함수만 제공합니다.
헬퍼 클래스 구현
이 클래스의 생성자는 위젯에 콘텐츠를 그리는 데 필요한 리소스를 설정합니다:
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() ` 함수에서 수행됩니다. 이 함수는 이미 페인트 장치( QWidget 또는 QOpenGLWidget)에 그리도록 설정된 ` QPainter `, 그리기 대상 영역에 대한 정보를 제공하는 ` QPaintEvent `, 그리고 페인트 장치가 마지막으로 업데이트된 이후 경과된 시간(밀리초 단위)을 매개변수로 받습니다.
void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
painter->fillRect(event->rect(), background);
painter->translate(100, 100);먼저 페인트 이벤트에 포함된 영역을 채우는 것으로 그리기를 시작하고, 이후 좌표계의 원점을 변환하여 나머지 그리기 작업이 페인트 장치의 중심 쪽으로 이동되도록 합니다.
지정된 경과 시간을 사용하여 원들의 나선형 패턴을 그리며, 원들이 좌표계의 원점을 중심으로 바깥쪽으로 움직이는 것처럼 보이도록 애니메이션을 적용합니다:
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()`를 호출하여 ` QPainter`의 상태를 저장해 두고, 작업이 끝난 후 ` restore()`를 호출하여 상태를 복원합니다.
painter->setPen(textPen);
painter->setFont(textFont);
painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter, QStringLiteral("Qt"));
}효과를 완성하기 위해 원점에 텍스트를 그립니다.
위젯 클래스 정의
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() 함수와 콘텐츠에 애니메이션을 적용하는 데 사용되는 슬롯만 포함되어 있습니다. 한 멤버 변수는 위젯이 콘텐츠를 그리는 데 사용하는 Helper 를 추적하고, 다른 멤버 변수는 마지막으로 업데이트된 이후 경과한 시간을 기록합니다.
위젯 클래스 구현
생성자는 전달된 ` Helper ` 객체를 저장하고 기본 클래스의 생성자를 호출하여 멤버 변수를 초기화할 뿐이며, 위젯의 크기를 고정으로 설정합니다:
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();
}여기서 우리는 타이머가 마지막으로 타임아웃된 이후 경과한 간격을 계산하고, 위젯을 다시 그리기 전에 이 값을 기존 값에 더합니다. Helper 클래스에서 사용되는 애니메이션은 1초마다 반복되므로, 모듈로 연산자를 사용하여 elapsed 변수가 항상 1000보다 작도록 보장할 수 있습니다.
Helper 클래스가 실제 그리기 작업을 모두 수행하므로, 위젯에 대한 QPainter 을 설정하고 헬퍼의 paint() 함수를 호출하는 페인트 이벤트만 구현하면 됩니다:
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}GLWidget 클래스 정의
GLWidget 클래스 정의는 QOpenGLWidget 에서 파생되었다는 점을 제외하면 기본적으로 Widget 클래스와 동일합니다.
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 `와 이전 업데이트 이후 경과된 시간을 기록합니다.
GLWidget 클래스 구현
생성자는 Widget 클래스의 생성자와 약간 다릅니다.
GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QOpenGLWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(200, 200);
setAutoFillBackground(false);
}elapsed 멤버 변수가 초기화되고, 위젯을 그리는 데 사용되는 Helper 객체가 저장됩니다.
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();
}안티앨리어싱은 가능한 경우 자동으로 활성화되므로, 위젯에 ` QPainter `을 설정하고 헬퍼의 ` paint() ` 함수를 호출하기만 하면 위젯의 내용을 표시할 수 있습니다.
Window 클래스 정의
Window 클래스는 기본적이고 간결한 정의를 가지고 있습니다:
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private:
Helper helper;
};이 클래스에는 모든 위젯에서 공유될 단일 Helper 객체가 포함되어 있습니다.
Window 클래스 구현
생성자가 모든 작업을 수행하며, 각 유형의 위젯을 생성하고 레이블과 함께 레이아웃에 삽입합니다:
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밀리초 타임아웃을 가진 타이머가 생성되며, 이 타이머는 ` Widget ` 및 ` GLWidget ` 객체의 ` animate() ` 슬롯에 연결됩니다. 일단 시작되면 위젯은 초당 약 20프레임의 속도로 업데이트되어야 합니다.
예제 실행
이 예제는 Widget 와 GLWidget 에서 동시에 수행되는 동일한 그리기 작업을 보여줍니다. GLWidget 의 렌더링 품질과 속도는 시스템의 OpenGL 드라이버가 제공하는 멀티샘플링 및 하드웨어 가속 지원 수준에 따라 달라집니다. 이 중 하나라도 지원되지 않는 경우, 드라이버는 품질을 희생하고 속도를 우선시하는 소프트웨어 렌더러로 대체될 수 있습니다.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.