I have a small test Tkinter window with Labels and Entries in a file called "customer.py"
I created another file "button_test.py" with a super simple tkinter window with only one button to call "customer.py"
The button calls 'customer.py" with no problem but If I click the button again over andover. Keeps popping up the same window. I could probably add some conditions over there maybe but I would like to know if there is a better way to prevent that. I see it also happens with the "Tk TopLevel"
I thank you for your help and time Comrades.
customer.py
from tkinter import *
class OFFLINE():
def __init__(self,window):
self.win = window
self.win.title("Emails")
frame = LabelFrame(self.win, text = 'CUSTOMER INFORMATION')
frame.grid(column = 0, row = 0, )
Label(frame, text = "Case Number").grid(column = 0, row = 1)
self.Case_box = Entry(frame).grid(column = 1, row = 1)
Label(frame, text = "Customer Name").grid(column = 0, row = 2)
self.name_box = Entry(frame).grid(column = 1, row = 2)
Label(frame, text = "Phone number").grid(column = 0, row = 3)
self.phone_box = Entry(frame).grid(column = 1, row = 3)
Label(frame, text = "Email").grid(column = 0, row =4)
self.email_box = Entry(frame).grid(column =1, row = 4)
def main():
root = Tk()
application = OFFLINE(root)
root.mainloop()
if __name__ == '__main__':
main()
button_test.py
import customer
from tkinter import *
offline = customer
window = Tk()
button = Button(window, text = "Click Me", command =offline.main)
button.pack()
window.mainloop()
You can disable button
button['state'] = 'disabled'
and later enable it
button['state'] = 'normal'
Or you can use .grab_set() to make modal window and first window will not get key/mouse events.
Minimal working code
from tkinter import *
def set_disabled():
button1['state'] = 'disabled'
def set_normal():
button1['state'] = 'normal'
window = Tk()
button1 = Button(window, text = "Click Me", command=set_disabled)
button1.pack()
button2 = Button(window, text = "Next Me", command=set_normal)
button2.pack()
window.mainloop()
EDIT:
Example with second window.
It shows how to do it with Toplevel() instead od second Tk() and without second `mainloop()
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def close_window():
top_window.destroy()
button_open['state'] = 'normal'
def open_window():
global top_window # to keep value in external variable
global button_close # to keep value in external variable
button_open['state'] = 'disabled'
top_window = tk.Toplevel(window)
label = tk.Label(top_window, text="New Window")
label.pack()
button_close = tk.Button(top_window, text = "Close", command=close_window)
button_close.pack()
# --- main ---
window = tk.Tk()
button_open = tk.Button(window, text="Open", command=open_window)
button_open.pack()
window.mainloop()
EDIT:
Example with grab_set() to make window modal
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def open_window():
top_window = tk.Toplevel(window)
top_window.grab_set()
label = tk.Label(top_window, text="New Window")
label.pack()
button_close = tk.Button(top_window, text = "Close", command=top_window.destroy)
button_close.pack()
# --- main ---
window = tk.Tk()
button_open = tk.Button(window, text="Open", command=open_window)
button_open.pack()
window.mainloop()
PEP 8 -- Style Guid for Python Code
You can simulate singleton feature using class as below:
customer.py
from tkinter import *
__all__ = ['main']
class OFFLINE():
...
class _SingletonWin(Toplevel):
_instance = None
def __init__(self, master=None, *args, **kw):
super().__init__(master, *args, **kw)
self.form = OFFLINE(self)
self.protocol("WM_DELETE_WINDOW", self.on_destroy)
#classmethod
def on_destroy(cls):
if cls._instance:
cls._instance.destroy()
cls._instance = None
#classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
def main():
return _SingletonWin.get_instance()
Then whenever main() is called, only one instance of the toplevel will be shown.
Related
So basically i want to make this GUI where you can insert text and then hit the go button ad it would do the feature. (example: "Stopwatch" and then after you hit enter it would start a stopwatch).
import tkinter as tk
import math
import time
root = tk.Tk()
root.geometry()
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text = "Exit", command = root.destroy)
exit_button.place(x=1506, y=0)
main_entry = root.Entry(root, )
root.mainloop()
So basically I want the answer in main entry to be taken and do the action asked in the text insertion.
Here i wrote an example on how to use the Entry and the Button widgets in Tkitner:
from tkinter import *
from tkinter.messagebox import showerror
import random
class App(Tk):
def __init__(self):
super(App, self).__init__()
self.title('Get a random integer')
self.geometry('400x250')
Label(self, text='Get a random number from A to B').pack(pady=20)
self.a_value = Entry(self, width=10)
self.a_value.insert(END, 'A')
self.a_value.pack(pady=5)
self.b_value = Entry(self, width=10)
self.b_value.insert(END, 'B')
self.b_value.pack(pady=5)
self.btn = Button(self, text='Get Random', command=self.get_rand)
self.btn.pack(pady=5)
self.out_label = Label(self)
self.out_label.pack(pady=10)
self.bind('<Return>', self.get_rand)
def get_rand(self, event=None):
a = self.a_value.get()
b = self.b_value.get()
try:
a = int(a)
b = int(b)
self.out_label.configure(text=f'{random.randint(a, b)}')
self.update()
except Exception as error:
showerror(title='ERROR', message=f'{error}')
if __name__ == '__main__':
myapp = App()
myapp.mainloop()
I'm trying to create an app with Tkinter which requires the user to hit the button of the first window and then a new window will appear where they'll write their name.
But i when i try to get the name, i always end up with an empty string.
Here's my code:
from tkinter import *
class first_class(object):
def __init__(self, window):
self.window = window
b1 = Button(window, text = "first_get", command = self.get_value_2)
b1.grid(row = 0, column = 1)
def get_value_2(self):
sc = Tk()
second_class(sc)
sc.mainloop()
class second_class(object):
def __init__(self, window):
def get_value_1():
print(self.name.get())
self.window = window
self.name = StringVar()
self.e1 = Entry(window, textvariable = self.name)
self.e1.grid(row = 0, column = 0)
b1 = Button(window, text = "second_get", command = get_value_1)
b1.grid(row = 0, column = 1)
window = Tk()
first_class(window)
window.mainloop()
What should i do to get the name properly?
Generally speaking, you should avoid calling Tk() more than once within a tkinter application. It's also hardly ever necessary to call mainloop() more than once.
Your code with the changes indicated below shows how to do this. Note that I also renamed and reformatted a few things so it follows the recommendations in PEP 8 - Style Guide for Python Code more closely — which I highly recommend you read and start following.
import tkinter as tk
class FirstClass(object):
def __init__(self, window):
self.window = window
b1 = tk.Button(window, text="first_get", command=self.get_value_2)
b1.grid(row=0, column=1)
def get_value_2(self):
# sc = tk.Tk() # REMOVED
SecondClass(self.window) # CHANGED
# sc.mainloop() # REMOVED
class SecondClass(object):
def __init__(self, window):
self.window = window
self.name = tk.StringVar()
self.e1 = tk.Entry(window, textvariable=self.name)
self.e1.grid(row=0, column=0)
def get_value_1():
print('self.name.get():', self.name.get())
b1 = tk.Button(window, text="second_get", command=get_value_1)
b1.grid(row=0, column=1)
window = tk.Tk()
FirstClass(window)
window.mainloop()
I have a sequence of pop up windows. I intended to close the window once i have completed the desired task. I am using a "askokcancel" button to get users confirmation whether the activity has completed. The problem is, every time the user presses ok, the focus goes back to the main starting window and rest of the pop up windows goes to the background while staying active. I want to either close the pop up windows or keep the focus to the second last window. Below is my code:
import tkinter as tk
from tkinter import ttk, StringVar, messagebox
from tkinter.filedialog import askopenfilename
from mytest import *
from tkinter import *
class myclass:
def __init__(self, master):
self.master = master
self.frame1 = tk.Frame(self.master)
self.button1 = tk.Button(self.frame1, text = 'select me first', width = 25, command = self.buttonFunc)
self.button1.pack()
self.quitButton = tk.Button(self.frame1, text = 'Quit', width = 25, command = self.close_windows1)
self.quitButton.pack()
self.frame1.pack()
self.master.geometry("200x200+60+60")
def buttonFunc(self):
self.top = tk.Toplevel(self.master)
self.button2 = tk.Button(self.top,text="Select second",command=self.anotherButtonFunc)
self.button2.pack()
self.quitButton = tk.Button(self.top, text = 'Quit', width = 25, command = self.close_windows2)
self.quitButton.pack()
self.master.geometry("200x200+60+60")
def anotherButtonFunc(self):
self.top2 = tk.Toplevel(self.top)
self.newClass = myClassExt(self.top2)
def close_windows1(self):
self.master.destroy()
def close_windows2(self):
self.top.destroy()
class myClassExt():
def __init__(self, top2):
self.top3 = top2
self.frame2 = tk.Frame(self.top3)
self.button3 = tk.Button(self.frame2, text = 'select me third', width = 25, command = self.buttonFunc)
self.button3.pack()
self.quitButton = tk.Button(self.frame2, text = 'Quit', width = 25, command = self.close_windows4)
self.quitButton.pack()
self.frame2.pack()
self.top3.geometry("200x200+60+60")
def buttonFunc(self):
ok = messagebox.askokcancel(message='Press OK to Confirm?')
if not ok:
pass
else:
messagebox.showinfo("Success","Well done")
self.close_windows4()
def close_windows4(self):
self.top3.destroy()
if __name__ == "__main__":
root = tk.Tk()
myclass = myclass(root)
root.mainloop()
From this made up example, i somehow want to either close window number 2 after user presses OK or keep the focus on window 2 rather than window 1. Please guide
There is no way to close a message box, although you can easily make your own. You just have to make a new tkinter window, and set an image, title, and text, then add a close button, and return the tk window. I made a function like this myself, for this very reason. Here is the function:
def mymessage(title, text, spacing = 25, buttonText = "Close", image = None):
tk2 = Tk()
tk2.resizable(0, 0)
tk2.title(title)
if image != None:
image = Label(tk2, image = PhotoImage(file = image))
image.pack()
spacer = Frame(tk2, relief = FLAT, bd = 0, width = 200, height = 25)
spacer.pack()
label = Label(tk2, text = text)
label.pack()
button = Button(tk2, text = buttonText, width = 5, height = 1, command = tk2.destroy)
button.pack()
return tk2
After calling the function, it returns the tk window, for easy destruction.
I want to have two tkinter windows. A button should be in the first window, and a reaction text should be in the second window.
My questions:
Must the second window have no modal?
How do I make the second window movable?
How can I give information to second window via callback function?
Thanks in advance for answers and advice!
Here is some code that may help you:
from tkinter import *
class App:
def __init__(self):
self.window1 = Tk()
self.window2 = Toplevel()
self.button = Button(self.window1, bd = 5, text = "Click Me!", command = self.update)
self.button.pack()
self.label = Label(self.window2, bd = 5, text = "Button has not been clicked.")
self.label.pack()
def update(self):
self.label.config(text = "Button has been clicked!")
self.window2.update()
app = App()
Explanation:
The first line imports tkinter
In the next line, we create a class. At the bottom of the code, we create an object using that class. This is useful because when the object is created, the functions in the class are already defined, so the function definition can be after when it is called.
After we declare our class, in __init__, we write code that will run when an object is created from that class. The code creates two windows. One contains a button, and the other one contains a label. The button has a command parameter to run the class function, update.
In update, we change the label text and update the window.
I have not next questions. My problems solution is here:
import tkinter as tk
class ViewOnMoon(tk.Toplevel):
def __init__(self, parent = None, draw = None):
tk.Toplevel.__init__(self, parent)
self.transient(parent)
self.title('View')
self.minsize(height = 300, width = 300)
fr_canvas = tk.Frame(self)
fr_canvas.place(relx=0.23, rely=0.01, anchor="nw")
self.canv_w = 200
self.canv_h = 200
self.canvas = tk.Canvas(fr_canvas, bg='white', width = self.canv_w, height=self.canv_h)
self.canvas.grid(column = 0, row = 0)
return
class GuiMoonMove(tk.Frame):
def __init__(self, master):
mon_h = 600
mon_w = 1250
tk.Frame.__init__(self, master)
self.frame = tk.Frame(master, width=1000, height=200, bd=2)
self.master.title('Move')
self.master.minsize(height = mon_h, width = mon_w)
fr_canvas = tk.Frame(self.master)
fr_canvas.place(relx=0.23, rely=0.01, anchor="nw")
fr_button = tk.Frame(self.master)
fr_button.place(relx=0.02, rely=0.06, anchor="nw")
self.canv_h = 600
self.canv_w = 950
self.lbl_view = tk.BooleanVar()
chb_view_on_moon = tk.Checkbutton(fr_button, text="Pohled na Měsíc", variable = self.lbl_view, \
onvalue=True, offvalue=False,command = self.callback)
chb_view_on_moon.grid(column= 0, row= 4,pady = 10)
self.canvas = tk.Canvas(fr_canvas, bg='white', width = self.canv_w, height=self.canv_h)
self.canvas.grid(column = 0, row = 0)
def callback(self,*args):
if self.lbl_view.get()==True:
self.view_on_moon = ViewOnMoon(parent = self.master)
else:
self.vom.destroy()
if __name__=="__main__":
root = tk.Tk()
app = GuiMoonMove(master = root)
app.mainloop()
This is small Python button program. My problem was when I am clicking button always opening new window. I want one window execution.
from tkinter import *
import sys
def pressed():
root = Tk()
root.title('My Window2')
root.geometry('200x200')
button = Button(root,text = 'press2',command = pressed2)
button.pack(pady = 20, padx = 20)
def close():
quit()
def pressed1():
print('second window')
def pressed2():
root = Tk()
root.title('My Window3')
root.geometry('200x200')
button = Button(root,text = 'press3',command = pressed1)
button.pack(pady = 20, padx = 20)
button = Button(root,text = 'back',command = pressed)
button.pack(pady = 20, padx = 20)
root = Tk()
root.title('My Window')
root.geometry('200x200')
button = Button(root,text = 'press',command = pressed)
button2 = Button(root,text = 'Exit',command = close)
button.pack(pady = 20, padx = 20)
button2.pack(pady = 20, padx = 20)
mainloop()
I have not used Tkinter, but here is what looks like is happening.
1. on my win 7 python 2.6 it is Tkinter, not tkinter
2. when you use root = Tk() it is creating a new window; if you remove the root = Tk() from pressed() and pressed2() it uses the original window over again.
It's not clear what you want, but if you are trying to modify the text, and command associated with the button then you just need to configure those attributes.
Something like this should work. It can be modified to add new buttons instead of reusing the same button. I made the class inherit from Frame, but you could also choose to inherit from Tk. (Note: This is Python 3 code)
import tkinter
class ButtonPressWindow(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
master.title('My Window')
master.geometry('200x200')
self.button1 = tkinter.Button(self, text='press', command=self.pressed)
self.button2 = tkinter.Button(self, text='Exit', command=self.close)
self.button1.pack(pady=20, padx=20)
self.button2.pack(pady=20, padx=20)
def pressed(self):
self.master.title('My Window2')
self.master.geometry('200x200')
self.button1.configure(text='press2', command=self.pressed2)
def pressed2(self):
self.master.wm_title('My Window3')
self.master.geometry('200x200')
self.button1.configure(text='press3', command=self.pressed3)
def pressed3(self):
print("Second window")
def close(self):
quit()
root = tkinter.Tk()
btnWindow = ButtonPressWindow(root)
btnWindow.pack(fill='both', expand=True)
root.mainloop()