좌표계

좌표계는 QPainter 클래스에 의해 제어됩니다. QPaintDeviceQPaintEngine 클래스와 함께 QPainter 는 Qt의 페인팅 시스템인 Arthur의 기초를 형성합니다. QPainter 는 그리기 작업을 수행하는 데 사용되고, QPaintDeviceQPainter 를 사용하여 그릴 수 있는 2차원 공간의 추상화이며, QPaintEngine 는 페인터가 다양한 유형의 장치에 그림을 그리는 데 사용하는 인터페이스를 제공합니다.

QPaintDevice 클래스는 칠할 수 있는 객체의 기본 클래스입니다: 이 클래스의 그리기 기능은 QWidget, QImage, QPixmap, QPicture, QOpenGLPaintDevice 클래스에 의해 상속됩니다. 페인트 장치의 기본 좌표계는 왼쪽 상단 모서리에 원점이 있습니다. X 값은 오른쪽으로 증가하고 Y 값은 아래쪽으로 증가합니다. 기본 단위는 픽셀 기반 장치의 경우 1픽셀, 프린터의 경우 1포인트(1/72인치)입니다.

논리적 QPainter 좌표와 물리적 QPaintDevice 좌표의 매핑은 QPainter 의 변환 매트릭스, 뷰포트 및 "창"에서 처리합니다. 논리적 좌표계와 물리적 좌표계는 기본적으로 일치합니다. QPainter 은 좌표 변환(예: 회전 및 크기 조정)도 지원합니다.

렌더링

논리적 표현

그래픽 프리미티브의 크기(너비 및 높이)는 렌더링되는 펜의 너비를 무시하고 항상 수학적 모델과 일치합니다:

QRect(QPoint(1, 2), QPoint(7, 6))QLine(QPoint(2, 7), QPoint(6, 1))
QLine(2, 7, 6, 1)
QRect(QPoint(1, 2), QSize(6, 4))
QRect(1, 2, 6, 4)

앨리어스 페인팅

그리기 시 픽셀 렌더링은 QPainter::Antialiasing 렌더 힌트에 의해 제어됩니다.

RenderHint 열거형은 특정 엔진에서 존중할 수도 있고 그렇지 않을 수도 있는 QPainter 플래그를 지정하는 데 사용됩니다. QPainter::Antialiasing 값은 엔진이 가능하면 프리미티브의 가장자리를 안티앨리어싱(다른 색상 강도를 사용하여 가장자리를 부드럽게 처리하는 것)해야 함을 나타냅니다.

그러나 기본적으로 페인터는 에일리어싱되며 다른 규칙이 적용됩니다: 1픽셀 너비의 펜으로 렌더링할 때 픽셀은 수학적으로 정의된 점의 오른쪽과 아래에 렌더링됩니다. 예를 들어

QPainter painter(this);

painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);

painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

픽셀 수가 짝수인 펜으로 렌더링할 때는 픽셀이 수학적으로 정의된 점 주위에 대칭으로 렌더링되고, 픽셀 수가 홀수인 펜으로 렌더링할 때는 1픽셀의 경우처럼 여분의 픽셀이 수학적인 점의 오른쪽과 아래에 렌더링됩니다. 구체적인 예는 아래 QRectF 다이어그램을 참조하세요.

QRectF
논리적 표현1픽셀 너비의 펜
2픽셀 너비의 펜3픽셀 너비의 펜

역사적인 이유로 QRect::right() 및 QRect::bottom() 함수의 반환값이 직사각형의 실제 오른쪽 하단 모서리에서 벗어난다는 점에 유의하세요.

QRect right() 함수는 () + () - 1을 반환하고 () 함수는 () + () - 1을 반환합니다. 다이어그램의 오른쪽 하단 녹색 점은 이러한 함수의 반환 좌표를 나타냅니다. left width bottom top height

대신 QRectF 을 사용하는 것이 좋습니다: QRectF 클래스는 정확성을 위해 부동 소수점 좌표를 사용하여 평면에서 직사각형을 정의하며(QRect 은 정수 좌표 사용), QRectF::right() 및 QRectF::bottom() 함수는 실제 오른쪽 하단 모서리를 반환합니다.

또는 QRect 를 사용하여 x() + width() 및 y() + height()를 적용하여 오른쪽 하단 모서리를 찾고 right() 및 bottom() 함수는 피합니다.

앤티 앨리어싱 페인팅

QPainteranti-aliasing 렌더 힌트를 설정하면 픽셀이 수학적으로 정의된 점의 양쪽에서 대칭으로 렌더링됩니다:

QPainter painter(this);
painter.setRenderHint(
    QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);
painter.setRenderHint(
    QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

변환

기본적으로 QPainter 은 연결된 디바이스의 자체 좌표계에서 작동하지만 아핀 좌표 변환도 완벽하게 지원합니다.

QPainter::scale() 함수를 사용하여 좌표계의 크기를 지정된 오프셋만큼 조정할 수 있고, QPainter::rotate() 함수를 사용하여 시계 방향으로 회전할 수 있으며, QPainter::translate() 함수를 사용하여 변환(즉, 포인트에 지정된 오프셋을 더하는 것)할 수 있습니다.

QPainter::shear() 함수를 사용하여 원점을 중심으로 좌표계를 왜곡할 수도 있습니다. 모든 변환 작업은 QPainter::worldTransform() 함수를 사용하여 검색할 수 있는 QPainter 의 변환 행렬에서 작동합니다. 행렬은 평면의 한 점을 다른 점으로 변환합니다.

동일한 변환이 반복적으로 필요한 경우 QTransform 객체와 QPainter::worldTransform() 및 QPainter::setWorldTransform() 함수를 사용할 수도 있습니다. 내부 스택에 행렬을 저장하는 QPainter::save() 함수를 호출하여 언제든지 QPainter 의 변환 행렬을 저장할 수 있습니다. QPainter::restore () 함수는 이를 다시 불러옵니다.

변환 매트릭스가 자주 필요한 경우 중 하나는 다양한 페인트 장치에서 동일한 그리기 코드를 재사용할 때입니다. 변환 매트릭스가 없으면 결과는 페인트 장치의 해상도에 엄격하게 구속됩니다. 프린터는 인치당 600도트와 같이 해상도가 높은 반면, 스크린은 인치당 72~100도트인 경우가 많습니다.

아날로그 시계 예제
아날로그 시계 예시는 QPainter 의 변환 매트릭스를 사용하여 사용자 정의 위젯의 콘텐츠를 그리는 방법을 보여줍니다.

더 읽기 전에 이 예제를 컴파일하고 실행하는 것이 좋습니다. 특히 창 크기를 다양한 크기로 조정해 보세요.

void AnalogClock::paintEvent(QPaintEvent *)
{
    static const QPoint hourHand[4] = {
        QPoint(5, 14),
        QPoint(-5, 14),
        QPoint(-4, -71),
        QPoint(4, -71)
    };
    static const QPoint minuteHand[4] = {
        QPoint(4, 14),
        QPoint(-4, 14),
        QPoint(-3, -89),
        QPoint(3, -89)
    };

    static const QPoint secondsHand[4] = {
       QPoint(1, 14),
       QPoint(-1, 14),
       QPoint(-1, -89),
       QPoint(1, -89)
    };

    const QColor hourColor(palette().color(QPalette::Text));
    const QColor minuteColor(palette().color(QPalette::Text));
    const QColor secondsColor(palette().color(QPalette::Accent));

    int side = qMin(width(), height());

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width() / 2, height() / 2);
    painter.scale(side / 200.0, side / 200.0);

좌표계를 변환하여 점 (0, 0)이 위젯의 왼쪽 상단이 아닌 중앙에 위치하도록 합니다. 또한 시스템의 배율을 side / 200으로 조정합니다. 여기서 side 은 위젯의 너비 또는 높이 중 가장 짧은 값입니다. 기기가 정사각형이 아니더라도 시계가 정사각형이 되기를 원합니다.

이렇게 하면 원점(0, 0)이 중앙에 있는 200 x 200 정사각형 영역이 생겨서 그 위에 그릴 수 있습니다. 그리면 위젯에 들어갈 수 있는 가장 큰 정사각형으로 표시됩니다.

창-뷰포트 변환 섹션도 참조하세요.

    painter.save();
    painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    painter.drawConvexPolygon(hourHand, 4);
    painter.restore();

좌표계를 회전하고 QPainter::drawConvexPolygon()를 호출하여 시계의 시침을 그립니다. 회전 덕분에 시계 바늘이 올바른 방향으로 그려집니다.

다각형은 세 점 (7, 8), (-7, 8), (0, -40)에 해당하는 hourHand 정적 변수(함수 시작 부분에 정의됨)에 저장된 번갈아 나타나는 x, y 값의 배열로 지정됩니다.

코드 주위에 QPainter::save() 및 QPainter::restore()을 호출하면 뒤에 나오는 코드가 우리가 사용한 변환으로 인해 방해받지 않도록 보장합니다.

    painter.setBrush(minuteColor);

    painter.save();
    painter.rotate(6.0 * time.minute());
    painter.drawConvexPolygon(minuteHand, 4);
    painter.restore();

그런 다음 30도 간격으로 12개의 짧은 선으로 구성된 시계 화면의 시간 표시를 그립니다. 이 루프가 완료되면 페인터가 원래 상태로 한 바퀴 회전되었으므로 상태를 저장하고 복원할 필요가 없습니다.

    painter.save();
    painter.rotate(6.0 * time.second());
    painter.drawConvexPolygon(secondsHand, 4);
    painter.drawEllipse(-3, -3, 6, 6);
    painter.drawEllipse(-5, -68, 10, 10);
    painter.restore();

(7, 8), (-7, 8), (0, -70)의 세 점으로 정의되는 시계의 분침에 대해서도 동일한 작업을 수행합니다. 이 좌표는 분침보다 더 얇고 긴 시침을 지정합니다.

    for (int j = 0; j < 60; ++j) {
        painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }

마지막으로 6도 간격으로 60개의 짧은 선으로 구성된 시계 페이스의 분 마커를 그립니다. 시침 마커를 그리지 않기 위해 매 5분 마커는 건너뜁니다. 마지막에는 그다지 유용하지 않은 방식으로 페인터가 회전하지만, 이미 페인팅이 완료되었으므로 상관없습니다.

변환 매트릭스에 대한 자세한 내용은 QTransform 문서를 참조하세요.

창-뷰포트 변환

QPainter 로 그릴 때는 논리적 좌표를 사용하여 점을 지정한 다음 페인트 장치의 물리적 좌표로 변환합니다.

논리적 좌표를 물리적 좌표로 매핑하는 작업은 QPainter 의 월드 변환 worldTransform()( 변환 섹션에 설명됨)과 QPainterviewport() 및 window()에 의해 처리됩니다. 뷰포트는 임의의 직사각형을 지정하는 물리적 좌표를 나타냅니다. '창'은 동일한 직사각형을 논리적 좌표로 설명합니다. 기본적으로 논리적 좌표계와 물리적 좌표계는 일치하며 페인트 장치의 사각형과 동일합니다.

창-뷰포트 변환을 사용하면 논리적 좌표계를 원하는 대로 만들 수 있습니다. 이 메커니즘을 사용하여 그리기 코드를 페인트 장치와 독립적으로 만들 수도 있습니다. 예를 들어 QPainter::setWindow() 함수를 호출하여 중앙에 (0, 0)이 있는 (-50, -50)에서 (50, 50)까지 논리 좌표를 확장할 수 있습니다:

QPainter painter(this);
painter.setWindow(QRect(-50, -50, 100, 100));

이제 논리적 좌표(-50,-50)는 페인트 장치의 물리적 좌표(0, 0)에 해당합니다. 페인트 장치에 관계없이 페인팅 코드는 항상 지정된 논리 좌표에서 작동합니다.

"창" 또는 뷰포트 사각형을 설정하면 좌표의 선형 변환을 수행합니다. '창'의 각 모서리는 뷰포트의 해당 모서리에 매핑되며, 그 반대의 경우도 마찬가지입니다. 따라서 일반적으로 뷰포트와 '창'의 가로 세로 비율을 동일하게 유지하여 변형을 방지하는 것이 좋습니다:

int side = qMin(width(), height());
int x = (width() - side / 2);
int y = (height() - side / 2);

painter.setViewport(x, y, side, side);

논리적 좌표계를 정사각형으로 만들면 QPainter::setViewport() 함수를 사용하여 뷰포트도 정사각형으로 만들어야 합니다. 위의 예에서는 페인트 장치의 직사각형에 맞는 가장 큰 정사각형으로 만들었습니다. 창 또는 뷰포트를 설정할 때 페인트 장치의 크기를 고려하면 그리기 코드를 페인트 장치와 독립적으로 유지할 수 있습니다.

창-뷰포트 변환은 선형 변환일 뿐, 즉 클리핑을 수행하지 않는다는 점에 유의하세요. 즉, 현재 설정된 '창' 외부에 그리는 경우에도 동일한 선형 대수 접근 방식을 사용하여 뷰포트에 그림이 변환됩니다.

뷰포트, '창' 및 변환 매트릭스는 논리적 QPainter 좌표가 페인트 장치의 물리적 좌표에 매핑되는 방식을 결정합니다. 기본적으로 월드 변환 행렬은 동일성 행렬이고 '창' 및 뷰포트 설정은 페인트 장치의 설정, 즉 월드, '창' 및 장치 좌표계가 동일하지만 앞서 살펴본 것처럼 변환 연산과 창-뷰포트 변환을 사용하여 시스템을 조작할 수 있습니다. 위 그림은 그 과정을 설명합니다.

아날로그 시계도참조하세요 .

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