I am trying to write tkinter code that calls a function either when a button is clicked or when enter is clicked when the button is in focus. I have the following code:
import tkinter as tk
m = tk.Tk(className="My window")
def callback():
print("Ice cream weather")
butt = tk.Button(m, text="My button", width=25, command=callback)
butt.grid()
butt.focus_set()
butt.bind('<Return>', callback)
m.mainloop()
But when I run it and press Enter, I get the following error:
Traceback (most recent call last):
File "C:\Users\chiller\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: callback() takes 0 positional arguments but 1 was given
I found a solution, which I posted below, but I am wondering if there is a simpler or neater fix.
A way to solve this is to set the function up to take in a dummy parameter, and set a default value for when it isn't passed (i.e. for button click, which passes 0 arguments). This is just changing the line
def callback():
To
def callback(pointless=None):
This gives the extra parameter from pressing Enter a place to go, while not requiring it for a button push.
Related
Hello I am working on a screenshot related python project using tkinter.
In my program I have a second window opened by a button press code below.
#Opens the second window
def open_win2():
global sec_window
sec_window = Toplevel()
sec_window.config(height = 1800,width = 1800, bg = "chocolate1")
sec_picture_box = Label(sec_window,height=800, width=800, image=mainview)
sec_picture_box.place(x=800, y=100)
I want to create a function that when called will create a button in the second window.
Is this remotely possible. I have tried to do the most simple thing I could think of to test if it can be done (Open a lable when called) the code for the function is which is the command of a button on the root window
def create_secondwindow_button():
screenshot_snap = Label(text = "dog",)
screenshot_snap.grid(sec_window,column = 1, row = 1)
I just get the error message
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Link\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/Users/Link/PycharmProjects/Helloworld/main.py", line 67, in create_secondwindow_button
screenshot_snap.grid(sec_window,column = 1, row = 1)
File "C:\Users\Link\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 2226, in grid_configure
+ self._options(cnf, kw))
_tkinter.TclError: bad option "-bd": must be -column, -columnspan, -in, -ipadx, -ipady, -padx, -pady, -row, -rowspan, or -sticky
Process finished with exit code 0
If you cant do this do you have to imbed your function within the function that opens the second window?
Thanks a bunch for any help!
This is how the function should be:
def create_secondwindow_button():
screenshot_snap = Label(sec_window, text="dog")
screenshot_snap.grid(column=1, row=1)
Also there is no space between kwarg arguments as You can see in my code (per PEP 8 at least).
Also also if You wanted to create a button, it should be:
def create_secondwindow_button():
screenshot_snap = Button(sec_window, text="dog")
screenshot_snap.grid(column=1, row=1)
And just in case You do, don't do this:
from tkinter import *
It is bad practice in general and You should either import what you need:
from tkinter import Tk, Label, Button
Or import the module like this
import tkinter
or
import tkinter as tk
(for example You can use as as You need for example You might as well say as kinter or sth)
In such case You would need to refer like this:
tk.Button
tk.Label
And so on...
I am trying to create a popup menu that opens only when right-clicked inside of certain widgets (Text and Entry, in this case) but nowhere else
inside the root window.
When a user right-clicks inside one of the widgets and selects "copy", the text selection inside that widget
should be copied to the clipboard.
As is, the code below only works when explicitly referring to a certain widget but I want to generalize the copyToClipboard function
to copy the text selection from the widget that the user right-clicked inside.
Instead, running the commented out lines from the code below gives the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\...\...\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
TypeError: <lambda>() missing 1 required positional argument: 'e'
How do I access the appropriate (right-clicked) widget within the copyToClipboard function?
def copyToClipboard():
#def copyToClipboard(event):
#value = event.widget.get(SEL_FIRST,SEL_LAST)
value = inputText.get(SEL_FIRST,SEL_LAST)
pyperclip.copy(value)
print(value)
def showMenu(event):
popup.post(event.x_root, event.y_root)
inputEntry = ttk.Entry(root)
inputText = Text(root)
popup = Menu(root)
popup.add_command(label="Copy", command=copyToClipboard)
#popup.add_command(label="Copy", command=lambda e: copyToClipboard(e))
inputText.bind("<Button-3>", showMenu)
inputEntry.bind("<Button-3>", showMenu)
inputText.pack()
inputEntry.pack()
mainloop()
I've added a solution below. Storing event.widget as a global variable seemed to help as per acw's suggestion. I got rid of pyperclip because it kept giving me chinese chars and other random chars when mixing clicking-to-copy with Ctrl-V.
EDIT: It is worth noting that the Entry widget doesn't seem to handle line breaks well when they are pasted with Ctrl-V into the entry widget. Unfortunately, I haven't found an effective way to override the hotkey's default paste command to remove the line breaks prior to pasting.
from tkinter import *
from tkinter import ttk
root = Tk()
def copyToClipboard():
val = clickedWidget.selection_get()
root.clipboard_clear()
root.clipboard_append(val)
def showMenu(event):
global clickedWidget
clickedWidget = event.widget
popup.post(event.x_root, event.y_root)
inputEntry = ttk.Entry(root)
inputText = Text(root)
popup = Menu(root)
popup.add_command(label="Copy", command=copyToClipboard)
inputText.bind("<Button-3>", showMenu)
inputEntry.bind("<Button-3>", showMenu)
inputText.pack()
inputEntry.pack()
mainloop()
I am working with Tkinter in Python 3.5 and I encounter a weird problem.
I used the tkinterbook about events and bindings to write this simple example:
from tkinter import *
root = Tk()
frame = Frame(root, width=100, height=100)
def callback(event):
print("clicked at", event.x, event.y)
# frame.unbind("<Button-1>", callback)
frame.bind("<Button-1>", callback)
frame.pack()
root.mainloop()
It works fine, but if I try to unbind the callback (just uncomment the line), it fails with the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Delgan\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:\Users\Delgan\Desktop\Test\test.py", line 9, in callback
frame.unbind("<Button-1>", callback)
File "C:\Users\Delgan\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 1105, in unbind
self.deletecommand(funcid)
File "C:\Users\Delgan\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 441, in deletecommand
self.tk.deletecommand(name)
TypeError: deletecommand() argument must be str, not function
This is not clear, I am not sure if it is a bug in tkinter or if I am doing something wrong.
frame.unbind("<Button-1>") works fine but I would like to remove this exact callback instead of a global remove.
The second argument to unbind is a 'funcid', not a function. help(root.unbind) returns
unbind(sequence, funcid=None) method of tkinter.Tk instance.
Unbind for this widget for event SEQUENCE the function identified with FUNCID.
Many tk functions return tk object ids that can be arguments for other funtions, and bind is one of them.
>>> i = root.bind('<Button-1>', int)
>>> i
'1733092354312int'
>>> root.unbind('<Button-1>', i) # Specific binding removed.
Buried in the output from help(root.bind) is this: "Bind will return an identifier to allow deletion of the bound function with unbind without memory leak."
Hi I am using Python27 on Window7 OS, i am trying to create a Tk GUI with button, when the button is press a file directory will appear. But the following code won't do anything. Did i miss out something?
import webbrowser
import Tkinter as Tk
def action(self):
webbrowser.open ('C:\AgmPlots')
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command= lambda: action())
You've got three big problems.
First, you never start the GUI. You need something like win.mainloop() at the end to actually do anything.
Second, your button isn't actually laid out within the frame, so you won't see it. You need something like button.pack().
Finally, your command is a function that calls action(), with no arguments. But you've defined it to require a parameter. So, all that will happen when you click it is that Tk will log a traceback that looks like this:
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1470, in __call__
return self.func(*args)
File "tkt.py", line 8, in <lambda>
button = Tk.Button(master=frame, text='press', command= lambda: action())
TypeError: action() takes exactly 1 argument (0 given)
To fix that, either don't add the unnecessary self parameter to action (this is a function, not a method), or explicitly pass some dummy to match it in your lambda.
While we're at it, lambda: action() does exactly the same thing as action itself, except more verbose, harder to read, and slower. You should never use unescaped backslashes in non-raw string literals. And we might as well remove the stray spaces and PEP8-ify everything to make it consistent.
So, putting it all together:
import webbrowser
import Tkinter as Tk
def action():
webbrowser.open(r'C:\AgmPlots')
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command=action)
button.pack()
win.mainloop()
I'm looking at the example codes online, seems like I'm doing exactly like them. But the event seems to load as soon as the ui loads. What am I doing wrong?
From the code below, the click function doesn't load right when ui is loaded. But when I click the button, it throws:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
TypeError: clicky() takes no arguments (1 given)
class LogIn:
def __init__(self):
self.root = Tk();
self.root.title("480 - Chat Project Login");
self.root.geometry("275x125");
self.username = Label(self.root, text="Username: ");
self.username.pack(side=LEFT);
self.username.place(x=40, y=20);
self.u_entry = Entry(self.root, width=20);
self.u_entry.pack(side=RIGHT, ipady=4, ipadx=4);
self.u_entry.place(x=110, y=20);
self.password= Label(self.root, text="Password: ");
self.password.pack(side=LEFT);
self.password.place(x=40, y=50);
self.p_entry = Entry(self.root, width=20);
self.p_entry.pack(side=RIGHT, ipady=4, ipadx=4);
self.p_entry.place(x=110, y=50);
self.button = Button(text="Send", width=8);
self.button.pack(side=RIGHT, ipady=4, ipadx=4);
self.button.place(x=168, y=80);
self.button.bind("<Button-1>", clicky);
self.root.mainloop();
def clicky():
print "hello";
if __name__ == "__main__":
LogIn();
# Client();
You need self.button = Button(text="Send",width=8,command=clicky).
There's a difference between callbacks registered via command and callbacks registered via bind. With command, the callback doesn't get passed any additional arguments. With bind, the callback gets passed an event object.
Also, in case it wasn't clear, note that command is specific to Button objects whereas bind can be applied to any Tkinter widget.