Обратный отсчет с Python и Gtk, проблемы с timeout_add - PullRequest
0 голосов
/ 05 июля 2018


Я пытаюсь создать приложение для тренировки, поэтому мне приходится считать каждое отжимание или отображать обратный отсчет для боковой доски. Для этого я попытался использовать GObject.timeout_add , но, похоже, он не работает так, как я думал.
В текущей ситуации все упражнения сеанса выполняются одновременно, а не по одному в правильном порядке. Я, конечно, что-то упустил, и через мой поиск в Интернете я все еще не нашел это.
Вот мой код:

#!/usr/bin/python
"""
Work out app to keep track of your progression through the session
"""

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject
from Programms import *
from time import sleep


def time_hours(t):
    return t // 3600


def time_minutes(t):
    return (t % 3600) // 60


def time_seconds(t):
    return int((t % 3600) % 60)


def time_format(t):
    hours = double_digit(time_hours(t))
    minutes = double_digit(time_minutes(t))
    seconds = double_digit(time_seconds(t))
    return "{}:{}:{}".format(hours, minutes, seconds)


def double_digit(t):
    if t == 0:
        return "00"
    elif t < 10:
        return "0{}".format(t)
    return t


class StartingLine:
    """
    Gtk
    """
    def __init__(self):
        # main window
        self.window = Gtk.Window()
        self.window.set_title("Work out !")
        self.window.set_size_request(200, 200)
        self.window.connect('destroy', lambda x: Gtk.main_quit())

        # start button
        self.button = Gtk.Button("Start")
        self.button.connect('clicked', self.start_work_out)

        self.window.add(self.button)

        self.window.show_all()

    def start_work_out(self, widget):
        self.window.hide()
        work = Two
        duration = work.duration
        for exo in work.exercises:
            Instructor(exo, duration)


class Instructor:
    """
    Gtk
    """
    def __init__(self, exo, duration):
        # main window
        self.window = Gtk.Window()
        self.window.set_title("Work out !")
        self.window.set_size_request(200, 200)
        self.window.connect("destroy", lambda x: Gtk.main_quit())

        # timer
        self.current_time = 0
        self.counter = 0
        self.timer_label = Gtk.Label(time_format(self.counter))

        # exercise
        self.current_exercise = Gtk.Label(exo.name)

        # overall progression
        self.bar = Gtk.ProgressBar.new()

        # hierarchy
        grid = Gtk.Grid()
        grid.attach(self.timer_label, 1, 0, 1, 1)
        grid.attach(self.current_exercise, 1, 1, 1, 1)
        grid.attach(self.bar, 1, 2, 1, 1)
        self.window.add(grid)

        # display
        self.window.show_all()

        if exo.type == ExoType.Reps:
            print('exercise : ', exo.name)
            self.counter = 0
            self.timer_label.set_label(str(self.counter))
            rep_id = GObject.timeout_add(1000*exo.in_between, self.display_rep, exo, duration)
            print("rep ID : ", rep_id)
        elif exo.type == ExoType.Timer:
            self.counter = exo.number
            self.timer_label.set_label(time_format(self.counter))
            time_id = GObject.timeout_add(1000*exo.in_between, self.display_timer, exo, duration)
            print("time ID : ", time_id)

    def display_rep(self, exo, duration):
        print("current time : ", self.current_time)
        print("current exercise : ", exo.name)
        print("rep : ", self.counter)
        self.counter += 1
        self.current_time += exo.in_between
        self.timer_label.set_label(str(self.counter))  # update counter
        self.current_exercise.set_label(exo.name)  # update exercise name
        self.bar.set_fraction(self.current_time/duration)  # update progression bar
        return self.counter < exo.number

    def display_timer(self, exo, duration):
        print("current time : ", self.current_time)
        print("current exercise : ", exo.name)
        print("timer : ", self.counter)
        self.counter -= 1
        self.current_time += exo.in_between
        self.timer_label.set_label(time_format(self.counter))  # update counter
        self.current_exercise.set_label(exo.name)  # update name
        self.bar.set_fraction(self.current_time/duration)  # update progression bar
        return self.counter > 0


if __name__ == "__main__":
    StartingLine()
    Gtk.main()

В этом коде я использовал два типа:

#!/usr/bin/python

"""
define class exercise and class session
"""


class Exercise:
    def __init__(self, name, typo, unilateral, number, preparation=0, in_between=1):
        """
        :param name: name of the exercise
        :param typo: either timer or reps
        :param number: either a time in seconds or a a number of reps
        :param preparation: time allocated to prepare the exercise, to put yourself in position
        :param in_between: time between reps. 1s by default.
        """
        self.name = name
        self.type = typo
        self.unilateral = unilateral
        self.number = number
        self.prep = preparation
        self.in_between = in_between


class ExoType(enumerate):
    Reps = 0
    Timer = 1


class Session:
    def __init__(self, name, exercises):
        self.name = name
        self.exercises = exercises
        self.duration = time_length(exercises)


def time_length(exercises):
    t = 0
    for exo in exercises:
        if exo.type == ExoType.Timer:
            t += exo.number
        elif exo.type == ExoType.Reps:
            t += exo.number*exo.in_between
        else:
            print("Error : Session duration")
    return t

В первый раз, когда я задаю вопрос здесь, пожалуйста, скажите мне, если я делаю неправильно.

1 Ответ

0 голосов
/ 11 июля 2018
rep_id = GObject.timeout_add(1000*exo.in_between, self.display_rep, exo, duration)

Когда вы timeout_add говорите Mainloop звонить function каждые n секунды.

for exo in work.exercises:
    Instructor(exo, duration)

Здесь вы добавляете каждое упражнение в основной цикл, что приводит к одновременному запуску, потому что вы создаете основной цикл один раз.

Существует несколько решений, и, на мой взгляд, ни одно из них не включает main_iteration_do.

  1. Реорганизовать вещи так, чтобы 1 упражнение выполнялось по своей основной лупе.
  2. Подайте сигнал, когда одно упражнение закончено, и в его обработчике начните другое упражнение.
...