2D 페인팅 예제
2D 페인팅 예제는 QPainter 및 QOpenGLWidget 을 함께 사용하여 지원되는 하드웨어에 가속화된 2D 그래픽을 표시하는 방법을 보여줍니다.
QPainter 클래스는 QWidget 및 QImage 과 같은 QPaintDevice 서브클래스가 제공하는 페인트 장치에 2D 그래픽 프리미티브를 그리는 데 사용됩니다.
QOpenGLWidget 는 QWidget 의 서브클래스이므로 paintEvent()를 다시 구현하고 QPainter 를 사용하여 QWidget 에서와 마찬가지로 장치에 그릴 수 있습니다. 유일한 차이점은 시스템의 OpenGL 드라이버가 지원하는 경우 하드웨어에서 페인팅 작업이 가속화된다는 것입니다.
이 예에서는 QWidget 와 QOpenGLWidget 에서 동일한 페인팅 작업을 수행합니다. QWidget 는 안티앨리어싱이 활성화된 상태로 표시되며, QOpenGLWidget 는 시스템의 OpenGL 드라이버에서 필요한 확장이 지원되는 경우 안티앨리어싱을 사용합니다.
개요
QOpenGLWidget 서브클래스에 페인팅한 결과와 QWidget 서브클래스의 기본 드로잉 결과를 비교하기 위해 두 종류의 위젯을 나란히 표시하고 싶습니다. 이를 위해 별도의 Helper
클래스를 사용하여 QWidget 및 QOpenGLWidget 의 하위 클래스를 파생하여 각각에 대해 동일한 페인팅 작업을 수행하고, 최상위 위젯에 배치하고, 그 자체로 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();
이 과정에서 좌표계가 여러 번 회전하므로 QPainter 의 상태를 미리 save()하고 나중에 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
클래스에서 사용되는 애니메이션은 매초마다 반복되므로 모듈로 연산자를 사용하여 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
클래스에는 기본적인 최소한의 정의가 있습니다:
class Window : public QWidget { Q_OBJECT public: Window(); private: Helper helper; };
모든 위젯 간에 공유될 단일 Helper
객체를 포함합니다.
창 클래스 구현
생성자가 모든 작업을 수행하여 각 유형의 위젯을 생성하고 레이블과 함께 레이아웃에 삽입합니다:
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 드라이버가 제공하는 멀티샘플링 및 하드웨어 가속 지원 수준에 따라 달라집니다. 이 중 하나에 대한 지원이 부족하면 드라이버는 품질과 속도를 맞바꾸는 소프트웨어 렌더러로 돌아갈 수 있습니다.
© 2025 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.