Why is Tkinter not displaying Button? - python

import Tkinter as ass
root = ass.Tk()
frame = ass.Frame(root)
button1 = ass.Button(frame, command=button1(), text='Kushagra', width=50, height=40)
button1.pack(side=ass.LEFT)
root.mainloop()
button1() is a function I made which i don't think is relevant. After I run this all I get is a blank window. How do I fix this?

You didn't pack the frame widget after creating the frame. The below is the edited code
import tkinter as ass
root = ass.Tk()
frame = ass.Frame(root)
frame.pack()
button1 = ass.Button(frame, text="QUIT")
button1.pack(side=ass.LEFT)
root.mainloop()

You have to pack the frame if you want it to be displayed. This will let the button to be shown but the function button1() won't work as you want because it would be called when it is given to the Button as a command, As you have used parenthesis () after giving it to the button as a command. You just need to remove those parentheses.
Like this:
import tkinter as ass
def button1():
return
root = ass.Tk()
frame = ass.Frame(root)
frame.pack()
button1 = ass.Button(frame, command=button1, text='Kushagra', width=50, height=40)
button1.pack(side=ass.LEFT)
root.mainloop()
And if you need to pass arguments to any function then you should use lambda before giving it as a command to any Button.
Like this:
import tkinter as ass
def test(a):
print(a)
root = ass.Tk()
frame = ass.Frame(root)
frame.pack()
button1 = ass.Button(frame, command=lambda: test(1), text='Kushagra', width=50, height=40)
button1.pack(side=ass.LEFT)
root.mainloop()

Related

tkinter get widget that event got called by

Minimal reproducable Example
from tkinter import *
def test(event):
print(event.widget)
window = Tk()
window.geometry("600x600")
window.bind("<Motion>", test)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Motion>", test)
window.mainloop()
I want to call the function "test" from different widgets when i move over them. Instead of that, when i hover over the frame, both the window and the frame print that im hovering over the frame, which is not the behaviour i need. Can someone help me achieve the right behaviour?
I think your confusion is in the moment of interpreting when the mouse pointer entered the widget or left the widget. Instead of Motion let's use for example Leave and Enter events to better understand what happens.
I have taken the liberty of including some labels that show which widget we enter and left at each moment.
from tkinter import *
def test_enter(event):
enter.set(event.widget)
def test_left(event):
left.set(event.widget)
window = Tk()
window.geometry("300x300")
window.bind("<Enter>", test_enter)
window.bind("<Leave>", test_left)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Enter>", test_enter)
frame.bind("<Leave>", test_left)
label1 = Label(frame, text="Enter")
label1.place(relx=0.1, rely=0.4, x= 0.2, y=0.2)
enter = StringVar()
label_enter = Label(frame, textvariable=enter)
label_enter.place(relx=0.3, rely=0.4, x= 0.6, y=0.2)
label2 = Label(frame, text="Leave")
label2.place(relx=0.1, rely=0.6, x= 0.2, y=0.2)
left = StringVar()
label_left = Label(frame, textvariable=left)
label_left.place(relx=0.3, rely=0.6, x= 0.6, y=0.2)
window.mainloop()
Remember that the Frame is inside the Window. I mean that when you enter the Window you have not left root Window, you will continue to be in Window. Or if you enter inside a Label you have not left the Frame.
You could use lambda to pass the widget when the function is run
def test(event, widget):
print(widget)
window = Tk()
window.geometry("600x600")
window.bind("<Motion>", test)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Motion>", lambda: test(frame))
window.mainloop()
You just need to change two lines
def test(event, widget):
print(widget)
and
frame.bind("<Motion>", lambda: test(frame))

simple Tkinter program - window vanishes after clicking button - maintop problem?

Coders,
I guess I have a newbie question: my windows disappears when I click on a button. If I put in root.mainloop() as last line in the buttonClicked-function, then the program is fine - but it looks not right...what is wrong here?
import tkinter as tk
def buttonClicked(event):
print(tf1.get())
tf1Content.set("button clicked")
# root.mainloop() ... would work
root = tk.Tk()
frame = tk.Frame(root, relief="ridge", borderwidth=2)
frame.pack(fill="both",expand=1)
label = tk.Label(frame, text="Input:")
label.pack(expand=1)
tf1Content = tk.StringVar()
tf1 = tk.Entry(frame, text="input here", textvariable=tf1Content)
tf1.pack(expand=1)
bOk = tk.Button(frame,text="OK",command=root.destroy)
bOk.bind("<Button-1>", buttonClicked)
bOk.widget = "bOK"
bOk.pack(side="bottom")
tf1.focus()
root.mainloop()
It turns out that you just copied this line:
bOk = tk.Button(frame,text="OK",command=root.destroy)
which binds a call to root.destroy() to the button press.
The fix is to just remove the command parameter:
bOk = tk.Button(frame,text="OK")

How do I destroy specific button in the loop when clicked?

I am trying to create a 10*10 board of buttons, which when clicked, the clicked button is destroyed and only that one. However, I don't know how to specify which button has been clicked.
from tkinter import *
root = Tk()
root.title("Board")
def buttonClick():
button.destroy()
for i in range(10):
for j in range(10):
button = Button(root, text="", padx=20, pady=10, command=buttonClick)
button.grid(row=i+1, column=j+1)
root.mainloop()
You have to create function which gets widget/button as argument and uses it with destroy()
def buttonClick(widget):
widget.destroy()
And first you have to create Button without command=
button = tk.Button(root, text="", padx=20, pady=10)
and later you can use this button as argument in command=.
button["command"] = lambda widget=button:buttonClick(widget)
It needs to use lambda to assign function with argument.
Because you create many buttons in loop so it also needs to use widget=button in lambda to create unique variable with value from button for every command. If you don't use it then all commands will use reference to the same (last) button - and click on every button will destroy only last button.
Full working code
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def buttonClick(widget):
widget.destroy()
# --- main ---
root = tk.Tk()
root.title("Board")
for i in range(10):
for j in range(10):
button = tk.Button(root, text="x", padx=20, pady=10)
button["command"] = lambda widget=button:buttonClick(widget)
button.grid(row=i+1, column=j+1)
root.mainloop()
PEP 8 -- Style Guide for Python Code
This can be easily accomplished with a custom class if you're alright with that:
from tkinter import Button, Tk
root = Tk()
root.title("Board")
class Self_Destruct_Button(Button):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.configure(command=self.button_click)
def button_click(self):
self.destroy()
for i in range(10):
for j in range(10):
button = Self_Destruct_Button(root, text="", padx=20, pady=10)
button.grid(row=i + 1, column=j + 1)
root.mainloop()
So the custom class just assigns the command to a button_click method, which destroys the button.
As a side note, I also removed the wildcard import as that's not best practice.
Let me know if this works for you

Tkinter : Button in frame not visible

I'm trying to implement a TicTacToe program. I am an absolute beginner in python. After viewing many tutorials and reading a few books, I have understood the basics of Python. I'm trying to get the buttons to display in a frame, but all I get is a blank window.
link for image of the resultant window
This is the code I have so far:
from Tkinter import *
class Buttons(object):
def __init__(self,master):
frame = Frame(master)
frame.pack()
self.button1= Button(frame,text="1",height=4,width=8,command=self.move)
self.button1.pack(side=LEFT)
self.button2= Button(frame,text="2",height=4,width=8,command=self.move)
self.button2.pack(side=LEFT)
self.button3= Button(frame,text="3",height=4,width=8,command=self.move)
self.button3.pack(side=LEFT)
root = Tk()
root=mainloop()
You defined your Buttons class but you didn't create an instance of that class, so no buttons were actually constructed. Also, you had a typo / syntax error:
root=mainloop()
should be
root.mainloop()
Also, you didn't define the move callback method.
Here's a repaired version of your code:
from Tkinter import *
class Buttons(object):
def __init__(self,master):
frame = Frame(master)
frame.pack()
self.button1 = Button(frame, text="1", height=4, width=8, command=self.move)
self.button1.pack(side=LEFT)
self.button2 = Button(frame, text="2", height=4, width=8, command=self.move)
self.button2.pack(side=LEFT)
self.button3 = Button(frame, text="3", height=4, width=8, command=self.move)
self.button3.pack(side=LEFT)
def move(self):
print "click!"
root = Tk()
Buttons(root)
root.mainloop()
However, this still has a problem: The move method has no way of knowing which button called it. Here's one way to fix that. I've also changed
from Tkinter import *
to
import tkinter as tk
It's not a good idea to use "star" imports. They make code harder to read and they pollute your namespace with all the names defined in the imported module (that's 175 names in the case of Tkinter), which can lead to name collisions.
import Tkinter as tk
class Buttons(object):
def __init__(self,master):
frame = tk.Frame(master)
frame.pack()
self.buttons = []
for i in range(1, 4):
button = tk.Button(
frame, text=i, height=4, width=8,
command=lambda n=i:self.move(n)
)
button.pack(side=tk.LEFT)
self.buttons.append(button)
def move(self, n):
print "click", n
root = tk.Tk()
Buttons(root)
root.mainloop()
Okay the problem was I needed to add a variable at the end of the code. Something like b=Buttons(root). It's working now.

Tkinter Entry widget requires two events to update

I've been trying to develop a small gui to calculate some totals with weighting etc. While trying to get a total to update real-time with a changing entry, I noticed it took two events to update; This is a simplified version of my code that shows the problem:
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
entry=Entry(frame)
entry.pack()
label=Label(frame,text="entry:")
label.pack()
def updatelabel(event):
label=Label(frame,text="entry:"+entry.get())
label.pack()
print "called"
entry.bind("<Key>", updatelabel)
root.mainloop()
When you input into the field the function calls, but does not update to what was typed until the next character is typed. How would I go about getting the label to update to what is in the field at the time?
You don't really need to explicitly process events and use callback functions to accomplish what you want. In other words it's possible to get Tkinter to do it for you automatically using a StringVar().
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
entry_var = StringVar()
entry_var.set('')
entry = Entry(frame, textvariable=entry_var)
entry.pack()
label = Label(frame, text='entry: ')
label.pack(side=LEFT)
contents = Label(frame, textvariable=entry_var)
contents.pack(side=LEFT)
entry.focus_set() # force initial keyboard focus to be on entry widget
root.mainloop()
Instead of using entry.bind("<Key>", update label), I used the root window instead: root.bind("<Key>", update label). This did the trick, however it is important to realize that the function updatelabel() will be called every time a key is pressed in your tkinter window. This could cause some problems if you have more than one entry box updating labels.
Here is the code I wrote with a few modifications:
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
update_label = StringVar() # Made a StringVar so you don't get new labels every time a key is pressed.
update_label.set("entry:")
entry=Entry(frame)
entry.pack()
label=Label(frame,textvariable=update_label) # Used textvariable= instead of text=
label.pack()
def updatelabel(event):
update_label.set("entry:" + entry.get()) # Setting the variable used in textvariable=
print "called"
root.bind("<Key>", updatelabel) # Changed entry.bind to root.bind
root.mainloop()
No it doesn't require two entries to be called, it is called on the first entry. The key bindings are on the Entry widgets to avoid the problems that a binding to the root will create if you have more than one entry widget.
import tkinter as tk
class SmallApp(tk.Frame):
def __init__(self, master = None):
tk.Frame.__init__(self, master)
self.master = master
self.pack()
self.entry = tk.Entry(self)
self.entry.pack()
self.var = "entry:"
self.label = tk.Label(text = self.var)
self.label.pack()
self.entry.bind("<Key>", self.updatelabel)
def updatelabel(self, event):
self.var += event.char
self.label.configure(text=self.var)
root = tk.Tk()
app = SmallApp(root)
app.mainloop()

Categories