【问题标题】:Holding Down Button and window updating issue按住按钮和窗口更新问题
【发布时间】:2017-11-25 04:12:43
【问题描述】:

当我一直按住 Ctrl+Up 时,我需要标签以 1000 毫秒的间隔更新。 (如果我按住 Ctrl+Up 5,2 秒,命令应该运行 5 次。)

after 方法似乎对此不起作用。它的行为也很奇怪,就好像它记录了我按下了多少次键,并且即使在 Ctrl+Up 未按下之后也会继续循环。

from Tkinter import * 

root = Tk()

def start(event):
    global x
    x = x+1
    x_var.set(x)
    root.after(1000, lambda: start(event))

x=1

x_var=IntVar()
x_var.set(x)

r = Label(root, textvariable=x_var)
r.pack()

root.bind('<Control-Up>', start)
root.mainloop()

【问题讨论】:

    标签: python python-2.7 tkinter


    【解决方案1】:

    这是一种在按住 Control + Up 的同时每 1000 毫秒运行一次命令的方法:

    • 存储和更新ControlUpcurrent pressed statuses

    • 有一个 .after() 循环,它每 1000 毫秒调用一次,如果当前同时按下 ControlUp,则在其中运行所需的命令。

    代码

    import Tkinter as tk
    
    root = tk.Tk()
    
    x = 1
    x_var = tk.IntVar()
    x_var.set(x)
    
    r = tk.Label(root, textvariable=x_var)
    r.pack()
    
    isPressed = {"Control_L": False, "Up": False}
    
    def update_key_status(key, value):
        global isPressed
        isPressed[key] = value
    
    # Make the Press/Release events of both keys update the "isPressed" dictionary
    for key in ["Up", "Control_L"]:
        root.bind('<KeyPress-{}>'.format(key), 
                  lambda evt, key=key: update_key_status(key, True))
        root.bind('<KeyRelease-{}>'.format(key), 
                  lambda evt, key=key: update_key_status(key, False))
    
    def increment_x():
        global x, x_var
        x += 1
        x_var.set(x)
    
    def start():
        if (isPressed["Control_L"] and isPressed["Up"]):
            increment_x()
        root.after(1000, start)
    
    start()
    root.mainloop()
    

    【讨论】:

    • 哦,这就是我想要的方式。我正在使用python 2.7,忘了说:x。我调整了 Tk,它起作用了,我会进一步研究你在那里做了什么,谢谢。
    【解决方案2】:

    after 方法似乎对此不起作用。

    不,它正在按照您的程序要求的方式工作。

    它的行为也很奇怪,好像它记录了我按了多少次键 并且即使在 Ctrl+Up 未按下后也会继续循环。

    这并不奇怪。瞥一眼给定的documentation,您将阅读:

    每次调用此方法时,只会调用一次回调。保持 调用回调,需要在里面重新注册回调 本身

    粗体文本正是您在start() 函数中所做的。因此,您当前代码的逻辑行为是,一旦您按下 Ctrl + Up,该回调将等待 1000 毫秒执行,之后它将继续永远运行(好吧,直到你结束 mainloop() 事件)

    所以要让你的程序在每次按下你指定的键后只增加一次标签的内容,你需要避免上面用粗体字写的设计。一个解决方案可以包括创建一个特定的增量函数,如下所示:

    def increment_x():
       global x, x_var
       x += 1
       x_var.set(x)
    

    然后将此函数用作您的start() 函数中的回调:

    def start(event):    
        root.after(1000, increment_x)
    

    所以你的代码变成了:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from Tkinter import * 
    
    root = Tk()    
    
    def start(event):    
        root.after(1000, increment_x)
    
    def increment_x():
       global x, x_var
       x += 1
       x_var.set(x)
    
    
    x=1
    
    x_var=IntVar()
    x_var.set(x)
    
    r = Label(root, textvariable=x_var)
    r.pack()
    
    root.bind('<Control-Up>', start)
    root.mainloop()
    

    附:请关注PEP8

    【讨论】:

    • 好的,但它仍然不能满足我的要求。按住 Control+Up 时,标签每秒更新 30 次。我希望命令在 1 秒后运行一次,同时按住 Control+Up。
    • 您必须按下一次并松开键。否则,如果您一直按下键(按住它们),您将触发事件绑定执行,因此标签的内容将快速增加并继续响应事件@MaiconErick
    • 那么,在按住按键来实现我想要的效果时,没有办法“暂停”一段时间的执行吗?
    • 您想要达到的目标与events binding 的理念背道而驰。我希望你明白这一点。但是,如果你想“打破”这个规则,你可以破解你的程序:例如,检查标签的内容何时更改为 2,然后使用unbind() 方法解除连续按键事件的绑定。但是不要指望其他按键会起作用。 @MaiconErick
    • 我想要这种“等待”,因为在繁重的工作中,假设我按住按键 5 秒,标签只会在 5 秒后更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2012-04-21
    • 2012-09-26
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    相关资源
    最近更新 更多