Code analysis of Qt drawing clock

brief description

QPainter provides common operations for 2D drawing, and QTimer provides a timer function. Combining the two, you can make a lot of custom special effect drawing.

Next, let's implement something that we have to touch every day - the clock. Contains all common functions: hour, minute, second.

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Method to realize

Since the clock is updated, we need to refresh regularly, and the clock itself is drawn using the QPainter mentioned earlier.

Use QTimer to refresh regularly, and set the timeout to 1000 milliseconds (1 second).
Draw the clock, realized by paintEvent(), including: hour hand, minute hand, second hand, panel, dial, etc.
Draw the text corresponding to the hour, and the text area is calculated by textRectF().

example

Effect

 

source code

First, we construct a timer QTimer and connect its timeout signal timeout() to the slot function update(). When update() is called, the system will automatically notify the current interface to redraw (paintEvent()).

ClockWidget::ClockWidget(QWidget *parent)
  : QWidget(parent)
{
  ...
 
  // 构造定时器,设置超时为 1 秒
  QTimer *timer = new QTimer(this);
  connect(timer, SIGNAL(timeout()), this, SLOT(update()));
  timer->start(1000);
  ...
}

Implement an interface for getting the text area:

QRectF ClockWidget::textRectF(double radius, int pointSize, double angle)
{
  QRectF rectF;
  rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2);
  rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0);
  rectF.setWidth(pointSize*4);
  rectF.setHeight(pointSize);
  return rectF;
}

Note: Here, textRectF() is mainly used to obtain the text area corresponding to the hour.

Override paintEvent() to draw the clock.

void ClockWidget::paintEvent(QPaintEvent *event)
{
  Q_UNUSED(event);
 
  // 时针、分针、秒针位置 - 多边形
  static const QPoint hourHand[3] = {
    QPoint(7, 8),
    QPoint(-7, 8),
    QPoint(0, -30)
  };
  static const QPoint minuteHand[3] = {
    QPoint(7, 8),
    QPoint(-7, 8),
    QPoint(0, -65)
  };
 
  static const QPoint secondHand[3] = {
    QPoint(7, 8),
    QPoint(-7, 8),
    QPoint(0, -80)
  };
 
  // 时针、分针、秒针颜色
  QColor hourColor(200, 100, 0, 200);
  QColor minuteColor(0, 127, 127, 150);
  QColor secondColor(0, 160, 230, 150);
 
  int side = qMin(width(), height());
  QTime time = QTime::currentTime();
 
  QPainter painter(this);
  painter.setRenderHint(QPainter::Antialiasing);
  // 平移坐标系原点至中心点
  painter.translate(width() / 2, height() / 2);
  // 缩放
  painter.scale(side / 200.0, side / 200.0);
 
  // 绘制时针
  painter.setPen(Qt::NoPen);
  painter.setBrush(hourColor);
 
  painter.save();
  // 每圈360° = 12h 即:旋转角度 = 小时数 * 30°
  painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
  painter.drawConvexPolygon(hourHand, 3);
  painter.restore();
 
  painter.setPen(hourColor);
 
  // 绘制小时线 (360度 / 12 = 30度)
  for (int i = 0; i < 12; ++i) {
    painter.drawLine(88, 0, 96, 0);
    painter.rotate(30.0);
  }
 
  int radius = 100;
  QFont font = painter.font();
  font.setBold(true);
  painter.setFont(font);
  int pointSize = font.pointSize();
 
  // 绘制小时文本
  int nHour = 0;
  for (int i = 0; i < 12; ++i) {
    nHour = i + 3;
    if (nHour > 12)
      nHour -= 12;
    painter.drawText(textRectF(radius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour));
  }
 
  // 绘制分针
  painter.setPen(Qt::NoPen);
  painter.setBrush(minuteColor);
 
  painter.save();
  // 每圈360° = 60m 即:旋转角度 = 分钟数 * 6°
  painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
  painter.drawConvexPolygon(minuteHand, 3);
  painter.restore();
 
  painter.setPen(minuteColor);
 
  // 绘制分钟线 (360度 / 60 = 6度)
  for (int j = 0; j < 60; ++j) {
    if ((j % 5) != 0)
      painter.drawLine(92, 0, 96, 0);
    painter.rotate(6.0);
  }
 
  // 绘制秒针
  painter.setPen(Qt::NoPen);
  painter.setBrush(secondColor);
 
  painter.save();
  // 每圈360° = 60s 即:旋转角度 = 秒数 * 6°
  painter.rotate(6.0 * time.second());
  painter.drawConvexPolygon(secondHand, 3);
  painter.restore();
}

Well, the comments are written very clearly, so I won’t go into more explanations. If you want to make an application, you can implement some interfaces for setting the pointer and dial style appearance by yourself.

Note: A lot of text on the web is drawn after rotation, and the effect is not good (6 shows 9), so please avoid this!

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/m0_60259116/article/details/130411296