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…