I'm building a code in which I'd like to be able to generate an event when the user changes the focus of the cursor from an Entry widget to anywhere, for example another entry widget, a button...
So far i only came out with the idea to bind to TAB and mouse click, although if i bind the mouse click to the Entry widget i only get mouse events when inside the Entry widget.
How can I accomplish generate events for when a widget loses cursor focus?
Thanks in advance!
The events <FocusIn> and <FocusOut> are what you want. Run the following example and you'll see you get focus in and out bindings whether you click or press tab (or shift-tab) when focus is in one of the entry widgets.
from Tkinter import *
def main():
global text
root=Tk()
l1=Label(root,text="Field 1:")
l2=Label(root,text="Field 2:")
t1=Text(root,height=4,width=40)
e1=Entry(root)
e2=Entry(root)
l1.grid(row=0,column=0,sticky="e")
e1.grid(row=0,column=1,sticky="ew")
l2.grid(row=1,column=0,sticky="e")
e2.grid(row=1,column=1,sticky="ew")
t1.grid(row=2,column=0,columnspan=2,sticky="nw")
root.grid_columnconfigure(1,weight=1)
root.grid_rowconfigure(2,weight=1)
root.bind_class("Entry","<FocusOut>",focusOutHandler)
root.bind_class("Entry","<FocusIn>",focusInHandler)
text = t1
root.mainloop()
def focusInHandler(event):
text.insert("end","FocusIn %s\n" % event.widget)
text.see("end")
def focusOutHandler(event):
text.insert("end","FocusOut %s\n" % event.widget)
text.see("end")
if __name__ == "__main__":
main();
This isn't specific to tkinter, and it's not focus based, but I got an answer to a similar question here:
Detecting Mouse clicks in windows using python
I haven't done any tkinter in quite a while, but there seems to be "FocusIn" and "FocusOut" events. You might be able to bind and track these to solve your issue.
From:
http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
Related
How come this isn't working? When I press the YES button that works, but when I press the NO button nothing happens.
def yespress(event):
print("Yes PRESSED")
def nopress(event):
print("No PRESSED")
## TKINTER SETUP
win = Tk()
win.title("Selector")
win.geometry('220x50')
Button_Yes = ttk.Button(win, text="YES")
Button_No = ttk.Button(win, text="NO")
Button_Yes.bind('<Button-1>', yespress)
Button_Yes.pack()
Button_No.bind('<Button-2>', nopress)
Button_No.pack()```
The problem is Not with the code you are a liitlbe bit confused with the
widget.bind(event,handler)
method.
this method handle the events that occur on the widget.
in your case you are handling the single click event here
Button_Yes.bind('<Button-1>', yespress)
but what about this method
Button_No.bind('<Button-2>', nopress)
what you really want to acheive because there is no event with name
"Button-2"
the "Button-1" event is for single click event. but if you want to listen to a
double click you should use
"Double-2" not "Button-2".
I hope i answer your question.
Feel free to ask.
for more about the bind method please read this.
https://www.python-course.eu/tkinter_events_binds.php
As far as I understand, the "normal" binding events order of a Tk/Tkinter Listbox widget is (simplifying): <ButtonPress>, <<ListboxSelect>>, <ButtonRelease>
Is it possible to "change" the order so to have <<ListboxSelect>> event triggering after the <ButtonRelease> one?
I was trying using bindtags together with a custom "fake" bind_class for this but without getting the desired result so far...
Here's the code sample:
import tkinter as tk
root = tk.Tk()
l = tk.Listbox(root, name='custlist')
for e in range(55): l.insert(tk.END, 'L_item'+str(e))
l.pack()
l.bind('<ButtonPress>', lambda e: print("L: Click"))
l.bind('<ButtonRelease>', lambda e: print("L: ButtonRelease"))
l.bind_class("post-class-bindings", "<<ListboxSelect>>", lambda e: print("L: post-ListboxSelect"))
l.bindtags((l.winfo_pathname(l.winfo_id()),'Listbox','post-class-bindings', '.', 'all'))
Can you tell me if is it possible to obtain such a thing in this way or another?
Thank you
EDIT:
Thinking of it I realize I can't get it that way 'cause I guess
<ButtonPress>+<<ListboxSelect>> events are somewhat "chained" in their flow while <ButtonRelease> is something "untied", so that I should invoke/generate the <<ListboxSelect>> event at the end of the <ButtonRelease> callback to trigger it... That might work most of the times but... That's not what I was trying to get here... (Indeed, that would be just like "moving" the <<ListboxSelect>> event code to the <ButtonRelease> callbak...)
So, in the end, the question would be if is it possible to "chain" ButtonRelease together with ListboxSelect (in the same way as for ButtonPress)? ... And I guess something like that isn't possible
Is it possible to "change" the order so to have <<ListboxSelect>> event triggering after the one?
The only way to do that is to prevent the selection from changing on a button click. <<ListboxSelect>> isn't a direct result of a button click or a button release, it's a direct result of the selection having been changed. You can't have the selection change on a click and not have <<ListboxSelect>> be generated.
I don't quite understand what your real need is, but if you want to be notified of a selection change on the release of the button you can always emit your own custom virtual event in a handler for <ButtonRelease-1>, for instance, <<ListboxSelectAfterClick>>.
Thanks to Bryan Oakley's clarifications I came to a possible solution for this:
The main intent for me was to have the element
selection in the list to activate/trigger only after the mouse button being released.
import tkinter as tk
root = tk.Tk()
l = tk.Listbox(temp, name='custlist', selectmode='single')
for e in range(55): l.insert(tk.END, 'L_item'+str(e))
l.pack()
l.bind('<ButtonPress>', lambda e: "break")
def AfterReleaseSelect(event):
event.widget.selection_clear(0,tk.END)
event.widget.selection_set(event.widget.nearest(event.y))
#more stuffs here if needed...
l.bind('<ButtonRelease>', AfterReleaseSelect)
What I'm doing here, in practice, is preventing the button click to do its job, so that the listbox selection won't be triggering, and then wait for the mouse button being released to do the stuff.
Some final thoughts on this:
First of all, please notice: I added selectmode='single' parameter to the Listbox widget here as I think it wouldn't be worth to apply such approach when dealing with default ("'browse'-select") Listboxes. This is because, differently than "'browse'-select" Listboxes, with "'single'-select" Listboxes elements selection doesn't "follow" the mouse 'till the end, it gets "stuck" on the first-clicked-element, even if you end releasing the mouse button on a different item.
I must say, anyhow, this probably won't be worth most of the times 'cause you might simply:
avoid using selectmode='single' parameter, staying with the default listbox 'browse'-select-behavior;
"move" the code you would execute with a bind <<ListboxSelect>> to a bind on <ButtonRelease> (as far as this doesn't involve too much "twisting" on the rest of the code, of course...)
I have an entry field, and as I type into the data field, I want a method, that updates a treeview widget to be ran. Currently, I can type in a search parameter, then press a 'search' button and it will run the method to search through the treeview to find specified clients, but I want to the treeview to be updating whilst typing into the entry, not by a button press
I am unsure as to weather this is possible, if it should be doing by binding keys or if there is a way using the event loop to achieve this?
See this SO post:
TkInter keypress, keyrelease events
Essentially:
from Tkinter import *
def keyup(e):
pass;
# e.char contains the pressed key if you need that info
# use your search function here
Edit (Sorry I forgot this):
You'll need to bind the keyup function to your widget with something like:
frame.bind("<KeyRelease>", keyup) # you can also bind to a search widget
I'm making a program on the Raspberry Pi with a touchscreen display.
I'm using Python Tkinter that has two entry widgets and one on screen keypad. I want to use the same keypad for entering data on both entry widgets.
Can anyone tell me how can i check if an entry is selected? Similar like clicking on the Entry using the mouse and the cursor appears. How can I know that in Python Tkinter?
Thank you.
There is always a widget with the keyboard focus. You can query that with the focus_get method of the root window. It will return whatever widget has keyboard focus. That is the window that should receive input from your keypad.
You can use events and bindigs to catch FocusIn events for your entries.
entry1 = Entry(root)
entry2 = Entry(root)
def callback_entry1_focus(event):
print 'entry1 focus in'
def callback_entry2_focus(event):
print 'entry2 focus in'
entry1.bind("<FocusIn>", callback_entry1_focus)
entry2.bind("<FocusIn>", callback_entry2_focus)
I am making a box that is similar to the tkMessageBox. There are two simple behaviors that I want to the box to have. First I want the button to be selected automatically when the window opens, and second I want to be able to press enter to push the button. Sounds simple and I realize that I could use the tkinterMessageBox to do this same thing, but this is a stepping stone, and I would like to know how to do this in the future for other things.
The current behavior of the window below is that it opens, and if I press tab it will select the button, but then i can only press the button with the mouse. Again the desired functionality is to have the button selected right away and be able to press the button with the enter key.
import Tkinter, tkMessageBox
from Tkinter import *
def closewindow():
Messagebox.destroy()
Messagebox=Tk()
l3=Label( Messagebox, text="This is your preview! Align camera then press ESC")
b3=Button(Messagebox, text="Okay", command=closewindow)
l3.grid(row=1,column=1)
b3.grid(row=2,column=1)
Messagebox.mainloop()
You can actually do this with just two lines of code:
b3.bind('<Return>', lambda _: closewindow())
b3.focus_set()
The first binds the button to the Enter key and the second sets the application's focus on the button.
Note that I had to use a lambda with the binding to handle the event object that will be sent to the callback. You could however change the definition of closewindow to handle this:
def closewindow(event=None):
Messagebox.destroy()
Now you can just do:
b3.bind('<Return>', closewindow)
For more information on bindings in Tkinter, see Events and Bindings over on Effbot.