Getting tkinter.Widget bindings - python

Is there a way to get the default binding of tk.Widget class and then call it?
I need to do this because I need to call the default binding before my custom binding. It is called as the last by default.
So what I want to do is: bind my widget to my own callback, get the default binding function, call the default binding function, call my fuction (custom binding)

If you want to simply reverse the order that the bindings are processed, you can do that by changing the binding tags without needing to know what the actual bindings are. The tags are what determines the order that events are processed. By default the value is the widget, the widget class, the toplevel window, and then "all".
The following example changes the order so that the class binding ("Entry") is handled before the binding of the widget:
import tkinter as tk
...
e = tk.Entry(...)
e.bindtags((
e.winfo_class(),
str(e),
e.winfo_toplevel(),
"all")
)

Related

Tkinter: Can you see all bindings of a widget?

In my application I want to toggle between two states, and in each of the states I want -> don't want various keys bound.
Right now what I've done is that in my class I've created an attribute self.bindings = [] and then I have a method to create bindings:
def _create_bindings(self):
self.bind("<Button-1>", self._canvas_on_click)
self.bindings.append("<Button-1>")
self.bind("<Double-Button-1>", self._canvas_on_2click)
self.bindings.append("<Double-Button-1>")
self.bind("<<arrow>>", self._canvas_on_arrows)
self.bindings.append("<<arrow>>")
self.bind("<space>", lambda event: self._toggle_selected())
self.bindings.append("<space>")
self.bind("<Key>", self._canvas_on_key_press)
self.bindings.append("<Key>")
self.bind("<BackSpace>", lambda event: self._empty_cell())
self.bindings.append("<BackSpace>")
self.bind("<Escape>", self._esc)
self.bindings.append("<Escape>")
and then to remove them:
def _remove_bindings(self):
for b in self.bindings:
self.unbind(b)
It's not terrible but it does lead to some duplication (see create function: create binding + add to list).
I could create a wrapper to combine these two steps, but regardless I still have an extra attribute to manage.
Is there a function which I can call which would provide me the same information as self.bindings above?
If you call the bind method without any parameters it will return a list of all events that you have bound for that widget. Your _remove_bindings could look like this:
def _remove_bindings(self):
for event in self.bind():
self.unbind(event)
There is no need to remove the bindings.
Altering the 'state' attribute of the e.g. Canvas, Button disables any bindings.

How to reassign object to a variable in python?

If I assign a variable (in this case b) to a button and put it on screen with pack(), then later reassign b to another data type, how do I access that button so that it can be deleted or otherwise referred to? I guess the question could be asked about any data type or object, but this is case stands out because the button is left on the screen. Example:
import tkinter as tk
root=tk.Tk()
root.geometry('300x300')
b=tk.Button(root, text="button b")
b.pack()
b=1
root.mainloop()
... then later reassign b to another data type, how do I access that button so that it can be deleted or otherwise referred to?
Short answer: you can't. In order to refer to something you must keep a reference. That being said,tkinter provides some alternatives.
If you're wanting to refer to the button in the callback, you can pass it in. This requires creating the button and then defining the callback in a separate step:
b = tk.Button(...)
b.configure(command=lambda button=b: do_something)
...
def do_something(button):
print("the widget is:", button)
Also, if you're using bindings, when the bound function is called it will be passed an event object that has an attribute that contains a reference to the widget.
b.bind("<1>", do_something)
...
def do_something(event):
print("the widget is:", event.widget)
Finally, you can ask tkinter for a list of child widgets (eg: root.winfo_children), and if you know whether you've used pack, place or grid, you can use the slaves method to query all of the widgets being managed inside a particular container (eg: root.grid_slaves(), root.pack_slaves(), root.place_slaves())
Save a reference somewhere with another assignment.
b = tk.Button(root, text="button b")
saved = b
b = 1
saved.pack()
You can access all widgets of the root window with the method:
list_of_widgets = root.pack_slaves()
and then check for the type of the object. ( Which is not a good practice ... )
Thus, i would recommend you to save the required references in a separeate object, for clearly seperating the interface to tkinter from your application. From then on, you should only access the widgets through your interface object. This creates much cleaner code.

Kivy: How to attach a callback to a widget created in kvlang

When you want to attach a callback to a kivywidget, for example a textinput you can use the bind() function. Example from Kivy docs for a textinput:
def on_text(instance, value):
print('The widget', instance, 'have:', value)
textinput = TextInput()
textinput.bind(text=on_text)
But how do I attach it to an element that was created in the kvlang file?
Get a reference to the element, then call bind as normal. For instance, for the root widget of the application you can use App.get_running_app().root.bind, or for others you can navigate the widget tree via kv ids.
You can call the bind() on the widget referenced by self.ids['id_from_kvlang']. However this cannot be done on class level, you need to operate on the instance. So you need to put it in a function of the class.
The __init__ function is called at the instantiation of the object so you can put it there. However you need to schedule it, so it won't happen instantly, the widgets you are binding to are not there yet so you have to wait a frame.
class SomeScreen(Screen):
def __init__(self,**kwargs):
#execute the normal __init__ from the parent
super().__init__(**kwargs)
#the callback function that will be used
def on_text(instance, value):
print('The widget', instance, 'have:', value)
#wrap the binding in a function to be able to schedule it
def bind_to_text_event(*args):
self.ids['id_from_kvlang'].bind(text=update_price)
#now schedule the binding
Clock.schedule_once(bind_to_text_event)

Re-binding “select all” in Entry widget

My question is related to this one where a Text widget is used.
However, in my case I want to rebind the select all on the entry widget.
I tried the following which allows me to use Ctrl+w to select all input in the entry field:
self.frmSearch = Frame()
self.txtSearch = Entry(self.frmSearch, bd=1, width=35)
self.txtSearch.bind('<Control-w>',lambda e: self.txtSearch.select_range(0, END))
However, once I change Ctrl+w to Ctrl+a this does not work anymore and no text is selected. Does anyone have an explanation why?
It is because you are putting the binding on the widget rather than the widget class, and by default the bindings on the class fire after the bindings on the widget.
The way Tkinter processes events is to first see if there is a binding on a widget, then on a class, and then on the toplevel window, and then finally on the special class "all". The events are processed in order unless you break the chain of events, so to speak. So, your control-w binding happens, but then the binding on the class happens and effectively undoes what you you did in your binding.
The best solution is to 1) not use lambda, but instead use a real method or function, and 2) do a "return 'break'" which prevents the class and other bindings from firing. Or, if you want this binding to affect all entry widgets in your application rather than just a specific one, use bind_class giving the class name of 'Entry'.
The question you refer to you in your question has an answer that gives an example of changing the class binding.

wxPython: Execute an event function automatically at program startup

There's a combobox event in my code:
self.combobox1.Bind(wx.EVT_COMBOBOX, self.onActionCombobox1)
It executes the function
def onActionCombobox1(self, event):
Is there a way to execute this function automatically everytime when I start my program?
I tried it like this:
self.onActionCombobox1(event)
but it says Undefined variable: event
if you do not make use of the event variable you want to do:
self.onActionCombobox1(None)
This, set in the __init__ method of your class, will execute the method at class instantiation (not necessarily equivalent to program startup as in wxPython you can have windows/widgets that can be created dynamically at run time. You could call the method from the class before instantiating it but then method actions have not to be related with any widget state or behavior as they do not exist yet. Anyway, in that case maybe the method should be written better as an independent function).

Categories

Resources