Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter Keyboard Binds

I'm working on an interface using Tkinter and the canvas widget, and so far have found answers to issues I have had from others questions and the answers posted, but I am stumped on this one.

I have several keyboard binds in the class where my GUI elements are created, and they all work fine when the program is started. The binds looks something like this:

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

and are within the __init__ function of the class. As of yesterday, I initialized this class to start the program, then waited for the user to select open from a menu, which then opened (among other things) a tkmessagebox

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

With this filename I am able to retrieve my required variable names from a certain filetype (inconsequential to the problem). Today I modified the __init__ function to call the open function when the program starts. Since nothing else can be done until this file is opened, it would make sense to open it first thing. Once the file is selected and the Tkmessagebox is closed, the root window is active, but none of the keyboard binds work. My functions still work using the menu/buttons assigned to them, just not the binds. I have tried binding the shortcuts to the root, with the same result, and am now thinking it may be an issue with the order I am calling them

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

I had actually run into this issue before, where a toplevel() instance was closed/destroyed and disabled the binds of the parent window. There isn't any error message to speak of, the binds just don't do anything. I should also mention I have tried to focus on the root window again using

self.openfile()
self.root.mainloop()
self.root.focus_set()

I got around it before by using the wm_withdraw() and wm_deiconify() functions to simply hide the child window, then close it after the program is complete. This fix is a little more difficult to apply in this case however. If anyone can shed some light on the cause of the problem I'd appreciate it.

Edit:

I've written up a runable code segment to show exactly what my issue is.

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()

The bind will work if self.openfile() is removed from __init__, and used only from the menu

Another Edit: I've updated the example again, giving a menu option to run the openfile() function. I noticed that if openfile() is called in __init__, the bind will not work. But if next the openfile function is called again, this time manually from the menu, the bind will start working again. Not exactly sure what to take from this. Also, my apologies for the post getting so long.

like image 720
pmacd Avatar asked Aug 02 '12 16:08

pmacd


People also ask

How does bind work in tkinter?

In Tkinter, bind is defined as a Tkinter function for binding events which may occur by initiating the code written in the program and to handle such events occurring in the program are handled by the binding function where Python provides a binding function known as bind() where it can bind any Python methods and ...

How do you bind a space key in tkinter?

Let us suppose for a particular application, we want to bind the <Space> Key such that it will perform a certain operation. We can bind any key to a particular operation or event by defining the bind(<key>, callback) method.

What is bind () in Python?

The bind() method of Python's socket class assigns an IP address and a port number to a socket instance. The bind() method is used when a socket needs to be made a server socket. As server programs listen on published ports, it is required that a port and the IP address to be assigned explicitly to a server socket.

What is B1 motion?

<B1-Motion> The mouse is moved, with mouse button 1 being held down (use B2 for the middle button, B3 for the right button). <ButtonRelease-1>


1 Answers

Change

self.openfile()

to

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

This moves the call to askopenfilename into the main event loop. Having it outside the main event loop is somehow clobbering your event bindings.

like image 124
Steven Rumbalski Avatar answered Sep 22 '22 10:09

Steven Rumbalski