【问题标题】:Tkinter Keyboard BindsTkinter 键盘绑定
【发布时间】:2012-08-02 16:07:51
【问题描述】:

我正在使用 Tkinter 和画布小部件开发一个界面,到目前为止,我已经从其他问题和发布的答案中找到了问题的答案,但我对这个问题感到困惑。

我在创建 GUI 元素的类中有几个键盘绑定,并且在程序启动时它们都可以正常工作。绑定看起来像这样:

self.canvas.get_tk_widget().bind("<Control-o>",self.flash_open)

并且在类的 __init__ 函数中。截至昨天,我初始化了这个类 启动程序,然后等待用户从菜单中选择打开,然后打开(除其他外)一个 tkmessagebox

self.specfilename =askopenfilename(filetypes=[("spec", "")],initialdir= self.pathname)

使用这个文件名,我可以从某个文件类型中检索我需要的变量名(与问题无关)。今天修改了__init__函数,在程序启动时调用open函数。由于在打开此文件之前无法进行任何其他操作,因此首先打开它是有意义的。选择文件并关闭 Tkmessagebox 后,根窗口将处于活动状态,但没有任何键盘绑定工作。我的功能仍然可以使用分配给它们的菜单/按钮工作,而不是绑定。我尝试将快捷方式绑定到根目录,结果相同,现在我认为这可能是我调用它们的顺序问题

def __init__(self):
    ...
    self.openfile() #calls the tkmessagebox
    self.root.mainloop() #starts gui

我之前实际上遇到过这个问题,其中一个 toplevel() 实例被关闭/销毁并禁用了父窗口的绑定。没有任何错误消息可言,绑定只是不做任何事情。我还应该提到我已经尝试使用

再次关注根窗口
self.openfile()
self.root.mainloop()
self.root.focus_set()

我之前通过使用 wm_withdraw() 和 wm_deiconify() 函数来简单地隐藏子窗口,然后在程序完成后关闭它。但是,在这种情况下,此修复程序更难应用。如果有人可以阐明问题的原因,我将不胜感激。

编辑:

我编写了一个可运行的代码段来准确显示我的问题所在。

import os
from tkFileDialog import askopenfilename
from Tkinter import *


class Start:
    def __init__(self):

        self.root = Tk()
        self.root.title('Binding Troubles')
        menubar = Menu(self.root)
        #add items and their commands to the menubar
        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label="Do work", command=self.do_work)
        filemenu.add_command(label="Open File",command=self.openfile)
        menubar.add_cascade(label="File", menu=filemenu)
        #bind control-o to perform the do work function
        self.root.bind("<Control-o>",self.flash_do_work)
        self.root.bind("<Control-O>",self.flash_do_work)
        #add the menubar to the GUI
        self.root.config(menu=menubar) 
        #initially open a tkdialog to open a file
        self.openfile()#comment out this line to make the bind work 
        self.root.focus()#also tried self.root.focus_set()
        self.root.mainloop()
    def flash_do_work(self,event):
        #indirect tie to the do_work() function, I'm don't know a 
        #proper way to make functions handle calls from both events and non-events
        self.do_work()
    def openfile(self):
        #gets current path
        self.pathname = os.getcwd()
        #Requests filename using a tkdialog
        self.filename =askopenfilename(initialdir= self.pathname)
        print self.filename
    def do_work(self):
        #placeholder for actual function; shows whether the bind is working or not
        print "work"

Start()

如果 self.openfile() 从 __init__ 中删除,绑定将起作用,并且只能从菜单中使用

另一个编辑:我再次更新了示例,提供了一个菜单选项来运行 openfile() 函数。我注意到如果在 __init__ 中调用 openfile(),绑定将不起作用。但是如果接下来再次调用 openfile 函数,这次是从菜单中手动调用,绑定将再次开始工作。不完全确定从中得到什么。另外,很抱歉帖子拖了这么久。

【问题讨论】:

  • 我没有,它是两种情况下的最后一个条目(在 _init_ 中调用 openfile() 或不调用),除非我尝试调用 focus_set(),从那以后我搬到了self.openfile() self.root.focus_set() self.root.mainloop() 编辑:我很难得到正确的评论格式......
  • 我注意到您将键盘事件绑定到特定小部件。除非小部件具有焦点,否则这甚至不会触发。更常见的是将事件绑定到父框架或整个窗口或根。
  • 在我刚刚添加的示例中,我将快捷方式绑定到了根目录。我还尝试在再次调用self.root.mainloop() 之前包含self.root.focus_set(),不幸的是问题仍然存在。但是,我已将绑定更改为程序中的根目录。
  • 我希望我对您提供的工作示例有额外的 +1。它确实澄清了这个问题。
  • 感谢您的反馈和答复!一旦我设法获得更多声誉,我会回来并应用一些向上箭头......它似乎还没有让我这样做。

标签: python tkinter keyboard-shortcuts


【解决方案1】:

改变

self.openfile()

self.root.after(1, self.openfile)

这会将对askopenfilename 的调用移动到主事件循环中。将它放在主事件循环之外会以某种方式破坏您的事件绑定。

【讨论】:

  • 哦,资本!它现在有效,我现在唯一担心的是某种竞争条件(尽管不太可能)发生。 after call中的1是否对应一定的时间?
  • 我不相信它会导致竞争条件。我认为 Tkinter 将它安排的事件排队。 after 方法中的 1 对应于 1 毫秒。见Time Tools, Threads, and Animation
  • 那么主循环之后的 1ms 开始了吗?谢谢你的链接,我会读一读
  • 如果我将延迟设置为零,您的错误会再次出现,这意味着一旦注册回调,时钟就会开始滴答作响。我不知道主循环启动的时间是否太短。
  • self.root.after_idle(self.openfile) 怎么样?这是否也会导致出现错误?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多