Re-binding “select all” in Entry widget - python

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.

Related

Tkinter: How do I properly set parameters of extended Button class?

I am experimenting with creating a customer relationship management program using tkinter and python and would like to have buttons generated based on tables in the database.
The idea is that there is a button for each table in the database, so that the table can be viewed and edited if needed.
I want to have each button look the same and, when clicked, generate a list of table entries into the main frame of my program. To do this, I want to extend the Button() class so that I can keep some attributes concurrent while also defining the display_items function:
class TabButton(Button):
def __init__(self, *args, **kwargs):
super().__init__(Button)
self['bg'] = '#a1a1a1'
self['font'] = ('Agency', 24)
def display_items(self, tab):
pass
#mycursor.execute('SELECT * FROM (%s)', tab)
This last line (above) is what selects data from the correct table in my database - I have commented it out while I figure out the rest of the class. I know what *args and **kwargs do, but I'm not sure what purpose they have in this __init__ function (I'm not very familiar with classes and copied this class from another Stack Overflow post).
To generate the buttons, I referenced a dict instance and assigned each key to a button:
tabs = {
'Table1': '',
'Table2': '',
'Table3': '',
}
for tab in tabs:
row = 0
tabs[tab] = TabButton(side_frame, command=lambda: TabButton.display_items(tab))
tabs[tab].grid(row=row, column=0)
row += 1
The problem is, when I run the program I get this error:
AttributeError: type object 'Button' has no attribute 'tk'
Any and all guidance is welcome!
If you notice any other mistakes in my code, could you please point them out? I'm very new to programming and it will save me making another post on Stack Overflow. :p
Thanks,
J
Super returns a temporary object of that class and let you access its content. Super itself dosent accept any arguments.
Also see the prupose of self in that context.
self represents the instance of the class
Often, the first argument of a method is called self. This is nothing
more than a convention: the name self has absolutely no special
meaning to Python. Note, however, that by not following the convention
your code may be less readable to other Python programmers
Another issue is your use of lambda. Your argument tab will be overwritten (if it isnt stored) by each iteration of your loop. Another issue that you might not intent to use the class for this method you rather want to be calles by the instance, therefor I added the argument self to your method and changed your lambda to make use of the instance.
import tkinter as tk
tabs = {'Table1': '',
'Table2': '',
'Table3': '',
}
root=tk.Tk()
class TabButton(tk.Button):
def __init__(self,master, *args, **kwargs):
#self is a reference to the instance of that object
super().__init__(master)#super dosent need a reference
self['bg'] = kwargs.get('bg','#a1a1a1')
self['font'] = kwargs.get('font',('Agency', 24))
def display_items(self,item):
print(f'{item} to show')
for tab in tabs:
b = TabButton(root) #returns a reference to that object
b.configure(command=lambda btn=b, argument=tab:btn.display_items(argument))
b.pack()
root.mainloop()

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.

Getting tkinter.Widget bindings

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

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.

how to update a wxlistbox from a different class?

i have a wxlistbox in a class and i want to update the data inside the listbox from a different class.Is i possible to reload the class while leave the control from another class?if yes ,how?
eg:
i have two classes,Class A and Class B.In class A there is a wxlistbox.while starting the program class A initilise the wxlistbox and bind some values.when a button inside class A clicked it call another frame class B.while close the frame B the wxlistbox inside class A should update.
My question is how to refresh listbox while close the frame B?
I would use the SetItems() method, which according to the docs does the following: "Clear and set the strings in the control from a list".
Edit: myListCtrl.SetItems(ListOfStrings)
That will replace all the items in the control with whatever is in the list.

Categories

Resources