이 페이지에서

기본 드로잉 예제

'기본 그리기' 예제는 ` QPainter ` 클래스를 사용하여 다양한 스타일로 기본 그래픽 프리미티브를 표시하는 방법을 보여줍니다.

QPainter xml-ph-0000@deepl.internal 클래스는 위젯 및 기타 페인트 장치에 대해 저수준 페인팅 작업을 수행합니다. 이 클래스는 단순한 선부터 원형이나 현과 같은 복잡한 도형에 이르기까지 모든 것을 그릴 수 있습니다. 또한 정렬된 텍스트와 픽스맵도 그릴 수 있습니다. 일반적으로 "자연" 좌표계에서 그리지만, 뷰 변환 및 월드 변환도 수행할 수 있습니다.

도면을 수정할 수 있는 다양한 옵션이 있는 창

이 예제는 현재 활성화된 도형을 표시하는 렌더링 영역을 제공하며, 사용자가 ` QPainter ` 매개변수를 사용하여 렌더링된 도형과 그 모양을 조작할 수 있게 합니다. 사용자는 활성화된 도형을 변경할 수 있으며(`Shape`), ` QPainter`의 펜(`Pen Width`, ` Pen Style`, ` Pen Cap`, ` Pen Join`), 브러시(`Brush Style`) 및 렌더링 힌트(`Antialiasing`)를 수정할 수 있습니다. 또한 사용자는 도형을 회전시킬 수 있습니다(Transformations); 내부적으로는 QPainter 의 좌표계 조작 기능을 활용하여 회전을 수행합니다.

'Basic Drawing' 예제는 두 개의 클래스로 구성되어 있습니다:

  • RenderArea 는 현재 활성화된 도형의 복사본 여러 개를 렌더링하는 사용자 정의 위젯입니다.
  • Window 는 여러 매개변수 위젯 외에도 RenderArea 위젯을 표시하는 애플리케이션의 메인 창입니다.

먼저 Window 클래스를 살펴본 다음, RenderArea 클래스를 살펴보겠습니다.

Window 클래스 정의

Window 클래스는 QWidget 를 상속받으며, 여러 매개변수 위젯 외에도 RenderArea 위젯을 표시하는 애플리케이션의 메인 윈도우입니다.

class Window : public QWidget
{
    Q_OBJECT

public:
    Window();

private slots:
    void shapeChanged();
    void penChanged();
    void brushChanged();

private:
    RenderArea *renderArea;
    QLabel *shapeLabel;
    QLabel *penWidthLabel;
    QLabel *penStyleLabel;
    QLabel *penCapLabel;
    QLabel *penJoinLabel;
    QLabel *brushStyleLabel;
    QLabel *otherOptionsLabel;
    QComboBox *shapeComboBox;
    QSpinBox *penWidthSpinBox;
    QComboBox *penStyleComboBox;
    QComboBox *penCapComboBox;
    QComboBox *penJoinComboBox;
    QComboBox *brushStyleComboBox;
    QCheckBox *antialiasingCheckBox;
    QCheckBox *transformationsCheckBox;
};

다양한 위젯과, ` RenderArea ` 위젯을 업데이트하는 세 개의 비공개 슬롯을 선언합니다. ` shapeChanged() ` 슬롯은 사용자가 현재 활성화된 도형을 변경할 때 ` RenderArea ` 위젯을 업데이트합니다. ` QPainter`의 펜 매개변수 중 하나가 변경되면 ` penChanged() ` 슬롯을 호출합니다. 또한 ` brushChanged() ` 슬롯은 사용자가 페인터의 브러시 스타일을 변경할 때 ` RenderArea ` 위젯을 업데이트합니다.

Window 클래스 구현

생성자에서는 메인 애플리케이션 창에 표시되는 다양한 위젯을 생성하고 초기화합니다.

Window::Window()
{
    renderArea = new RenderArea;

    shapeComboBox = new QComboBox;
    shapeComboBox->addItem(tr("Polygon"), RenderArea::Polygon);
    shapeComboBox->addItem(tr("Rectangle"), RenderArea::Rect);
    shapeComboBox->addItem(tr("Rounded Rectangle"), RenderArea::RoundedRect);
    shapeComboBox->addItem(tr("Ellipse"), RenderArea::Ellipse);
    shapeComboBox->addItem(tr("Pie"), RenderArea::Pie);
    shapeComboBox->addItem(tr("Chord"), RenderArea::Chord);
    shapeComboBox->addItem(tr("Path"), RenderArea::Path);
    shapeComboBox->addItem(tr("Line"), RenderArea::Line);
    shapeComboBox->addItem(tr("Polyline"), RenderArea::Polyline);
    shapeComboBox->addItem(tr("Arc"), RenderArea::Arc);
    shapeComboBox->addItem(tr("Points"), RenderArea::Points);
    shapeComboBox->addItem(tr("Text"), RenderArea::Text);
    shapeComboBox->addItem(tr("Pixmap"), RenderArea::Pixmap);

    shapeLabel = new QLabel(tr("&Shape:"));
    shapeLabel->setBuddy(shapeComboBox);

먼저 현재 활성화된 도형을 렌더링할 RenderArea 위젯을 생성합니다. 그런 다음 Shape 콤보박스를 생성하고, 관련 항목(즉, QPainter 가 그릴 수 있는 다양한 도형)을 추가합니다.

    penWidthSpinBox = new QSpinBox;
    penWidthSpinBox->setRange(0, 20);
    penWidthSpinBox->setSpecialValueText(tr("0 (cosmetic pen)"));

    penWidthLabel = new QLabel(tr("Pen &Width:"));
    penWidthLabel->setBuddy(penWidthSpinBox);

QPainter's pen은 QPen 객체입니다. QPen 클래스는 페인터가 선과 도형의 윤곽선을 어떻게 그려야 하는지를 정의합니다. 펜에는 Width, style, cap, join 등 여러 속성이 있습니다.

펜의 너비는 0 이상이 될 수 있지만, 가장 일반적인 너비는 0입니다. 이는 0 픽셀을 의미하는 것이 아니라, 수학적으로 정확하지는 않을지라도 도형이 가능한 한 매끄럽게 그려진다는 것을 의미합니다.

Pen Width 매개변수를 위해 QSpinBox 객체를 생성합니다.

    penStyleComboBox = new QComboBox;
    penStyleComboBox->addItem(tr("Solid"), static_cast<int>(Qt::SolidLine));
    penStyleComboBox->addItem(tr("Dash"), static_cast<int>(Qt::DashLine));
    penStyleComboBox->addItem(tr("Dot"), static_cast<int>(Qt::DotLine));
    penStyleComboBox->addItem(tr("Dash Dot"), static_cast<int>(Qt::DashDotLine));
    penStyleComboBox->addItem(tr("Dash Dot Dot"), static_cast<int>(Qt::DashDotDotLine));
    penStyleComboBox->addItem(tr("None"), static_cast<int>(Qt::NoPen));

    penStyleLabel = new QLabel(tr("&Pen Style:"));
    penStyleLabel->setBuddy(penStyleComboBox);

    penCapComboBox = new QComboBox;
    penCapComboBox->addItem(tr("Flat"), Qt::FlatCap);
    penCapComboBox->addItem(tr("Square"), Qt::SquareCap);
    penCapComboBox->addItem(tr("Round"), Qt::RoundCap);

    penCapLabel = new QLabel(tr("Pen &Cap:"));
    penCapLabel->setBuddy(penCapComboBox);

    penJoinComboBox = new QComboBox;
    penJoinComboBox->addItem(tr("Miter"), Qt::MiterJoin);
    penJoinComboBox->addItem(tr("Bevel"), Qt::BevelJoin);
    penJoinComboBox->addItem(tr("Round"), Qt::RoundJoin);

    penJoinLabel = new QLabel(tr("Pen &Join:"));
    penJoinLabel->setBuddy(penJoinComboBox);

펜 스타일은 선의 유형을 정의합니다. 기본 스타일은 실선(Qt::SolidLine)입니다. 스타일을 없음(Qt::NoPen)으로 설정하면 페인터가 선이나 윤곽선을 그리지 않도록 지시합니다. 펜 끝(cap)은 선의 끝점이 어떻게 그려지는지를 정의합니다. 그리고 펜 연결(join)은 여러 개의 연결된 선이 그려질 때 두 선이 어떻게 연결되는지를 정의합니다. cap과 join은 너비가 1픽셀 이상인 선에만 적용됩니다.

우리는 Pen Style, Pen Cap 및 Pen Join 매개변수 각각에 대해 QComboBox객체를 생성하고, 관련 항목(즉, 각각 Qt::PenStyle, Qt::PenCapStyle 및 Qt::PenJoinStyle 열거형의 값)을 추가합니다.

    brushStyleComboBox = new QComboBox;
    brushStyleComboBox->addItem(tr("Linear Gradient"),
            static_cast<int>(Qt::LinearGradientPattern));
    brushStyleComboBox->addItem(tr("Radial Gradient"),
            static_cast<int>(Qt::RadialGradientPattern));
    brushStyleComboBox->addItem(tr("Conical Gradient"),
            static_cast<int>(Qt::ConicalGradientPattern));
    brushStyleComboBox->addItem(tr("Texture"), static_cast<int>(Qt::TexturePattern));
    brushStyleComboBox->addItem(tr("Solid"), static_cast<int>(Qt::SolidPattern));
    brushStyleComboBox->addItem(tr("Horizontal"), static_cast<int>(Qt::HorPattern));
    brushStyleComboBox->addItem(tr("Vertical"), static_cast<int>(Qt::VerPattern));
    brushStyleComboBox->addItem(tr("Cross"), static_cast<int>(Qt::CrossPattern));
    brushStyleComboBox->addItem(tr("Backward Diagonal"), static_cast<int>(Qt::BDiagPattern));
    brushStyleComboBox->addItem(tr("Forward Diagonal"), static_cast<int>(Qt::FDiagPattern));
    brushStyleComboBox->addItem(tr("Diagonal Cross"), static_cast<int>(Qt::DiagCrossPattern));
    brushStyleComboBox->addItem(tr("Dense 1"), static_cast<int>(Qt::Dense1Pattern));
    brushStyleComboBox->addItem(tr("Dense 2"), static_cast<int>(Qt::Dense2Pattern));
    brushStyleComboBox->addItem(tr("Dense 3"), static_cast<int>(Qt::Dense3Pattern));
    brushStyleComboBox->addItem(tr("Dense 4"), static_cast<int>(Qt::Dense4Pattern));
    brushStyleComboBox->addItem(tr("Dense 5"), static_cast<int>(Qt::Dense5Pattern));
    brushStyleComboBox->addItem(tr("Dense 6"), static_cast<int>(Qt::Dense6Pattern));
    brushStyleComboBox->addItem(tr("Dense 7"), static_cast<int>(Qt::Dense7Pattern));
    brushStyleComboBox->addItem(tr("None"), static_cast<int>(Qt::NoBrush));

    brushStyleLabel = new QLabel(tr("&Brush:"));
    brushStyleLabel->setBuddy(brushStyleComboBox);

QBrush 클래스는 QPainter 에 의해 그려지는 도형의 채우기 패턴을 정의합니다. 기본 브러시 스타일은 Qt::NoBrush 입니다. 이 스타일은 페인터에게 도형을 채우지 말라고 지시합니다. 채우기의 표준 스타일은 Qt::SolidPattern 입니다.

Brush Style 매개변수에 대한 QComboBox 를 생성하고, 관련 항목(즉, Qt::BrushStyle 열거형의 값들)을 추가합니다.

    otherOptionsLabel = new QLabel(tr("Options:"));
    antialiasingCheckBox = new QCheckBox(tr("&Antialiasing"));

앤티앨리어싱은 픽셀을 “부드럽게” 처리하여 더 균일하고 거친 부분이 적은 선을 만드는 기능이며, QPainter 의 렌더링 힌트를 사용하여 적용할 수 있습니다. QPainter::RenderHints 는 QPainter 에 플래그를 지정하는 데 사용되며, 이는 특정 엔진에 따라 적용될 수도 있고 그렇지 않을 수도 있습니다.

우리는 단순히 Antialiasing 옵션을 위한 QCheckBox 를 생성하기만 하면 됩니다.

    transformationsCheckBox = new QCheckBox(tr("&Transformations"));

Transformations 옵션은 렌더링된 도형이 3차원 공간에서 회전된 것처럼 보이게 하는 좌표계 조작을 의미합니다.

QPainter::translate(), QPainter::rotate() 및 QPainter::scale() 함수를 사용하여 메인 애플리케이션 창에서 간단한 QCheckBox 로 표시되는 이 기능을 구현합니다.

    connect(shapeComboBox, &QComboBox::activated,
            this, &Window::shapeChanged);
    connect(penWidthSpinBox, &QSpinBox::valueChanged,
            this, &Window::penChanged);
    connect(penStyleComboBox, &QComboBox::activated,
            this, &Window::penChanged);
    connect(penCapComboBox, &QComboBox::activated,
            this, &Window::penChanged);
    connect(penJoinComboBox, &QComboBox::activated,
            this, &Window::penChanged);
    connect(brushStyleComboBox, &QComboBox::activated,
            this, &Window::brushChanged);
    connect(antialiasingCheckBox, &QAbstractButton::toggled,
            renderArea, &RenderArea::setAntialiased);
    connect(transformationsCheckBox, &QAbstractButton::toggled,
            renderArea, &RenderArea::setTransformed);

그런 다음 정적 함수 ` QObject::connect()`를 사용하여 매개변수 위젯을 해당 슬롯에 연결함으로써, 사용자가 도형이나 다른 매개변수를 변경할 때마다 ` RenderArea ` 위젯이 업데이트되도록 합니다.

    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->setColumnStretch(0, 1);
    mainLayout->setColumnStretch(3, 1);
    mainLayout->addWidget(renderArea, 0, 0, 1, 4);
    mainLayout->addWidget(shapeLabel, 2, 0, Qt::AlignRight);
    mainLayout->addWidget(shapeComboBox, 2, 1);
    mainLayout->addWidget(penWidthLabel, 3, 0, Qt::AlignRight);
    mainLayout->addWidget(penWidthSpinBox, 3, 1);
    mainLayout->addWidget(penStyleLabel, 4, 0, Qt::AlignRight);
    mainLayout->addWidget(penStyleComboBox, 4, 1);
    mainLayout->addWidget(penCapLabel, 3, 2, Qt::AlignRight);
    mainLayout->addWidget(penCapComboBox, 3, 3);
    mainLayout->addWidget(penJoinLabel, 2, 2, Qt::AlignRight);
    mainLayout->addWidget(penJoinComboBox, 2, 3);
    mainLayout->addWidget(brushStyleLabel, 4, 2, Qt::AlignRight);
    mainLayout->addWidget(brushStyleComboBox, 4, 3);
    mainLayout->addWidget(otherOptionsLabel, 5, 0, Qt::AlignRight);
    mainLayout->addWidget(antialiasingCheckBox, 5, 1, 1, 1, Qt::AlignRight);
    mainLayout->addWidget(transformationsCheckBox, 5, 2, 1, 2, Qt::AlignRight);
    setLayout(mainLayout);

    shapeChanged();
    penChanged();
    brushChanged();
    antialiasingCheckBox->setChecked(true);

    setWindowTitle(tr("Basic Drawing"));
}

마지막으로, 다양한 위젯을 레이아웃에 추가하고, ` shapeChanged()`, ` penChanged()`, ` brushChanged() ` 슬롯을 호출하여 애플리케이션을 초기화합니다. 또한 앤티앨리어싱을 활성화합니다.

void Window::shapeChanged()
{
    RenderArea::Shape shape = RenderArea::Shape(shapeComboBox->itemData(
            shapeComboBox->currentIndex(), IdRole).toInt());
    renderArea->setShape(shape);
}

shapeChanged() 슬롯은 사용자가 현재 활성화된 도형을 변경할 때마다 호출됩니다.

먼저 QComboBox::itemData() 함수를 사용하여 사용자가 선택한 도형을 가져옵니다. 이 함수는 콤보박스의 지정된 인덱스에 있는 지정된 역할에 대한 데이터를 반환합니다. QComboBox::currentIndex()를 사용하여 도형의 인덱스를 가져오며, 역할은 Qt::ItemDataRole 열거형으로 정의됩니다. IdRole 는 Qt::UserRole 의 별칭입니다.

Qt::UserRole 은 애플리케이션별 용도로 사용할 수 있는 첫 번째 역할일 뿐이라는 점에 유의하십시오. 동일한 인덱스에 서로 다른 데이터를 저장해야 하는 경우, Qt::UserRole 의 값을 간단히 증가시켜 다른 역할을 사용할 수 있습니다. 예를 들어, 'Qt::UserRole + 1' 및 'Qt::UserRole + 2'와 같이 사용할 수 있습니다. 그러나 각 역할에 고유한 이름을 부여하는 것이 좋은 프로그래밍 관행입니다. 예를 들어, 'myFirstRole = Qt::UserRole + 1' 및 'mySecondRole = Qt::UserRole + 2'와 같이 설정할 수 있습니다. 이 특정 예제에서는 단 하나의 역할만 필요하지만, window.cpp 파일의 맨 앞에 다음 코드 줄을 추가합니다.

const int IdRole = Qt::UserRole;

QComboBox::itemData() 함수는 데이터를 QVariant 형식으로 반환하므로, 데이터를 RenderArea::Shape 형식으로 형변환해야 합니다. 지정된 역할에 대한 데이터가 없는 경우, 함수는 QMetaType::UnknownType 를 반환합니다.

마지막으로 RenderArea::setShape() 슬롯을 호출하여 RenderArea 위젯을 업데이트합니다.

void Window::penChanged()
{
    int width = penWidthSpinBox->value();
    Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(
            penStyleComboBox->currentIndex(), IdRole).toInt());
    Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(
            penCapComboBox->currentIndex(), IdRole).toInt());
    Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(
            penJoinComboBox->currentIndex(), IdRole).toInt());

    renderArea->setPen(QPen(Qt::blue, width, style, cap, join));
}

사용자가 펜 매개변수 중 하나를 변경할 때마다 penChanged() 슬롯을 호출합니다. 다시 한 번 QComboBox::itemData() 함수를 사용하여 매개변수를 가져온 다음, RenderArea::setPen() 슬롯을 호출하여 RenderArea 위젯을 업데이트합니다.

void Window::brushChanged()
{
    Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox->itemData(

사용자가 브러시 매개변수를 변경할 때마다 brushChanged() 슬롯이 호출되며, 이 매개변수는 앞서와 마찬가지로 QComboBox::itemData() 함수를 사용하여 가져옵니다.

    if (style == Qt::LinearGradientPattern) {
        QLinearGradient linearGradient(0, 0, 100, 100);
        linearGradient.setColorAt(0.0, Qt::white);
        linearGradient.setColorAt(0.2, Qt::green);
        linearGradient.setColorAt(1.0, Qt::black);
        renderArea->setBrush(linearGradient);

브러시 매개변수가 그라데이션 채우기인 경우, 특별한 조치가 필요합니다.

QGradient 클래스는 QBrush 와 함께 사용되어 그라데이션 채우기를 지정합니다. Qt는 현재 선형, 방사형, 원추형의 세 가지 유형의 그라데이션 채우기를 지원합니다. 이들 각각은 QGradient 의 하위 클래스인 QLinearGradient, QRadialGradient 및 QConicalGradient 로 표현됩니다.

따라서 브러시 스타일이 ` Qt::LinearGradientPattern`인 경우, 먼저 생성자에 인수로 전달된 좌표 사이의 보간 영역을 갖는 ` QLinearGradient ` 객체를 생성합니다. 위치는 논리 좌표를 사용하여 지정됩니다. 그런 다음 ` QGradient::setColorAt()` 함수를 사용하여 그라디언트의 색상을 설정합니다. 색상은 위치(0과 1 사이)와 QColor 으로 구성된 정지점(stop points)을 사용하여 정의됩니다. 이 정지점 집합은 그라데이션 영역이 어떻게 채워져야 하는지를 설명합니다. 그라데이션은 임의의 개수의 정지점을 가질 수 있습니다.

마지막으로 RenderArea::setBrush() 슬롯을 호출하여 QLinearGradient 객체를 사용하여 RenderArea 위젯의 브러시를 업데이트합니다.

    } else if (style == Qt::RadialGradientPattern) {
        QRadialGradient radialGradient(50, 50, 50, 70, 70);
        radialGradient.setColorAt(0.0, Qt::white);
        radialGradient.setColorAt(0.2, Qt::green);
        radialGradient.setColorAt(1.0, Qt::black);
        renderArea->setBrush(radialGradient);
    } else if (style == Qt::ConicalGradientPattern) {
        QConicalGradient conicalGradient(50, 50, 150);
        conicalGradient.setColorAt(0.0, Qt::white);
        conicalGradient.setColorAt(0.2, Qt::green);
        conicalGradient.setColorAt(1.0, Qt::black);
        renderArea->setBrush(conicalGradient);

QLinearGradient 에 사용된 것과 유사한 작업 패턴이 Qt::RadialGradientPattern 와 Qt::ConicalGradientPattern 의 경우에도 사용됩니다.

유일한 차이점은 생성자에 전달되는 인자입니다. QRadialGradient 생성자의 경우 첫 번째 인자는 중심이고, 두 번째 인자는 방사형 그라데이션의 반지름입니다. 세 번째 인자는 선택 사항이지만, 원 내부의 그라데이션 초점 위치를 정의하는 데 사용할 수 있습니다(기본 초점 위치는 원의 중심입니다). QConicalGradient 생성자의 경우, 첫 번째 인수는 원뿔의 중심을 지정하고, 두 번째 인수는 보간법의 시작 각도를 지정합니다.

    } else if (style == Qt::TexturePattern) {
        renderArea->setBrush(QBrush(QPixmap(":/images/brick.png")));

브러시 스타일이 ` Qt::TexturePattern `인 경우, ` QPixmap`을 기반으로 ` QBrush `을 생성합니다. 그런 다음 ` RenderArea::setBrush() ` 슬롯을 호출하여 새로 생성된 브러시로 ` RenderArea ` 위젯을 업데이트합니다.

    } else {
        renderArea->setBrush(QBrush(Qt::green, style));
    }
}

그렇지 않은 경우, 주어진 스타일과 녹색을 가진 브러시를 생성한 다음, RenderArea::setBrush() 슬롯을 호출하여 RenderArea 위젯을 새로 생성된 브러시로 업데이트합니다.

RenderArea 클래스 정의

RenderArea 클래스는 QWidget 을 상속받으며, QPainter 을 사용하여 현재 활성화된 도형의 여러 복사본을 렌더링합니다.

class RenderArea : public QWidget
{
    Q_OBJECT

public:
    enum Shape { Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse, Arc,
                 Chord, Pie, Path, Text, Pixmap };

    explicit RenderArea(QWidget *parent = nullptr);

    QSize minimumSizeHint() const override;
    QSize sizeHint() const override;

public slots:
    void setShape(Shape shape);
    void setPen(const QPen &pen);
    void setBrush(const QBrush &brush);
    void setAntialiased(bool antialiased);
    void setTransformed(bool transformed);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    Shape shape;
    QPen pen;
    QBrush brush;
    bool antialiased;
    bool transformed;
    QPixmap pixmap;
};

먼저, 위젯에서 렌더링할 수 있는 다양한 도형(즉, ` QPainter`에서 렌더링할 수 있는 도형)을 담을 ` Shape ` 공용 열거형을 정의합니다. 그런 다음 생성자와 ` QWidget`의 공용 함수 중 두 가지인 ` minimumSizeHint()` 및 ` sizeHint()`를 재구현합니다.

또한 지정된 매개변수에 따라 현재 활성화된 도형을 그릴 수 있도록 QWidget::paintEvent() 함수도 재구현합니다.

여러 비공개 슬롯을 선언합니다. setShape() 슬롯은 RenderArea 의 모양을 변경하고, setPen() 및 setBrush() 슬롯은 위젯의 펜과 브러시를 수정하며, setAntialiased() 및 setTransformed() 슬롯은 위젯의 각 속성을 수정합니다.

RenderArea 클래스 구현

생성자에서 위젯의 변수 몇 가지를 초기화합니다.

RenderArea::RenderArea(QWidget *parent)
    : QWidget(parent)
{
    shape = Polygon;
    antialiased = false;
    transformed = false;
    pixmap.load(":/images/qt-logo.png");

    setBackgroundRole(QPalette::Base);
    setAutoFillBackground(true);
}

위젯의 모양을 ` Polygon`로 설정하고, `antialiased` 속성을 `false`로 설정하며, 위젯의 `pixmap` 변수에 이미지를 로드합니다. 마지막으로 위젯의 배경 역할을 설정하고, 배경을 렌더링하는 데 사용될 위젯의 ` palette `에서 브러시를 정의합니다. ` QPalette::Base `는 일반적으로 흰색입니다.

QSize RenderArea::sizeHint() const
{
    return QSize(400, 200);
}

RenderArea 는 위젯에 권장되는 크기를 저장하는 QWidget 의 sizeHint 속성을 상속받습니다. 이 속성의 값이 유효하지 않은 크기인 경우, 권장 크기는 지정되지 않습니다.

QWidget::sizeHint() 함수의 기본 구현은 위젯에 레이아웃이 없는 경우 유효하지 않은 크기를 반환하고, 그렇지 않은 경우에는 레이아웃의 선호 크기를 반환합니다.

이 함수를 재구현한 결과, 너비 400픽셀, 높이 200픽셀인 ` QSize `를 반환합니다.

QSize RenderArea::minimumSizeHint() const
{
    return QSize(100, 100);
}

RenderArea 또한 QWidget 의 minimumSizeHint 속성을 상속받아 위젯에 권장되는 최소 크기를 저장합니다. 이 속성의 값이 유효하지 않은 크기인 경우에도 권장 크기는 없습니다.

QWidget::minimumSizeHint()의 기본 구현은 위젯에 대한 레이아웃이 없는 경우 유효하지 않은 크기를 반환하고, 그렇지 않은 경우에는 레이아웃의 최소 크기를 반환합니다.

이 함수를 재구현한 결과, 너비 100픽셀, 높이 100픽셀인 QSize 객체를 반환합니다.

void RenderArea::setShape(Shape shape)
{
    this->shape = shape;
    update();
}

void RenderArea::setPen(const QPen &pen)
{
    this->pen = pen;
    update();
}

void RenderArea::setBrush(const QBrush &brush)
{
    this->brush = brush;
    update();
}

RenderArea 위젯의 모양, 펜 또는 브러시를 수정하고자 할 때마다 public setShape(), setPen() 및 setBrush() 슬롯이 호출됩니다. 슬롯 매개변수에 따라 모양, 펜 또는 브러시를 설정하고, QWidget::update()를 호출하여 RenderArea 위젯에 변경 사항이 반영되도록 합니다.

QWidget::update() 슬롯은 즉시 다시 그리기를 유발하지 않으며, 대신 Qt가 메인 이벤트 루프로 돌아왔을 때 처리될 페인트 이벤트를 예약합니다.

void RenderArea::setAntialiased(bool antialiased)
{
    this->antialiased = antialiased;
    update();
}

void RenderArea::setTransformed(bool transformed)
{
    this->transformed = transformed;
    update();
}

setAntialiased() 와 setTransformed() 슬롯을 사용하여 슬롯 매개변수에 따라 속성의 상태를 변경하고, QWidget::update() 슬롯을 호출하여 RenderArea 위젯에 변경 사항이 반영되도록 합니다.

void RenderArea::paintEvent(QPaintEvent * /* event */)
{
    static const QPoint points[4] = {
        QPoint(10, 80),
        QPoint(20, 10),
        QPoint(80, 30),
        QPoint(90, 70)
    };

    QRect rect(10, 20, 80, 60);

    QPainterPath path;
    path.moveTo(20, 80);
    path.lineTo(20, 30);
    path.cubicTo(80, 0, 50, 50, 80, 80);

    int startAngle = 20 * 16;
    int arcLength = 120 * 16;

그런 다음 QWidget::paintEvent() 함수를 다시 구현합니다. 가장 먼저, 다양한 도형을 그리는 데 필요한 그래픽 객체들을 생성합니다.

QPoint객체 4개로 구성된 벡터를 생성합니다. 이 벡터를 사용하여 Points, Polyline 및 Polygon 도형을 렌더링합니다. 그런 다음 QRect 객체를 생성하여 평면 상의 직사각형을 정의하고, 이를 Path 및 Pixmap 을 제외한 모든 도형의 경계 사각형으로 사용합니다.

또한 ` QPainterPath`도 생성합니다. ` QPainterPath ` 클래스는 그리기 작업을 위한 컨테이너를 제공하여, 그래픽 도형을 구성하고 재사용할 수 있게 해줍니다. 페인터 경로(painter path)는 사각형, 타원, 선, 곡선과 같은 여러 그래픽 구성 요소로 이루어진 객체입니다. 페인터 경로( QPainterPath ) 클래스에 대한 자세한 내용은 ‘페인터 경로(Painter Paths )’ 예제를 참조하십시오. 이 예제에서는 하나의 직선과 베지어 곡선으로 구성된 페인터 경로를 생성합니다.

또한 Arc, Chord 및 Pie 도형을 그릴 때 사용할 시작 각도와 호 길이를 정의합니다.

    QPainter painter(this);
    painter.setPen(pen);
    painter.setBrush(brush);
    if (antialiased)
        painter.setRenderHint(QPainter::Antialiasing, true);

RenderArea 위젯을 위한 QPainter 을 생성하고, RenderArea 의 펜과 브러시에 맞춰 페인터의 펜과 브러시를 설정합니다. Antialiasing 매개변수 옵션이 선택된 경우, 페인터의 렌더링 힌트도 설정합니다. QPainter::Antialiasing 는 엔진이 가능한 경우 프리미티브의 가장자리에 앤티앨리어싱을 적용해야 함을 나타냅니다.

    for (int x = 0; x < width(); x += 100) {
        for (int y = 0; y < height(); y += 100) {
            QPainterStateGuard guard(&painter);
            painter.translate(x, y);

마지막으로, RenderArea 의 도형을 여러 개 복사하여 렌더링합니다. 복사본의 수는 RenderArea 위젯의 크기에 따라 달라지며, 두 개의 for 루프와 위젯의 높이 및 너비를 사용하여 각 복사본의 위치를 계산합니다.

각 복사본에 대해 먼저 ` QPainterStateGuard`을 인스턴스화하여 현재 페인터 상태를 저장합니다. 그런 다음 ` QPainter::translate()` 함수를 사용하여 좌표계를 ` for ` 루프의 변수들로 결정된 위치로 변환합니다. 이 좌표계 변환을 생략하면 도형의 모든 복사본이 ` RenderArea ` 위젯의 왼쪽 상단 모서리에 서로 겹쳐서 렌더링됩니다.

            if (transformed) {
                painter.translate(50, 50);
                painter.rotate(60.0);
                painter.scale(0.6, 0.9);
                painter.translate(-50, -50);
            }

Transformations 매개변수 옵션이 선택된 경우, QPainter::rotate() 함수를 사용하여 좌표계를 시계 방향으로 60도 회전하고 QPainter::scale() 함수를 사용하여 크기를 축소한 후, 좌표계를 추가로 평행 이동시킵니다. 마지막으로 좌표계를 회전 및 크기 조정하기 전의 위치로 다시 평행 이동시킵니다.

이제 도형을 렌더링하면 마치 3차원 공간에서 회전된 것처럼 보입니다.

            switch (shape) {
            case Line:
                painter.drawLine(rect.bottomLeft(), rect.topRight());
                break;
            case Points:
                painter.drawPoints(points, 4);
                break;
            case Polyline:
                painter.drawPolyline(points, 4);
                break;
            case Polygon:
                painter.drawPolygon(points, 4);
                break;
            case Rect:
                painter.drawRect(rect);
                break;
            case RoundedRect:
                painter.drawRoundedRect(rect, 25, 25, Qt::RelativeSize);
                break;
            case Ellipse:
                painter.drawEllipse(rect);
                break;
            case Arc:
                painter.drawArc(rect, startAngle, arcLength);
                break;
            case Chord:
                painter.drawChord(rect, startAngle, arcLength);
                break;
            case Pie:
                painter.drawPie(rect, startAngle, arcLength);
                break;
            case Path:
                painter.drawPath(path);
                break;
            case Text:
                painter.drawText(rect,
                                 Qt::AlignCenter,
                                 tr("Qt by\nThe Qt Company"));
                break;
            case Pixmap:
                painter.drawPixmap(10, 10, pixmap);
            }

다음으로, ` RenderArea`의 도형을 식별하고, 관련 ` QPainter ` 드로잉 함수를 사용하여 렌더링합니다:

렌더링을 시작하기 전에, 현재 페인터 상태를 저장했습니다(상태를 스택에 밀어 넣음). 이렇게 하는 이유는 각 도형 복사본의 위치를 좌표계의 동일한 점을 기준으로 계산하기 때문입니다. 좌표계를 변환할 때, 변환 과정을 시작하기 전에 현재 페인터 상태를 저장하지 않으면 이 점에 대한 정보를 잃게 됩니다.

        }
    }

    painter.setRenderHint(QPainter::Antialiasing, false);
    painter.setPen(palette().dark().color());
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(QRect(0, 0, width() - 1, height() - 1));
}

그런 다음, 도형의 복사본 렌더링이 완료되면 ` QPainterStateGuard`가 ` QPainter::restore()` 함수를 호출하여 원래의 페인터 상태를 복원합니다. 이러한 방식으로 다음 도형 복사본이 올바른 위치에 렌더링되도록 보장합니다.

페인터 상태를 저장하는 대신 QPainter::translate()을 사용하여 좌표계를 원래대로 되돌릴 수도 있습니다. 하지만 ( Transformation 매개변수 옵션이 선택된 경우) 좌표계를 변환하는 것 외에도 회전과 크기 조정까지 수행하기 때문에, 가장 쉬운 해결책은 현재 페인터 상태를 저장하는 것입니다.

예제 프로젝트 @ code.qt.io

© 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.