button won't repeat commands tkinter [duplicate] - python

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 6 years ago.
I'm new to GUIs and just learning how to use Tkinter. I wrote a python program to put the students in my class into pairs for my seating charts. The program itself runs fine; the problem is the tkinter gui.
I've tried to make the button generate and display a new set of pairs each time. Instead, the GUI will display the first set of pairs as soon as I open it, without even pressing the button. The button does nothing. If I run it in console, I don't get any error messages or anything printed to console.
At Button commands in Tkinter I saw an answer to do with using lambda. When I tried it, the label will initially be blank. It will display the pairs when the button is pressed the first time, as expected, but on subsequent presses it just makes the label blank again.
I'm not sure what the problem is. Can you help me? Here is the code:
from Tkinter import *
from SeatingChart import *
root = Tk()
class App:
def __init__(self, master):
self.win = Frame(master)
self.win.pack()
self.d = Label(self.win, text = "", width=140)
self.d.pack()
self.b = Button(self.win, text="Pair Up!", command=self.display_pairs(roster))
self.b.pack()
def display_pairs(self, l):
self.d.config(text=pair(roster))
app = App(root)
mainloop()

When creating the button, the command that you supply is the result of the display_pairs method (which is None because it doesn't return anything) rather than a reference to the method.
Try:
class App:
def __init__(self, master):
self.win = Frame(master)
self.win.pack()
self.d = Label(self.win, text = "", width=140)
# Maybe display an initial roster?
# self.d = Label(self.win, text = pair(roster), width=140)
self.d.pack()
self.b = Button(self.win, text="Pair Up!", command=self.display_pairs)
self.b.pack()
def display_pairs(self):
self.d.config(text=pair(roster))

Related

Is there a way to make a label show in every window for tkinter without having to write out every single line of code over and over

I am wondering if there is a way, in tkinter or using any other python module, to make it so you keep a label or any other element in every window made by just using something like a function that makes the label within the window? I've tried this:
#Modules
import tkinter as tkin
#The initializer window
class Test:
def __init__(self):
#Initializes the main window
self.start = tkin.Tk()
self.start.title('Test')
self.label_thing()
#Makes a label
def label_thing(self):
self.label1 = tkin.Label(text='Not Button')
self.label1.pack()
I don't know if I made any errors or if this isn't a thing you can do but I'd also like to refrain from having the label localized to this window and having to remake the code for every window.
Let us assume you have a button that creates windows, you would pass this window as an argument to the function that creates the label, so like:
import tkinter as tk # Fixed weird import naming
class Test:
def __init__(self):
self.start = tk.Tk()
self.start.title('Test')
self.label_thing(self.start) # Label on the main window
tk.Button(self.start,text='Click me',command=self.create_win).pack()
self.start.mainloop()
def label_thing(self, master):
self.label1 = tk.Label(master, text='Not Button')
self.label1.pack()
def create_win(self):
new = tk.Toplevel()
self.label_thing(new) # Label on the new window
if __name__ == '__main__':
Test()
As you can see, as long as you press the button, new windows are created, and all those windows have the label on them, dynamically.

How to use Tk button? [duplicate]

This question already has answers here:
How to pass arguments to a Button command in Tkinter?
(18 answers)
Closed 3 years ago.
I'm a beginner in Python and I'm trying to build some GUI to understand.
I want to pass to a button a function that requies a parameter, but when I launch the script, it does not
work.
I'm attaching a python file.
from tkinter import *
from tkinter import messagebox
window = Tk()
window.title("Hello World")
window.geometry('350x200')
def clicked(msg):
messagebox.showinfo("Message",msg)
text = Entry(window,width=100)
text.grid(column = 1, row = 0)
btn = Button(window,text = "Click me",command = clicked(text.get()))
btn.grid(column=5, row=1)
window.mainloop()
The following fix is required for your file:
When you assign the command parameter, it wont wait till your click on button, it will pop out the message box right after your tkinter application execution. (Thats what i experienced when i executed your code)
You have to use lambda here
So you can fix this by:
btn.bind('<Button-1>',lambda event: clicked('Your Text')) # Button-1 stands for left mouse click
More on bind() method:
https://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
This is the final code:
from tkinter import *
from tkinter import messagebox
window = Tk()
window.title("Hello World")
window.geometry('350x200')
def clicked(msg):
messagebox.showinfo("Message",msg)
text = Entry(window,width=100)
text.grid(column = 1, row = 0)
btn = Button(window,text = "Click me")
btn.bind('<Button-1>',lambda event: clicked(text.get()))
btn.grid(column=5, row=1)
window.mainloop()
The command will be executed when the code is interpreted, to avoid that you can use lambda to pass an argument to the function
command = lambda : clicked(text.get()))
Or you can use partial which will return a callable object that behaves like a function when it is called.
from functools import partial
...
command = partial(clicked, text.get()))

How do you close a python - tkinter window, when the window object is encapsulated?

Ok, so this is from a larger project that I am working on, so I apologize if it looks messy.
The issue is that when I click the 'Exit Program' Button on the GUI, the window remains active.
I know that the button is working as when I hit the 'x' on the top right corner the window; the program closes, so the run variable has been set back to 0, which stops the code from looping.
My question is how do I get the window to be closed automatically when the exit button is clicked, because the root.destroy() method isn't doing it.
#imports
from tkinter import *
import random, pickle, shelve
#global vars
run = 0
class Window(Frame):
#the class that manages the UI window
def __init__(self, master, screen_type = 0):
"""Initilize the frame"""
super(Window, self).__init__(master)
self.grid()
if screen_type == 1:
self.log_in_screen()
def log_in_screen(self):
#Program Exit Button
self.exit = Button(self, text = " Exit Program ", command = self.end)
self.exit.grid(row = 3, column = 0, columnspan = 2, sticky = W)
def end(self):
global run, root
run = 0
root.destroy()
#Main Loop
def main():
global run, root
run = 1
while run != 0:
root = Tk()
root.title("Budget Manager - 0.6.1")
root.geometry("400x120")
screen = Window(root, screen_type = run)
root.mainloop()
store = shelve.open("store.dat", "c")
main()
store.close()
My question is how do I get the window to be closed automatically when
the exit button is clicked, because the root.destroy() method isn't
doing it.
The answer is: call destroy() on the root window. You say it isn't working, but the code you posted seems to work, and what destroy() is documented to do is exactly what you describe you want to have happen: it will destroy the window. Your code creates new toplevel windows in a loop, so maybe it only appears to not work since the old window id destroyed and the new window is created in the blink of an eye.
It seems like what you're really asking is "how can I make clicking on the "x" do the same as clicking on the "Exit program" button?". If that is the case, the answer is very straight-forward, even with your unconventional code that creates root windows in a loop.
To get the "x" button on the window frame to call a function instead of destroying the window, use the wm_protocol method with the "WM_DELETE_WINDOW" constant and the function you want it to call.
For example:
while run != 0:
root = Tk()
...
screen = Window(root, screen_type = run)
root.wm_protocol("WM_DELETE_WINDOW", screen.end)
...
root.mainloop()
you could do something like the below. I've used it in my own projects etcand it works.
Mywin =tkinter.Tk()
def exit():
Mywin.quit()
# etc.

How to pause a script with a Tkinter event?

I'm creating a simple class named Dialog. I only want it to return when init method is already finished.
from tkinter import *
class Dialog:
def __set_data(self):
self.data = self.entry_.get()
self.top.destroy()
def __init__(self, prompt_text = "Prompt:", submit_text = "OK", text_size = 5, button_size = 5, main_window = Tk()):
main_window.withdraw()
top = self.top = Toplevel(main_window)
Label(top, text=prompt_text).pack()
self.entry_ = Entry(top)
self.entry_.pack(padx = text_size)
button = Button(top, text = submit_text, command = self.__set_data)
button.pack(pady=button_size)
def get_data(self):
return self.data
data = 0
a = Dialog();
print (a.get_data())
If you run this code, you will get the output 0. I want to the output only show up after the user input. How can I do this?
Firstly, I don't think that you really want to postpone the __init__ method returning. If you do that, your code will never get to tk.mainloop(), and will never actually appear on screen.
Instead, what you want to do is be notified when the data in the Entry widget changes. This is a pretty common thing to do in GUI toolkits; the way tkinter handles it is with Events and Bindings. You can read about them generally here.
One way of performing your particular task (showing the data in self.entry once it has been changed by the user) might be to use the method shown in this question.
Alternatively, you could add a command to your submit button (see here) and read the value of the entry in that method.

Tkinter button command activates upon running program? [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 6 months ago.
I'm trying to make a build retrieval form, and seem to have issues with the buttons... I'm a novice at Python/tkinter GUI programming (and GUI programming in general) and borrowed the skeleton of a Hello World app, and sorta built off that.
In the code below, I've set the "command" option of my Browse button to call my class's internal get_dir() function when it's clicked. However, as soon as I attempt to run the app, the get_dir() function is called and I'm prompted to choose a directory. Any ideas why this happens, and what I can do to make it behave properly?
from Tkinter import *
import tkFont
from tkFileDialog import askdirectory
class App:
def __init__(self, master):
fontHead = tkFont.Font(family="Arial", size=10, weight=tkFont.BOLD)
fontBold = tkFont.Font(family="Arial", size=8, weight=tkFont.BOLD)
fontReg = tkFont.Font(family="Arial", size=8)
frameN = Frame(master)
frameN.grid(row=0,padx=5,pady=5)
frameXBH = Frame(frameN)
frameXBH.grid(row=0,columnspan=5,padx=5)
Canvas(frameXBH,borderwidth=0,relief="flat",height=1,width=20,background="#cccccc").grid(row=0)
Label(frameXBH, text="Xbox 360",font=fontBold,width=9).grid(row=0,column=1)
Canvas(frameXBH,borderwidth=0,relief="flat",height=1,width=440,background="#cccccc").grid(row=0,column=2,sticky="WE")
Label(frameN, text="Destination Path:",font=fontReg).grid(row=1,sticky="W")
xbPath = Entry(frameN,width=30,font=fontReg)
xbPath.grid(row=1,column=1,sticky="W")
xbBrowse = Button(frameN,text="Browse...",font=fontReg,command=self.get_dir(xbPath))
xbBrowse.grid(row=1,column=2,sticky="W")
xbRel = Checkbutton(frameN,text="Release",font=fontReg)
xbRel.grid(row=1,column=3,sticky="W")
xbShip = Checkbutton(frameN,text="Ship",font=fontReg)
xbShip.grid(row=1,column=4,sticky="W")
Canvas(frameN,borderwidth=1,relief="groove",width=550,height=0).grid(row=2,columnspan=5,pady=10)
# SAVE AND CANCEL
btnSave = Button(frameN,text="Save",width=10)
btnSave.grid(row=3,column=3,sticky="E")
btnCancel = Button(frameN,text="Cancel",width=10)
btnCancel.grid(row=3,column=4,sticky="W")
def get_dir(self,box):
tmp = askdirectory(mustexist=1,title="Please select a destination")
tmp = tmp.replace("/","\\")
box.delete(0,END)
box.insert(0,tmp)
root = Tk()
root.resizable(0,0)
app = App(root)
root.mainloop()
Make your event handler a lambda function, which calls your get_dir() with whatever arguments you want:
xbBrowse = Button(frameN, text="Browse...", font=fontReg, command=lambda : self.get_dir(xbPath))
In the above code:
xbBrowse = Button(frameN,text="Browse...",font=fontReg,command=self.get_dir(xbPath))
You are invoking the function already, you should be simply passing the function:
xbBrowse = Button(frameN,text="Browse...",font=fontReg,command=self.get_dir)
You need to pass a reference of your get_dir method
so change
xbBrowse = Button(frameN,text="Browse...",font=fontReg,command=self.get_dir(xbPath))
to
xbBrowse = Button(frameN,text="Browse...",font=fontReg, command=self.get_dir)
Then make your Entry widget an instance variable so that you can access it in your get_dir method.
e.g.
self.xbPath = Entry(frameN,width=30,font=fontReg)
Then your get_dir() method will look like:
def get_dir(self):
tmp = askdirectory(mustexist=1,title="Please select a destination")
tmp = tmp.replace("/","\\")
self.xbPath.delete(0,END)
self.xbPath.insert(0,tmp)

Categories

Resources