아날로그 시계
아날로그 시계 예시는 사용자 정의 위젯의 콘텐츠를 그리는 방법을 보여줍니다.
아날로그 시계 예제 스크린샷
이 예제는 QPainter 의 변형 및 크기 조정 기능을 사용하여 사용자 정의 위젯을 더 쉽게 그리는 방법도 보여줍니다.
AnalogClock 클래스 정의
AnalogClock
클래스는 매초마다 자동으로 업데이트되는 시침, 분침, 초침이 있는 시계 위젯을 제공합니다. QWidget 클래스를 서브클래싱하고 표준 paintEvent() 함수를 재구현하여 시계 화면을 그립니다:
class AnalogClock : public QWidget { Q_OBJECT public: AnalogClock(QWidget *parent = nullptr); protected: void paintEvent(QPaintEvent *event) override; };
AnalogClock 클래스 구현
위젯이 구성되면 현재 시간을 추적하기 위해 1초 타이머를 설정하고 표준 update() 슬롯에 연결하여 타이머가 timeout() 신호를 보내면 시계 화면이 업데이트되도록 합니다. 마지막으로 위젯의 크기를 조정하여 적당한 크기로 표시되도록 합니다.
AnalogClock::AnalogClock(QWidget *parent) : QWidget(parent) { QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update)); timer->start(1000); setWindowTitle(tr("Analog Clock")); resize(200, 200); }
paintEvent()
함수는 위젯의 콘텐츠를 업데이트해야 할 때마다 호출됩니다. 이는 위젯이 처음 표시될 때와 위젯이 가려진 후 노출될 때 발생하지만 위젯의 update() 슬롯이 호출될 때에도 실행됩니다. 타이머의 timeout() 신호를 이 슬롯에 연결했으므로 적어도 초당 한 번 호출됩니다.
페인터를 설정하고 시계를 그리기 전에 먼저 시침, 분침, 초침에 사용할 QPoint목록 3개와 QColor목록 3개를 정의합니다. palette () 함수를 사용하여 밝은 모드와 어두운 모드 모두에서 창의 나머지 부분에 맞는 적절한 색상을 얻습니다. 시침과 분침은 전경색으로, 초침은 강조색으로 그려집니다.
또한 위젯의 가장 짧은 면의 길이를 결정하여 위젯 안에 시계 화면을 맞출 수 있도록 합니다. 그리기를 시작하기 전에 현재 시간을 확인하는 것도 유용합니다.
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. 페인터를 사용하여 QPaintDevice 에 그릴 수 있지만 일반적으로 위젯과 함께 사용되므로 위젯 인스턴스를 페인터의 생성자에게 전달합니다.
QPainter::Antialiasing 으로 QPainter::setRenderHint()를 호출하여 앤티앨리어싱을 켭니다. 이렇게 하면 대각선 그리기가 훨씬 부드러워집니다.
painter.setRenderHint(QPainter::Antialiasing);
이동은 원점을 위젯의 중앙으로 이동하고 스케일 연산은 다음 그리기 작업이 위젯에 맞게 스케일되도록 합니다. 우리는 -100에서 100 사이의 x 및 y 좌표를 사용할 수 있는 배율을 사용하여 위젯의 가장 짧은 변의 길이 내에 위치하도록 합니다.
painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0);
코드를 더 간단하게 만들기 위해 위젯의 중앙에 위치하도록 위치와 크기를 조정할 고정된 크기의 시계 화면을 그립니다.
페인터는 페인트 이벤트 중에 이루어진 모든 변형을 처리하고 모든 것이 올바르게 그려지도록 합니다. 페인터가 변환을 처리하도록 하는 것이 사용자 지정 위젯의 내용을 그리기 위해 수동 계산을 수행하는 것보다 쉬운 경우가 많습니다.
윤곽선이 필요 없으므로 펜을 Qt::NoPen 으로 설정하고 시간을 표시하는 데 적합한 색상의 단색 브러시를 사용합니다. 브러시는 다각형 및 기타 기하학적 모양을 채울 때 사용됩니다.
painter.setPen(Qt::NoPen); painter.setBrush(hourColor);
먼저 좌표계를 현재 시와 분에 따라 결정된 수만큼 시계 반대 방향으로 회전하는 공식을 사용하여 시침을 그립니다. 즉, 시침이 필요한 만큼 시계 방향으로 회전하여 표시됩니다. 이전 회전을 고려하지 않고 분침을 배치하기 위해 회전 전후의 변환 행렬을 저장하고 복원합니다.
painter.save(); painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 4); painter.restore();
시침과 같은 색으로 매 시간마다 시계 가장자리에 마커를 그립니다. 각 마커를 그린 다음 좌표계를 회전하여 화가가 다음 마커를 그릴 준비를 합니다.
for (int i = 0; i < 12; ++i) { painter.drawRect(73, -3, 16, 6); painter.rotate(30.0); }
분침도 시침과 비슷한 방식으로 회전하고 칠합니다.
painter.setBrush(minuteColor); painter.save(); painter.rotate(6.0 * time.minute()); painter.drawConvexPolygon(minuteHand, 4); painter.restore();
초침의 경우 동일한 작업을 수행하고 시각적 하이라이트로 두 개의 시클을 추가합니다.
painter.setBrush(secondsColor); 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();
마지막으로 시계 가장자리에 분과 초를 나타내는 마커를 그립니다. 이번에는 마커를 선으로 그려서 펜을 각 색으로 설정합니다.
painter.setPen(minuteColor); for (int j = 0; j < 60; ++j) { painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); }
© 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.