What is the difference between command and bind in tkinter? - python

I'm trying to make a button print a string when it's pressed and print another when it's released. I know about the command atribute and the bind method, but I would like to know if it's possible to accomplish it only using atributes or if I have to use methods. With this piece of code:
class motor:
def __init__(eleMesmo, eixo , valorZero):
eleMesmo.eixo = eixo
eleMesmo.zero = valorZero
def aumenta(self):
print(self.eixo + str(self.zero+5))
def diminui(self):
print(self.eixo + str(self.zero-5))
def para(self):
print(self.eixo + str(self.zero))
eixox = motor('x',90)
eixoy = motor('y',90)
class Interface:
def __init__(elemesmo, widget):
quadro = Frame(widget)
quadro.pack()
elemesmo.aumentarY = Button(quadro,text="Aumentar Y",height=10,width=20,command=eixoy.aumenta)
elemesmo.aumentarY.pack(side=TOP)
elemesmo.diminuirY = Button(quadro,text="Diminuir Y",height=10,width=20,command=eixoy.diminui)
I can call the method aumenta for object eixo y when button aumentarY is pressed. I would like to call the method para for object eixo y when button aumentarY is released. How I can do it?

All Event types are outlined here, you are looking for <Button-1> (click down on button 1 (left mouse button if you are right handed)) and <ButtonRelease-1> (release mouse button 1 (left button if you are right handed)).
Note I wouldn't use command if you bind both of these.
elemesmo.aumentarY = Button(quadro,text="Aumentar Y",height=10,width=20)
elemesmo.aumentarY.bind("<Button-1>",eixoy.aumenta)
elemesmo.aumentarY.bind("<ButtonRelease-1>",eixoy.para)
However you must know that when using bind the callback is called with an Event object, if you don't need it you can just add an optional and unused parameter to the callback:
def aumenta(self, event=None):
print(self.eixo + str(self.zero+5))
def diminui(self, event=None):
print(self.eixo + str(self.zero-5))
def para(self, event=None):
print(self.eixo + str(self.zero))

Both command and .bind method are used to add life and functionality to a button, using the tkinter module on Python.
Command Parameter:
tkinter.Button(frame, text="Exit", fg="green", bg="pink", command=master.destroy)
The above button would destroy the frame we the 'Exit' button is selected or clicked any how. Try using the tab key and pressing spacebar. You will notice that the button would work.
What if you don't want that?
What if you strictly want the user to click it using the left mouse button?
Note that, you can pass a simple zero-parameter method to the command parameter, which may or may not contain any event object.
Bind Method:
The bind method is used to add extra information/functionality to the button, the way it needs to be clicked, the specific button that needs to be used and so on. It looks something like this:
btn = Button(frame, text="Exit", fg="green", bg="pink")
btn.bind(sequence="<Button-1>", func=master.destroy)
This will work only when the Mouse Button-1 (Left-Mouse Button) is pressed. Some alternate versions to this are like:
btn.bind(sequence="<ButtonRelease-1>", func=master.destroy)
The above works when the Mouse Button-1 is pressed and released.
btn.bind(sequence="<Double-Button-1>", func=master.destroy)
Similarly, the above sequence works only when the Mouse Button-1 is Double Clicked.
Note that, in the bind method you cannot pass a simple zero-parameter method to the bind method, it must contain one event object as shown below.
def callback(event):
pass
For the entire list of sequences for bind method, refer this article.

Related

Does customtkinter CTkButton hover has event option?

I want to perform an action when a mouse hover event occurred on customtkinter ctkbutton hover. is it yet implemented?
Per the CTkButton source code, the on_enter method is bound to the <Enter> event. This method is predominantly focused on updating the button's appearance on hover. If you want to trigger an additional callback on hover, you'll have to add another binding to the button
def callback(event):
# put whatever you want to do 'on hover' into this function
print('Button hovered!')
button = CTkButton(parent, text='Button!')
# use '+' to avoid overwriting the existing binding
button.bind('<Enter>', callback, add='+')
button.pack()

How can we bind certain pixels of tkinter window or frame?

Is there anyway to bind certain coordinates of window or frame like when mouse enter these coordinates call this function etc. The reason is that i want to bind these coordinates for scrollbar, So I can hide scrollbar if user leaves that position.
You can use bind and <Enter>
Example:
from tkinter import Button, Tk
root = Tk()
def hover(event):
b.config(bg="blue")
def leave(event):
b.config(bg="white")
b = Button(root, text="Click me!")
b.pack(pady=20)
b.bind("<Enter>", hover)
b.bind("<Leave>", leave)
root.mainloop()
For more bindings, you can refer this:
https://www.geeksforgeeks.org/python-binding-function-in-tkinter/
No, you cannot bind to specific pixels. However, you can simulate that by binding to all mouse movement (eg: <Motion>). In the bound function, you can then determine if the mouse is over whatever region you want to have active.

WASD input in python

In python, how can I receive keyboard input. I'm well aware of console input with input("...") but I'm more concerned with receiving keyboard input while the console window is not active. For example if I created an instance of a Tkinter screen how could I check to see if let's say "w" was pressed. Then if the statement returned true i could move an object accordingly.
The way you do this with a GUI toolkit like tkinter is to create a binding. Bindings say "when this widget has focus and the user presses key X, call this function".
There are many ways to accomplish this. You can, for example, create a distinct binding for each character. Or, you could create a single binding that fires for any character. With these bindings, you can have them each call a unique function, or you can have all the bindings call a single function. And finally, you can put the binding on a single widget, or you can put the binding on all widgets. It all depends on exactly what you are trying to accomplish.
In a simple case where you only want to detect four keys, four bindings (one for each key) calling a single function makes perhaps the most sense. For example, in python 2.x it would look something like this:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, width=400, height=400)
self.label = tk.Label(self, text="last key pressed: ", width=20)
self.label.pack(fill="both", padx=100, pady=100)
self.label.bind("<w>", self.on_wasd)
self.label.bind("<a>", self.on_wasd)
self.label.bind("<s>", self.on_wasd)
self.label.bind("<d>", self.on_wasd)
# give keyboard focus to the label by default, and whenever
# the user clicks on it
self.label.focus_set()
self.label.bind("<1>", lambda event: self.label.focus_set())
def on_wasd(self, event):
self.label.configure(text="last key pressed: " + event.keysym);
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()

Tkinter binding mouse double click

I'm trying to bind my mouse double click to a function which for now just prints the current selection in a Tkinter list box. To be clear the function should only print when the user double clicks on one of the items of a Tkinter list box. What event binding should I use?
You can bind to <Double-Button-1>:
widget.bind('<Double-Button-1>', handler)
There is also <Button-1> for normal mouse clicks and <Triple-Button-1> for a triple mouse click.
For more information on bindings in Tkinter, see Events and Bindings.
You have to realize that there is a hierarchy to all widgets, and this means that for each widget you click, multiple bindings are possible. If you don't override the default action, each hierarchy's default handler gets called, starting at the lowest level (such as your Listbox) and going all the way up to the Tk() or Toplevel() widget. For you, since you want to print only when a listbox item is clicked, you can bind to the listbox widget, as follows:
listboxWidget.bind('<Double-Button-1>', listboxWidget_leftclick_handler)
Then, when you enter the def listboxWidget_leftclick_handler(event) function, you don't have to check the event.widget value to see if it's the name of your Listbox widget. But you could also check at a higher level (bind a handler to a higher-level widget) and check event.widget to see which widget was clicked.
Also note that the only way to prevent the entire hierarchy of event handlers from triggering is by using a return 'break' from your custom handler, but you usually only need to do this if later handlers corrupt what your custom handler has done.
Additional info about default handlers
The other part which I left out is that there is also a "default" handler for most events. If you bind your own handler, once it's finished, if you don't return 'break', the default handler will be called next.
For example, say you want to make your own Entry box into a password entry. By default, when you type alphanumeric chars when the Entry has focus (which means it's getting input from the keyboard), the chars will appear in the Entry. You can bind:
myEntry.bind('<KeyPress>', passworder)
where passworder is your custom handler which grabs the event holding your inputted char and then outputs an asterisk into the Entry instead. But, if you don't use a return "break" at the end of your handler, the Entry widget is still going to see that char that you didn't want shown, because once your handler is done inserting the asterisk, the default handler will simply insert the typed char (like it would normally). But, if you do the return 'break', the default handler won't get called, and the typed char(s) won't appear in the Entry.
As an add-on. In order to distinguish action between a single click and a double click, delay the call to mouse action for a brief period to allow for the double click flag to be set. See below example:
from tkinter import *
def mouse_click(event):
''' delay mouse action to allow for double click to occur
'''
aw.after(300, mouse_action, event)
def double_click(event):
''' set the double click status flag
'''
global double_click_flag
double_click_flag = True
def mouse_action(event):
global double_click_flag
if double_click_flag:
print('double mouse click event')
double_click_flag = False
else:
print('single mouse click event')
root = Tk()
aw = Canvas(root, width=200, height=100, bg='grey')
aw.place(x=0, y=0)
double_click_flag = False
aw.bind('<Button-1>', mouse_click) # bind left mouse click
aw.bind('<Double-1>', double_click) # bind double left clicks
aw.mainloop()

Python Tkinter: Changing other button's text from event handler of one button

I have the following problem when using tkinter to create a very simple window containing a matrix of buttons: When one of the buttons is clicked, the event handler changes the text of that button using the configure method on the button widget. This works. But I also want to change the text in one of the other buttons, which does not work. The method I use is that on creating the button, I store the object returned by the Button method before I use the grid geometry manager to place it. This object looks like ".123456789L" when printed and seems to be a pointer to the widget. I also use configure on this to change the button text. But somehow it seems to be wrong, because it works sometimes, and most of the times not. There's unfortunately no error message, just nothing happens when calling configure. I checked and it seems to be the correct pointer to the widget. Do I have to use a special way to affect a widget other that the one that called the event handler? These are the relevant parts of the code:
# CREATING THE BUTTONS:
buttons={} # global
for i in range(3):
for j in range(3):
button = Tkinter.Button(self,text='foo')
buttons[button]=(i,j)
button.grid(column=j,row=i)
button.bind( "<Button-1>", self.OnButtonClick )
# CHANGING BUTTONS:
def find_button(i,j):
"""Return the pointer to the other button to be changed when a button has been clicked."""
for button,key in buttons.items():
if key==(i,j): return button
def OnButtonClick(self,event):
print "You clicked the button",buttons[event.widget]
i,j=buttons[event.widget]
old_button=find_button(i,j) # This is simplified, I don't actually pass i,j, but other values. But I checked this and it returns the reference to the correct button. But this simplified version works the same way, just assume a different button that the one pressed would be returned.
old_button.configure(text = 'blabla') # THIS DOES NOT WORK
event.widget.configure(text = 'something') # THIS WORKS
I have the same problem and i solve it with:
buttons[button]=(i,j,button)
and in the function OnButtonClicK:
i,j,old_button=buttons[event.widget]
old_button.configure(text = 'blabla') # THIS DOES NOT WORK

Categories

Resources