기본 드로잉 예제
기본 드로잉 예제는 QPainter 클래스를 사용하여 다양한 스타일로 기본 그래픽 프리미티브를 표시하는 방법을 보여줍니다.
QPainter 위젯 및 기타 페인트 장치에서 로우 레벨 페인팅을 수행합니다. 이 클래스는 단순한 선부터 파이와 코드와 같은 복잡한 도형까지 모든 것을 그릴 수 있습니다. 또한 정렬된 텍스트와 픽셀맵도 그릴 수 있습니다. 일반적으로 "자연스러운" 좌표계로 그리지만 뷰와 월드 변환도 수행할 수 있습니다.
이 예제에서는 현재 활성 도형을 표시하는 렌더링 영역을 제공하고 사용자가 QPainter 매개변수를 사용하여 렌더링된 도형과 그 모양을 조작할 수 있도록 합니다: 사용자는 활성 도형(Shape)을 변경하고 QPainter 의 펜(Pen Width, Pen Style, Pen Cap, Pen Join), 브러시(Brush Style) 및 렌더링 힌트(Antialiasing)를 수정할 수 있습니다. 또한 사용자는 도형을 회전(Transformations)할 수 있으며, 배후에서는 QPainter 의 좌표계 조작 기능을 사용하여 회전을 수행합니다.
기본 드로잉 예제는 두 개의 클래스로 구성됩니다:
RenderArea
는 현재 활성 도형의 여러 복사본을 렌더링하는 사용자 정의 위젯입니다.Window
는 여러 매개변수 위젯과 함께RenderArea
위젯을 표시하는 애플리케이션의 메인 창입니다.
먼저 Window
클래스를 살펴본 다음 RenderArea
클래스를 살펴보겠습니다.
창 클래스 정의
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() { 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의 펜은 QPen 객체이고, QPen 클래스는 화가가 도형의 선과 윤곽을 그리는 방법을 정의합니다. 펜에는 몇 가지 속성이 있습니다: 너비, 스타일, 캡 및 조인.
펜의 너비는 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)으로 설정하면 선이나 윤곽선을 그리지 않도록 페인터에 지시합니다. 펜 캡은 선의 끝점을 그리는 방법을 정의합니다. 그리고 펜 결합은 여러 개의 연결된 선이 그려질 때 두 선이 결합하는 방법을 정의합니다. 캡과 조인은 너비가 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
로 형변환해야 합니다. 주어진 역할에 대한 데이터가 없는 경우 이 함수는 QVariant::Invalid를 반환합니다.
결국 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
위젯을 업데이트합니다.
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 로 구성된 정지점을 사용하여 정의됩니다. 정지점 집합은 그라데이션 영역을 어떻게 채워야 하는지를 설명합니다. 그라디언트에는 임의의 수의 정지점이 있을 수 있습니다.
마지막으로 RenderArea::setBrush()
슬롯을 호출하여 RenderArea
위젯의 브러시를 QLinearGradient 객체로 업데이트합니다.
} 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
위젯을 업데이트합니다.
그렇지 않으면 지정된 스타일과 녹색으로 브러시를 만든 다음 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 으로 설정하고 앤티앨리어싱 속성을 false로 설정한 다음 위젯의 픽셀맵 변수에 이미지를 로드합니다. 마지막으로 위젯의 배경 역할을 설정하여 위젯의 palette 에서 배경을 렌더링하는 데 사용할 브러시를 정의합니다. QPalette::Base 은 일반적으로 흰색입니다.
RenderArea
는 위젯의 권장 크기를 유지하는 QWidget 의 sizeHint 속성을 상속합니다. 이 속성의 값이 잘못된 크기인 경우 권장되는 크기가 없습니다.
QWidget::sizeHint() 함수의 기본 구현은 위젯에 대한 레이아웃이 없는 경우 잘못된 크기를 반환하고, 그렇지 않으면 레이아웃의 기본 권장 크기를 반환합니다.
이 함수를 다시 구현하면 너비 400픽셀, 높이 200픽셀의 QSize 가 반환됩니다.
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(); }
공개 setShape()
, setPen()
및 setBrush()
슬롯은 RenderArea
위젯의 모양, 펜 또는 브러시를 수정할 때마다 호출됩니다. 슬롯 매개변수에 따라 모양, 펜 또는 브러시를 설정하고 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() 함수를 다시 구현합니다. 가장 먼저 할 일은 다양한 모양을 그리는 데 필요한 그래픽 객체를 만드는 것입니다.
4개의 QPoint벡터를 생성하고 이 벡터를 사용하여 Points, Polyline 및 Polygon 모양을 렌더링합니다. 그런 다음 평면에 직사각형을 정의하는 QRect 을 생성하여 Path 과 Pixmap 을 제외한 모든 도형의 경계 사각형으로 사용합니다.
또한 QPainterPath 을 생성합니다. QPainterPath 클래스는 페인팅 작업을 위한 컨테이너를 제공하여 그래픽 도형을 구성하고 재사용할 수 있도록 합니다. 페인터 경로는 직사각형, 타원, 선, 곡선 등 여러 그래픽 빌딩 블록으로 구성된 객체입니다. QPainterPath 클래스에 대한 자세한 내용은 페인터 경로 예시를 참조하세요. 이 예제에서는 하나의 직선과 베지어 곡선으로 구성된 페인터 경로를 만듭니다.
또한 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) { painter.save(); painter.translate(x, y);
마지막으로 RenderArea
도형의 여러 복사본을 렌더링합니다. 사본의 수는 RenderArea
위젯의 크기에 따라 달라지며, 두 개의 for
루프와 위젯 높이와 너비를 사용하여 위치를 계산합니다.
각 복사본에 대해 먼저 현재 페인터 상태를 저장합니다(상태를 스택에 푸시). 그런 다음 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 그리기 함수를 사용하여 렌더링합니다:
- QPainter::drawLine(),
- QPainter::drawPoints(),
- QPainter::drawPolyline(),
- QPainter::drawPolygon(),
- QPainter::drawRect(),
- QPainter::drawRoundedRect(),
- QPainter::drawEllipse(),
- QPainter::drawArc(),
- QPainter::drawChord(),
- QPainter::drawPie(),
- QPainter::drawPath(),
- QPainter::drawText() 또는
- QPainter::drawPixmap()
렌더링을 시작하기 전에 현재 페인터 상태를 저장했습니다(상태를 스택에 푸시). 그 이유는 좌표계의 동일한 지점을 기준으로 각 도형 사본의 위치를 계산하기 때문입니다. 좌표계를 변환할 때 변환 프로세스를 시작하기 전에 현재 페인터 상태를 저장하지 않으면 이 지점에 대한 지식을 잃게 됩니다.
painter.restore(); } } painter.setRenderHint(QPainter::Antialiasing, false); painter.setPen(palette().dark().color()); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); }
그런 다음 도형의 사본 렌더링이 끝나면 QPainter::restore() 함수를 사용하여 관련 좌표계와 함께 원래의 페인터 상태를 복원할 수 있습니다. 이렇게 하면 다음 도형 사본이 올바른 위치에 렌더링되도록 할 수 있습니다.
페인터 상태를 저장하는 대신 QPainter::translate() 함수를 사용하여 좌표계를 다시 변환할 수도 있습니다. 하지만 좌표계를 변환하는 것 외에도( Transformation 매개변수 옵션이 체크된 경우) 좌표계를 회전하고 배율을 조정하기 때문에 가장 쉬운 해결책은 현재 페인터 상태를 저장하는 것입니다.
© 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.