Communication with the video detection ⚙️
For communicating the change in variables modified in the detection algorithm, a AppSignals class is created, taking advantage of the pyqtSignal facility.
class AppSignals(QObject):
stop_detection = pyqtSignal()
start_detection = pyqtSignal()
update_reps = pyqtSignal(int)
update_avg_time = pyqtSignal(float)
update_training_time = pyqtSignal(int)
update_set_time = pyqtSignal(int)
update_rest_time = pyqtSignal(int)
This class is used in the initializer method of the Home class
class Home(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.settings()
self.app_signals = AppSignals()
self.detection_worker = DetectionWorker(self.app_signals)
self.start_session_button.clicked.connect(self.app_signals.start_detection.emit)
self.end_session_button.clicked.connect(self.app_signals.stop_detection.emit)
self.app_signals.update_reps.connect(self.update_reps_label)
self.app_signals.update_avg_time.connect(self.update_avg_time_label)
self.app_signals.update_training_time.connect(self.update_training_time_label)
self.app_signals.update_set_time.connect(self.update_set_time_label)
self.app_signals.update_rest_time.connect(self.update_rest_time_label)
This method initializes the UI and the settings of the app.
Then the objects of app_signals and detection_worker are created, the first one for managing the change in variables in real time and the second one for calling the detection methods described in the last devlog.
The rest of the lines connect the clicks in buttons to their respective actions and the change in variables to the update of their respective labels.
Updating methods and settings
def settings(self):
self.setWindowTitle("FitVision")
self.setGeometry(250, 250, 600, 400)
def update_reps_label(self, reps):
self.last_session_total_reps.setText(f"Total Reps: {reps}")
def update_avg_time_label(self, avg_time):
self.last_session_avg_time_per_rep.setText(f"Avg time per rep: {avg_time:.2f}s")
def update_training_time_label(self, training_time):
self.last_session_training_time.setText(f"Total training time: {training_time}s")
def update_set_time_label(self, set_time):
self.last_set_time.setText(f"Set time: {set_time}s")
def update_rest_time_label(self, rest_time):
self.last_rest_time.setText(f"Rest time: {rest_time}s")
The settings method, which sets the initial parameters of the app is called at the initialization of the Home object, and the rest of the methods are called whenever a change in the value of any variable is communicated through the app_signals object.
First version of the User Interface 🖥️
The code
The first version of the app's UI is powered by PyQT5
def initUI(self):
self.start_session_button = QPushButton("Start Session")
self.end_session_button = QPushButton("End Session")
self.last_session_total_reps = QLabel("Total Reps: 0")
self.last_session_avg_time_per_rep = QLabel("Avg Time per Rep: 0s")
self.last_session_training_time = QLabel("Training Time: 0s")
self.last_set_time = QLabel("Set Time: 0s")
self.last_rest_time = QLabel("Rest Time: 0s")
The first lines of the UI initializer method are used to define the interface elements.
self.master = QVBoxLayout()
row1 = QHBoxLayout()
row2 = QHBoxLayout()
row3 = QHBoxLayout()
row1.addWidget(self.start_session_button, alignment=Qt.AlignCenter)
row1.addWidget(self.end_session_button, alignment=Qt.AlignCenter)
row2.addWidget(self.last_session_training_time, alignment=Qt.AlignCenter)
row2.addWidget(self.last_session_total_reps, alignment=Qt.AlignCenter)
row2.addWidget(self.last_session_avg_time_per_rep, alignment=Qt.AlignCenter)
row3.addWidget(self.last_set_time, alignment=Qt.AlignCenter)
row3.addWidget(self.last_rest_time, alignment=Qt.AlignCenter)
self.master.addLayout(row1, 50)
self.master.addLayout(row2, 25)
self.master.addLayout(row3, 25)
self.setLayout(self.master)
Then, the widgets are created and placed in the master layout.
self.setStyleSheet("""
QWidget {
background-color: #565656;
}
QPushButton {
background-color: #1c549f;
padding: 20px;
border-width: 5px;
border-style: solid;
border-radius: 5px;
border-color: #1a4b8e;
color: white;
margin-top: 40px;
}
QPushButton:hover {
background-color: #1a4b8e;
}
""")
And finally, a simple CSS style is applied.
The results 👀
The result is a simple and minimalistic UI which tells the user some important metrics of his/her workout.
Important: The size of the window is currently set to be 600x400 as seen in the settings() method, but this and many other things may be changed in the future.
Next steps 📑
The next planned steps are the following:
- Add a Pause session feature
- Improve the UI desing
- Add a visual feedback to some counts like the avg_time per rep, set/rest times and repetition count.
Thanks for reading! 🤗
Credits
I watched the following video to get to know PyQT5:
Build a Python Desktop Application in Minutes | Code with Josh
Top comments (0)