Tkinter: messagebox doesn`t work right. (get two windows) - python

I am using python 3.
If I opan an error messagebox, i get two frames, one is emty and one is the error-window. That is my code:
from tkinter import messagebox
messagebox.showwarning('warning', 'warning')

Everything works correctly in your example. The empty window is the main window of Tk. It is always open when you start any Tk program. You can minimize it if you want, but closing it terminates the main loop.

Try this:
root = tkinter.Tk()
root.withdraw()
messagebox.showwarning('warning', 'warning')

Thank you DYZ,
in my code is no main window, (eg.: main = Tk() ... main.mainloop), because of that the warning massage create one. I could solve the problem by create one and minimize it. at the end of massagebox I destroyed it to continue in code.
from tkinter import *
from tkinter import messagebox
main = Tk()
main.geometry("500x400+300+300")
def message():
main.geometry("0x0")
messagebox.showwarning("Say Hello", "Hello World")
main.destroy()
B1 = Button(main, text = "Start Dialog",fg="dark green", command = message)
B1.pack()
main.mainloop()
print("finish dialog")

Related

Open window on button click, close current window?

I have been searching for a solution for this issue, but I can't seem to find a viable answer.
I have the following code to open another tkinter script on button click:
# Program to Open on Button Click
def tkinter1():
ret = os.system('python C:\filepath\new_script.py"')
if ret:
# record updated, reload data
treeview_preview()
b1 = Button(master, text="New Window", command=tkinter1)
My problem I am facing is that I want the current window to close on the button click and only keep the new window open.
I know it is possible. I have this instance with many different windows and I seem to be stuck.
The unfortunate thing is that I have an entire different script for different parts of the beta software and the only way I could successfully run all of them is to access them as stated above.
I tried using the if ret: exit() command at the end with the same result. I have windows opening over and over again.
It seems simple, but I haven't been programming tkinter script for too long.(I still have a lot to learn)
All help is appreciated.
You can use master.withdraw(). I
made your code runnable with a few lines. Ok lets say your fixed main code is this:
import tkinter as tk
from tkinter import *
from seccond import *
from multiprocessing import Process
import os
def main():
master = tk.Tk()
# Program to Open on Button Click
def tkinter1():
master.withdraw()
master.destroy()
ret = Process(target=treeview_preview())
ret.start()
#if ret:
# # record updated, reload data
# treeview_preview()
#commented out bc i don't know what it is
b1 = Button(master, text="New Window", command=tkinter1)
b1.pack()
master.mainloop()
if __name__ == '__main__':
main()
the secondary code name seccond.py in the same folder as the main code is called as an external function but also as a separate process.
import tkinter as tk
def treeview_preview():
root = tk.Tk()
S = tk.Scrollbar(root)
T = tk.Text(root, height=4, width=50)
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
quote = """this is the seccond window."""
T.insert(tk.END, quote)
tk.mainloop()
The code will remove the window but not the terminal box as it will use it for the second script.

Using Python, how do you call a tkinter GUI from another GUI?

I created a couple of GUIs using tkinter. But now I am interested in combining them into one caller GUI. So the caller GUI would have buttons that, when clicked, would open the other GUIs. However, I cannot get it to work. I've done the imports correctly (I think), edited the main functions in the subGUIs, and added the command=GUI.main in my buttons. I get it to load but I get errors about missing files...but when I run a GUI by itself it works fine.
In my research, I read that there can only be one mainloop in a Tkinter program. Basically, I cannot use a Tkinter GUI to call another Tkinter GUI. Do you know what I can do different, for instance, can I create the caller GUI using wxPython and have it call all other GUIs that use Tkinter?
Thank you!
You can't "call" another GUI. If this other GUI creates its own root window and calls mainloop(), your only reasonable option is to spawn a new process. That's a simple solution that requires little work. The two GUIs will be completely independent of each other.
If you have control over the code in both GUIs and you want them to work together, you can make the base class of your GUI a frame rather than a root window, and then you can create as many windows as you want with as many GUIs as you want.
For example, let's start with a simple GUI. Copy the following and put it in a file named GUI1.py:
import tkinter as tk
class GUI(tk.Frame):
def __init__(self, window):
tk.Frame.__init__(self)
label = tk.Label(self, text="Hello from %s" % __file__)
label.pack(padx=20, pady=20)
if __name__ == "__main__":
root = tk.Tk()
gui = GUI(root)
gui.pack(fill="both", expand=True)
tk.mainloop()
You can run that GUI normally with something like python GUI1.py.
Now, make an exact copy of that file and name it GUI2.py. You can also run it in the same manner: python GUI2.py
If you want to make a single program that has both, you can create a third file that looks like this:
import tkinter as tk
import GUI1
import GUI2
# the first gui owns the root window
win1 = tk.Tk()
gui1 = GUI1.GUI(win1)
gui1.pack(fill="both", expand=True)
# the second GUI is in a Toplevel
win2 = tk.Toplevel(win1)
gui2 = GUI2.GUI(win2)
gui2.pack(fill="both", expand=True)
tk.mainloop()
Depending on your OS and window manager, one window might be right on top of the other, so you might need to move it to see both.
Thank you for the ideas. At first, your code wouldn't print the text on the toplevel window. So I edited it a little and it worked! Thank you. GUI1 and GUI2 look like:
import tkinter as tk
def GUI1(Frame):
label = tk.Label(Frame, text="Hello from %s" % __file__)
label.pack(padx=20, pady=20)
return
if __name__ == "__main__":
root = tk.Tk()
GUI1(root)
root.mainloop()
And then the caller looks like this:
from tkinter import *
import GUI1
import GUI2
def call_GUI1():
win1 = Toplevel(root)
GUI1.GUI1(win1)
return
def call_GUI2():
win2 = Toplevel(root)
GUI2.GUI2(win2)
return
# the first gui owns the root window
if __name__ == "__main__":
root = Tk()
root.title('Caller GUI')
root.minsize(720, 600)
button_1 = Button(root, text='Call GUI1', width='20', height='20', command=call_GUI1)
button_1.pack()
button_2 = Button(root, text='Call GUI2', width='20', height='20', command=call_GUI2)
button_2.pack()
root.mainloop()

Tkinter threading and return to text widget

I've read some post on stack overflow,Issues intercepting subprocess output in real time, Redirect command line results to a tkinter GUI, i know i have to use threading and queue in tkinter, but I am still can't do the same thing because I am a beginner in program,please help.
The goal: When press a button, getting the 'top' command output and realtime display in tkinter text widget
The issue: I've tried to follow the code, but still cannot get the output, but I have not idea how to make it work.
from tkinter import *
import tkinter as tk
import subprocess
from threading import Thread
from queue import Queue
window = tk.Tk()
window.title('realtime')
window.geometry('800x400')
text = tk.Text(window)
text.pack()
button = tk.Button(window, text= 'Press')
button.pack()
window.mainloop()
This is only the gui outlook, please help
top refreshes itself now and then and I'm guessing that's the behavior you want to capture with threading and whatnot. However in this case it would be much easier to ask top to only run once, and have tkinter do the timing and refreshing:
import tkinter as tk
from sh import top
def update_text():
text.delete(0.0, tk.END)
text.insert(0.0, top('-b', n=1))
window.after(1000, update_text) # call this function again in 1 second
window = tk.Tk()
window.title('realtime')
window.geometry('800x400')
text = tk.Text(window)
text.pack()
button = tk.Button(window, text= 'Press', command=update_text)
button.pack()
window.mainloop()
You may need to install sh to run top like I did, or use subprocess.check_output if you want.
text.insert(0.0, subprocess.check_output(['top', '-b', '-n 1']))

python tkinter - get cursor in new window

I'd like to use the tab key in both showing of the following code:
from tkinter import *
main = Tk()
def pressButton():
main.destroy()
End=Button(main,text='Finished',width=15,command=pressButton).grid()
main.mainloop()
from tkinter import *
main = Tk()
def pressButton():
main.destroy()
End=Button(main,text='Finished',width=15,command=pressButton).grid()
main.mainloop()
first window works: i can press tab and space and it opens the second window; there i'm not able to "press button" by using tab and space, because the cursor is in Python Shell.
How can I get the cursor in the second window?
As mention in that post "Tkinter main window focus", it is possible to force the focus to the main window.
Solution - add a call to the after() to focus_force().
from tkinter import *
main = Tk()
def pressButton():
main.destroy()
End=Button(main,text='Finished',width=15,command=pressButton).grid()
# call the focus_force() after the window is displayed
main.after(1, lambda: main.focus_force())
main.mainloop()

Tkinter exit error [duplicate]

How do I end a Tkinter program? Let's say I have this code:
from Tkinter import *
def quit():
# code to exit
root = Tk()
Button(root, text="Quit", command=quit).pack()
root.mainloop()
How should I define the quit function to exit my application?
You should use destroy() to close a Tkinter window.
from Tkinter import *
#use tkinter instead of Tkinter (small, not capital T) if it doesn't work
#as it was changed to tkinter in newer Python versions
root = Tk()
Button(root, text="Quit", command=root.destroy).pack() #button to close the window
root.mainloop()
Explanation:
root.quit()
The above line just bypasses the root.mainloop(), i.e., root.mainloop() will still be running in the background if quit() command is executed.
root.destroy()
While destroy() command vanishes out root.mainloop(), i.e., root.mainloop() stops. <window>.destroy() completely destroys and closes the window.
So, if you want to exit and close the program completely, you should use root.destroy(), as it stops the mainloop() and destroys the window and all its widgets.
But if you want to run some infinite loop and don't want to destroy your Tkinter window and want to execute some code after the root.mainloop() line, you should use root.quit(). Example:
from Tkinter import *
def quit():
global root
root.quit()
root = Tk()
while True:
Button(root, text="Quit", command=quit).pack()
root.mainloop()
#do something
See What is the difference between root.destroy() and root.quit()?.
def quit()
root.quit()
or
def quit()
root.destroy()
import tkinter as tk
def quit(root):
root.destroy()
root = tk.Tk()
tk.Button(root, text="Quit", command=lambda root=root:quit(root)).pack()
root.mainloop()
Illumination in case of confusion...
def quit(self):
self.destroy()
exit()
A) destroy() stops the mainloop and kills the window, but leaves python running
B) exit() stops the whole process
Just to clarify in case someone missed what destroy() was doing, and the OP also asked how to "end" a tkinter program.
I think you wrongly understood the quit function of Tkinter. This function does not require you to define.
First, you should modify your function as follows:
from Tkinter import *
root = Tk()
Button(root, text="Quit", command=root.quit).pack()
root.mainloop()
Then, you should use '.pyw' suffix to save this files and double-click the '.pyw' file to run your GUI, this time, you can end the GUI with a click of the Button, and you can also find that there will be no unpleasant DOS window. (If you run the '.py' file, the quit function will fail.)
The usual method to exit a Python program:
sys.exit()
(to which you can also pass an exit status) or
raise SystemExit
will work fine in a Tkinter program.
In case anyone wants to bind their Escape button to closing the entire GUI:
master = Tk()
master.title("Python")
def close(event):
sys.exit()
master.bind('<Escape>',close)
master.mainloop()
The easiest way would be to click the red button (leftmost on macOS and rightmost on Windows).
If you want to bind a specific function to a button widget, you can do this:
class App:
def __init__(self, master)
frame = Tkinter.Frame(master)
frame.pack()
self.quit_button = Tkinter.Button(frame, text = 'Quit', command = frame.quit)
self.quit_button.pack()
Or, to make things a little more complex, use protocol handlers and the destroy() method.
import tkMessageBox
def confirmExit():
if tkMessageBox.askokcancel('Quit', 'Are you sure you want to exit?'):
root.destroy()
root = Tk()
root.protocol('WM_DELETE_WINDOW', confirmExit)
root.mainloop()
you only need to type this:
root.destroy()
and you don't even need the quit() function cause when you set that as commmand it will quit the entire program.
you dont have to open up a function to close you window, unless you're doing something more complicated:
from Tkinter import *
root = Tk()
Button(root, text="Quit", command=root.destroy).pack()
root.mainloop()
In idlelib.PyShell module, root variable of type Tk is defined to be global
At the end of PyShell.main() function it calls root.mainloop() function which is an infinite loop and it runs till the loop is interrupted by root.quit() function. Hence, root.quit() will only interrupt the execution of mainloop
In order to destroy all widgets pertaining to that idlelib window, root.destroy() needs to be called, which is the last line of idlelib.PyShell.main() function.
I normally use the default tkinter quit function, but you can do your own, like this:
from tkinter import *
from tkinter.ttk import *
window = Tk()
window.geometry('700x700') # 700p x 700p screen
def quit(self):
proceed = messagebox.askyesno('Quit', 'Quit?')
proceed = bool(proceed) # So it is a bool
if proceed:
window.quit()
else:
# You don't really need to do this
pass
btn1 = Button(window, text='Quit', command=lambda: quit(None))
window.mainloop()
For menu bars:
def quit():
root.destroy()
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=quit)
menubar.add_cascade(label="menubarname", menu=filemenu)
root.config(menu=menubar)
root.mainloop()
I use below codes for the exit of Tkinter window:
from tkinter import*
root=Tk()
root.bind("<Escape>",lambda q:root.destroy())
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="exit",command=root.destroy).pack()
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="quit",command=quit).pack()
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="exit",command=exit).pack()
root.mainloop()
Code snippet below. I'm providing a small scenario.
import tkinter as tk
from tkinter import *
root = Tk()
def exit():
if askokcancel("Quit", "Do you really want to quit?"):
root.destroy()
menubar = Menu(root, background='#000099', foreground='white',
activebackground='#004c99', activeforeground='white')
fileMenu = Menu(menubar, tearoff=0, background="grey", foreground='black',
activebackground='#004c99', activeforeground='white')
menubar.add_cascade(label='File', menu=fileMenu)
fileMenu.add_command(label='Exit', command=exit)
root.config(bg='#2A2C2B',menu=menubar)
if __name__ == '__main__':
root.mainloop()
I have created a blank window here & add file menu option on the same window(root window), where I only add one option exit.
Then simply run mainloop for root.
Try to do it once
Of course you can assign the command to the button as follows, however, if you are making a UI, it is recommended to assign the same command to the "X" button:
def quit(self): # Your exit routine
self.root.destroy()
self.root.protocol("WM_DELETE_WINDOW", self.quit) # Sets the command for the "X" button
Button(text="Quit", command=self.quit) # No ()
There is a simple one-line answer:
Write - exit() in the command
That's it!

Categories

Resources