I implement a label that displays the current time in several of my PyQt5 applications. Here is a MRE:
import sys
import logging
from PyQt5 import QtWidgets, QtCore, QtGui
__log__ = logging.getLogger()
class App(QtWidgets.QApplication):
def __init__(self, sys_argv):
super(App, self).__init__(sys_argv)
self.main_view = MainView()
self.main_view.show()
class MainView(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setObjectName("MreUi")
self.resize(300, 100)
self.setWindowTitle('MreUi')
self.label = QtWidgets.QLabel()
self.setCentralWidget(self.label)
config_clock(self.label)
self.start_clocks()
def start_clocks(self):
timer = QtCore.QTimer(self)
timer.timeout.connect(self.show_time)
timer.start(1000)
def show_time(self):
current_time = QtCore.QTime.currentTime()
clock_label_time = current_time.toString('hh:mm:ss')
self.label.setText(clock_label_time)
def config_clock(label):
label.setAlignment(QtCore.Qt.AlignCenter)
font = QtGui.QFont('Arial', 24, QtGui.QFont.Bold)
label.setFont(font)
if __name__ == '__main__':
logging.basicConfig()
app = App(sys.argv)
try:
sys.exit(app.exec_())
except Exception as e:
__log__.error('%s', e)
As I implemented a similar clock in several of my PyQt apps, I thought it would be nice to implement it as a component / encapsulate it. First I thought of doing this by calling a config_clock function from any QWidget, and have that function do ~ALL of the work implementing the clock for the specified label. This would avoid having to repeat myself in multiple applications from writing/calling start_clocks and show_time instance methods of MainView. but as I started to code that ...
# from inside my QWidget:
config_clock(self.label)
# this function would live outisde the class, thus reusable by diff Qt apps:
def config_clock(label):
# start the clock
# set default font, etc for label
# instantiate QtCore.QTimer
# # but that's when I realized I've always passed self to QtCore.QTimer and that maybe encapsulating this isn't as trivial as I thought.
Should I create some kind of ClockLabel() object of my own that gets passed a QtWidget's label and can also be an instance attribute of each QtWidget that might need it? That smells kind of clunky to me. But surely there must be a way to make a 'reusable component' in PyQt, I just don't know how...
I also am not certain if the MainView(QtWidgets.QMainWindow) could rightly be referred to as the 'parent class' if I were to pass it as a parameter to a ClockLabel() class I write or a config_clock function whose signature could look like:
def config_clock(label, parent_qtwidget):
# also feels clunky and not sure if parent would be the right term
Thanks
CodePudding user response:
With QtWidgets it is normal to specialize widgets by inheritance. Here is an example of how you might rearrange your code to produce a reusable widget:
class ClockLabel(QtWidgets.QLabel):
def __init__(self, parent=None):
super().__init__(parent)
self.setAlignment(QtCore.Qt.AlignCenter)
font = QtGui.QFont('Arial', 24, QtGui.QFont.Bold)
self.setFont(font)
self._timer = QtCore.QTimer(self)
self._timer.timeout.connect(self._show_time)
def start(self):
self._timer.start(1000)
def stop(self):
self._timer.stop()
def _show_time(self):
current_time = QtCore.QTime.currentTime()
clock_label_time = current_time.toString('hh:mm:ss')
self.setText(clock_label_time)
