【问题标题】:Is there a way to implement a countdown within a window, without the window freezing?有没有办法在窗口内实现倒计时,而不会冻结窗口?
【发布时间】:2020-05-26 10:07:27
【问题描述】:
import PySimpleGUI as sg
import time
q1 = [
        [sg.Text("Question 1!"), sg.Button("x", visible=False), sg.Text("Time:"), sg.Text(" ", size=(10,1), key="t")],
        [sg.Text("This is where question 1 will be?")],
        [sg.Button("Option 1", key="1",button_color=("#ffffff","#151515")), sg.Button("Option 2", key="2",button_color=("#00ff00", "#151515"))],
        [sg.Button("Option 3", key="3",button_color=("#00ffff", "#151515")), sg.Button("Option 4", key="4",button_color=("#ff00ff", "#151515"))],
        [sg.Button("Submit"), sg.Button("Next Question"), sg.Button("Skip")]
    ]

window = sg.Window("Question 1",q1)

while True:
    event, values = window.Read()
    if event is None:
        break

    seconds = 20
    for i in range(seconds):
        seconds = seconds - i
        window.FindElement("t").Update(seconds)
        time.sleep(1)

我不确定我是否以正确的方式处理此问题,但我想在右上角显示一个 20 秒计时器。但是,使用上面的代码,没有计时器启动,当您按下按钮时,它会冻结程序 20 秒。

【问题讨论】:

  • 您是否只是在使用计时器向用户显示还剩多少时间,以及当它达到零时您想退出?
  • @DJSchaffner 是的,这个想法是,如果时间到 0 并且他们没有回答,它将跳到下一个问题。但是,我还想保留每个问题所花费的时间,以便我可以显示完成测验所用的时间
  • 我现在想到的 2 个选项是 A)在不同的线程中运行你的计时器,因此它仍然倒计时但不会阻塞主循环或 B)使用来自 @987654323 的 time 方法@ 包裹。然后手动计算你的计时器。我将继续发布选项 B) 的答案
  • 我添加了一个关于如何做计时器的答案。至于更新窗口中的计时器:我自己没有尝试过,但似乎你应该这样做window['mykey'].update(textVar)

标签: python pysimplegui


【解决方案1】:

如果在这篇文章的许多注释中讨论了这一点,我们深表歉意。如果是这样,请随意忽略并抱歉占用空间。

  1. 永远不要在事件循环中放置“睡眠”。改为在 window.read 上使用超时
  2. 调用 window.refresh() 以使更改出现在您的窗口中: https://pysimplegui.readthedocs.io/en/latest/call%20reference/#window 它指出:

当您希望某些内容立即出现在您的窗口中时(只要调用此函数),请使用此调用。如果没有此调用,您对 Window 的更改将在下一次 Read 调用之前对用户不可见

  1. 有一个计时器演示 - 此演示和定期刷新窗口的概念在整个文档、演示程序和 Trinket 中都有引用。如果您不定期调用 read 或 refresh ,文档直接谈到让窗口看起来冻结。主要文档中讨论了计时器:

https://pysimplegui.readthedocs.io/en/latest/#persistent-window-example-running-timer-that-updates

【讨论】:

    【解决方案2】:

    您可以选择保存开始时间,并在主循环的每次迭代中计算时间差并更新计时器。
    当差值达到 20 秒时,您停止并继续进行下一个问题,否则您将保留当前剩余时间或任何您想用它做的事情并开始新的问题。

    这是一个基本的例子:

    from time import time
    
    TIME_PER_QUESTION = 20.0
    
    # Loop questions
    for i in range(3):
      start = time()
      current = time()
      time_left = TIME_PER_QUESTION
    
      while time_left > 0:
        # Update your interface
        # doStuff()... update()...
    
        # Spam a bit for testing
        print("Leftover time {:.0f}".format(time_left))
    
        # Update current time and our timer
        current = time()
        time_left = TIME_PER_QUESTION - (current - start)
    

    当然,您可以添加更多方法来跳出循环并存储剩余时间等,然后继续下一个问题。

    有更多方法可以实现这一点,但这是您可以做到的一件事。 (这种技术主要用于游戏中的主循环之类的东西)
    如 cmets 中所述,如果您愿意,您也可以使用线程计时器函数来完成。

    编辑
    至于更新 gui 中的文本,我不确定你的做法是否有效,但如果你说它从未更新过,不妨试试这个:

    window['t'].update("{:.0f}".format(time_left))
    

    【讨论】:

    • 我有点理解您提供的代码,但我将如何实现它。我试图实现它,但是,计时器仍然没有出现
    • 只需将您在问题中为计时器编写的for 循环替换为我的示例中的while 循环(当然还有必要的变量)
    • 我不确定我是否执行错误,但计时器没有出现,我仍然遇到窗口冻结问题。计时器确实有效,我可以看到它出现了,但它不在 GUI 上,它也是冷冻器
    • @Mr-Nightmare 你在用update还是Update? Python 区分大小写,从我在文档中找到的内容来看,它用小写 u 拼写。如果这不起作用,我担心您提供的 pysimplgegui 代码有问题。如果是这样,我不能真正帮助你,因为我自己没有使用它。如果你省略了我在示例中给出的内部 while 循环,而只是不断更新计时器而不停止,会发生什么?
    • 同样的事情也会发生。我一直使用更新而不是更新,并且在其他程序上它可以工作
    【解决方案3】:

    我需要构建类似的东西,我使用了上面 PSG 示例计时器中的 @Mike 并将其简化为基础。

    def binary_timed(time_allowed=15,default_value=False,query='no text inputed'):
        """
        This is a GUI that will present a user with a 'query' which is a string
        it gives them a number of seconds to make a binary choice and returns
        a default value when the time runs out
        """
        #layout options for the GUI
        layout = [
                     [sg.Text(query)],#
                     [sg.Text('time remaining: %s'%time_allowed,key='timer')],
                     [
                         sg.Button('Yes'),
                         sg.Button('No'),
                     ]
                 ]
        
        #present the user with the gui
        window = sg.Window('binary_timed', layout)
        time_passed = 0
        while (True):
            event, values = window.read(timeout=1000)#1000 ms -> 1s wait between read
            time_passed += 1
            time_remaining = time_allowed-time_passed
            window['timer'].update("time remaining: %s"%time_remaining)
            if event != sg.TIMEOUT_KEY: #a button has been pressed 
                window.close()
                break
            if time_remaining == 0:
                window.close()
                break
            
        #evauluate our results
        if event == sg.WIN_CLOSED: return default_value #pressed the exit button
        if event == sg.TIMEOUT_KEY: return default_value
        if event == 'Yes': return True
        if event == 'No': return False
    

    以我的为基础,我将超时概念应用于您的概念。希望这会有所帮助并使事情变得容易理解。

    import PySimpleGUI as sg
    q1 = [
            [sg.Text("Question 1!"), sg.Button("x", visible=False), sg.Text("Time:"), sg.Text(" ", size=(10,1), key="t")],
            [sg.Text("This is where question 1 will be?")],
            [sg.Button("Option 1", key="1",button_color=("#ffffff","#151515")), sg.Button("Option 2", key="2",button_color=("#00ff00", "#151515"))],
            [sg.Button("Option 3", key="3",button_color=("#00ffff", "#151515")), sg.Button("Option 4", key="4",button_color=("#ff00ff", "#151515"))],
            [sg.Button("Submit"), sg.Button("Next Question"), sg.Button("Skip")]
        ]
    
        
    window = sg.Window("Question 1",q1)
    time_elapsed = 0
    time_remaining = 20
    while True:
        event, values = window.read(1000)
        time_remaining -= time_elapsed
        window['t'].update(time_remaining)
        time_elapsed += 1
        if event != sg.TIMEOUT_KEY: #a button has been pressed 
                window.close()
                break
        if time_remaining == 0:
            window.close()
            break
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 2021-04-28
      • 2016-12-27
      • 1970-01-01
      • 1970-01-01
      • 2020-05-25
      • 2013-01-07
      相关资源
      最近更新 更多