Creating Analog Clock using PyQt5 in Python
In this post, I’ll show how to create an Analog Clock using PyQt5. I am using Python 3.7 throughout all the programs and this should work fine in Python3.8 also.
The analog clock will look like this:

And I will use three main things,
1. QPainter
2. QTimer
3. Qpolygon
First I will code to create the face of the clock, here the face of the clock means the markings for hours, minutes and seconds.
painter = QPainter()
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.hourColor)
painter.save()
painter.rotate(30.0 * (time.hour() + time.minute() / 60.0))
painter.drawConvexPolygon(AnalogClock.hourHand)
painter.restore()
painter.setPen(AnalogClock.hourColor)
for i in range(12):
painter.drawLine(88, 0, 96, 0) # markings for hour hand
painter.rotate(30.0)
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.minuteColor)
painter.save()
painter.rotate(6.0 * (time.minute() + time.second() / 60.0))
painter.drawConvexPolygon(AnalogClock.minuteHand)
painter.restore()
painter.setPen(AnalogClock.minuteColor)
for j in range(60):
if (j % 5) != 0:
painter.drawLine(92, 0, 96, 0) # markings for minute hand
painter.rotate(6.0)
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.secondColor)
painter.save()
painter.rotate(360 * (time.minute() + time.second() / 60.0))
painter.drawConvexPolygon(AnalogClock.secondHand)
painter.restore()now, in the above code, I have used painter.drawConvexPolygon() where the inside parameters are the dimension of the clock hands respectively. I have defined them above using QPolygon() class.
secondHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -95)
])
hourHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -50)
])
minuteHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -70)
])Now, you have to make little bit calculations in the painter.rotate() part to make the clock look accurate.
Like for hour hand, you want to rotate it 30(360/12.0) times in an hour, i.e. 30 * (hour + minute)
For minute hand, you wan tot rotate it 6 times in a minute, i.e 6*(minute + second/60)
And for second’s hand, you want to rotate it 360 degrees in 1 minute,360*(minute + second/60)
Thus I have implied that logic in the painter.rotate() part.
Now you have to create the main function and instantiate the AnalogClock class to run and display the clock properly.
I have summed up the total code and this looks like this:
from PyQt5.QtCore import QPoint, Qt, QTime, QTimer
from PyQt5.QtGui import QColor, QPainter, QPolygon
from PyQt5.QtWidgets import QApplication, QWidget
class AnalogClock(QWidget):
secondHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -95)
])
hourHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -50)
])
minuteHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -70)
])
hourColor = QColor(127, 0, 127)
minuteColor = QColor(0, 100, 250, 200)
secondColor = QColor(195, 0, 0, 150)
def __init__(self, parent=None):
super(AnalogClock, self).__init__(parent)
timer = QTimer(self)
timer.timeout.connect(self.update)
timer.start(1000)
self.setWindowTitle("Analog Clock")
self.resize(600, 600)
def paintEvent(self, event):
side = min(self.width(), self.height())
time = QTime.currentTime()
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.translate(self.width() / 2, self.height() / 2)
painter.scale(side / 200, side / 200)
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.hourColor)
painter.save()
painter.rotate(30.0 * (time.hour() + time.minute() / 60.0)) # 360/12.0 times per hour
print(f'hour:{time.hour()}, minute:{time.minute()}, second:{time.second()}')
painter.drawConvexPolygon(AnalogClock.hourHand)
painter.restore()
painter.setPen(AnalogClock.hourColor)
for i in range(12):
painter.drawLine(88, 0, 96, 0)
painter.rotate(30.0)
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.minuteColor)
painter.save()
painter.rotate(6.0 * (time.minute() + time.second() / 60.0)) # 6 times a minute
painter.drawConvexPolygon(AnalogClock.minuteHand)
painter.restore()
painter.setPen(AnalogClock.minuteColor)
for j in range(60):
if (j % 5) != 0:
painter.drawLine(92, 0, 96, 0)
painter.rotate(6.0)
painter.setPen(Qt.NoPen)
painter.setBrush(AnalogClock.secondColor)
painter.save()
painter.rotate(360 * (time.minute() + time.second() / 60.0)) # 360 times in a minute
painter.drawConvexPolygon(AnalogClock.secondHand)
painter.restore()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
clock = AnalogClock()
clock.show()
sys.exit(app.exec_())
You can play around with the colors of the clock hand and can change the theme of the clock. I have used the RGBA color format. Where a stands for the strength of the alpha channel. It ranges from [0,255]. 255 means opaque.
Tuhin,
I think this is good programming:
doing so much with so little code.
I am using the code for my autopilot compass which has three hands,
wind heading, boat heading, next waypoint heading.
I just made all the hands equal length and rotated each hand badsed on the headings. Works brilliantly.
Thanks for the example…