DEV Community

Cover image for FitVision - devlog #2
Eric Garcia
Eric Garcia

Posted on

FitVision - devlog #2

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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;
            }
        """)
Enter fullscreen mode Exit fullscreen mode

And finally, a simple CSS style is applied.

The results 👀

Image description

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)

OSZAR »