Python 和 Gtk 的倒计时,timeout_add 的问题

Countdown with Python and Gtk, problems with timeout_add


我正在尝试制作一个锻炼应用程序,所以我必须计算每个俯卧撑或显示侧板倒计时。为此,我尝试使用 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

第一次在这里提问,如有不妥请指正

rep_id = GObject.timeout_add(1000*exo.in_between, self.display_rep, exo, duration)

当您 timeout_add 时,您告诉 Mainloop 每 n 秒调用一次 function

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

此处将每个练习添加到 mainloop,这会导致同步 运行,因为您创建了一次 mainloop。

有几种解决方案,在我看来 none 其中包括 main_iteration_do

  1. 重组事物,使 1 个练习 运行 成为自己的主循环。
  2. 当一个练习完成并在它的处理程序中开始另一个练习时发出信号。