Python Forum
[Tkinter] Modal window - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [Tkinter] Modal window (/thread-40930.html)

Pages: 1 2


Modal window - DPaul - Oct-15-2023

Hi,
I'm getting pretty confused, reading about modal windows in tKinter.
I thought it would be simple.

I have an existing app,where users make a selection in a listbox, and go on from there.
However, as an extra service, I would like this selection to trigger a pop-up TopLevel window,
with a rather large amout of text.
That is easy.
BUT, I would like this TopLevel to be modal, so the user has to close it before moving on.

I had hoped that adding some parameter to "topWindow = Toplevel(height=500, width=200)"
would do the trick, but how ?
thanks,
Paul


RE: Modal window - menator01 - Oct-15-2023

If you're using TopLevel could you not just use the withdraw and deiconify functions?

I have an example on the site. I will search and post the link.



Not the example I was looking for but, same principle.
https://python-forum.io/thread-26925-post-114781.html#pid114781


Another quick example of toplevel window

import tkinter as tk

class TopWindow:
	def __init__(self, root):
		self.root = root
		self.window = tk.Toplevel(None)
		
		label = tk.Label(self.window, text='This is a top level window.')
		label.pack()
		
		btn = tk.Button(self.window, text='Close Me', command=self.close)
		btn.pack()
		
		self.window.protocol('WM_DELETE_WINDOW', self.close)
		
	def close(self):
		self.window.destroy()
		self.root.deiconify()
		
		
		
class MainWindow:
	def __init__(self, parent):
		self.parent = parent
		label = tk.Label(parent, text='The Main Window')
		label.pack()
		
		btn = tk.Button(parent, text='Open Window', command=self.openme)
		btn.pack()
	
	def openme(self):
		self.parent.withdraw()
		TopWindow(self.parent)
		
		
root = tk.Tk()
MainWindow(root)
root.mainloop()



RE: Modal window - DPaul - Oct-15-2023

(Oct-15-2023, 09:06 AM)menator01 Wrote: If you're using TopLevel could you not just use the withdraw and deiconify functions?
Thanks and agreed.
Seems to be a lot of hassle for something I thought to be simple.
I'll try it.
Paul


RE: Modal window - Gribouillis - Oct-15-2023

Have you tried the grab_set() method?


RE: Modal window - menator01 - Oct-15-2023

One more example that I found here. I used the example at the bottom of the page.
https://stackoverflow.com/questions/10057672/correct-way-to-implement-a-custom-popup-tkinter-dialog-box

import tkinter as tk
from tkinter.simpledialog import Dialog

class MyDialog(Dialog):
	def __init__(self, parent, **kwargs):
		Dialog.__init__(self, parent, **kwargs)
		
	def body(self, parent):
		label = tk.Label(self, text='Can hold tkinter widgets such as label, listbox, etc...', wraplength=300, justify='left', anchor='w')
		label.pack()
		
	def validate(self):
		return 1
		
	def apply(self):
		pass
		
		
class Window:
	def __init__(self, parent):
		self.parent = parent
		btn = tk.Button(parent, text='Click Me', command=self.opendialog)
		btn.pack()
		
	def opendialog(self):
		MyDialog(self.parent)
		
		
root = tk.Tk()
Window(root)
root.mainloop()



RE: Modal window - Larz60+ - Oct-15-2023

check out grab_set as mentioned above by Griboullis
for example, see: https://www.pythontutorial.net/tkinter/tkinter-toplevel/


RE: Modal window - deanhystad - Oct-15-2023

If all you want to do is display a block of text and an ok button, look at tkinter.dialog.Dialog, the parent class for tkinter common dialogs.
import tkinter as tk
from tkinter.dialog import Dialog, DIALOG_ICON


class Window(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("Basic Dialog Demo")
        tk.Button(
            self, text='Push me! Push me! Push me!', command=self.opendialog
        ).pack(padx=80, pady=(100, 10))


    def opendialog(self):
        with open(__file__, "r") as file:
            text = file.read()

        Dialog(
            self,
            title="Popup Dialog",
            text=text,
            bitmap=DIALOG_ICON,
            default=0,
            strings=("OK",)
        )
        print("Dialog closed.")


Window().mainloop()



RE: Modal window - DPaul - Oct-15-2023

The problem with this forum is that you get so may valid responses.
Now I need to try them all.
Won't tell which one suits best, not to make anyone jealous. Tongue
thx,
Paul


RE: Modal window - DPaul - Oct-16-2023

FYI
The good news is, that I now have a nice & shining modal TopLevel window!
Thanks,
Paul
edit: showed it to a user today, he loved it !


RE: Modal window - deanhystad - Oct-16-2023

Calling grab_set() makes a TopLevel window modal, but it does not make it act like a dialog. A dialog window blocks execution of the caller, which makes it easy to write code that uses values from the dialog. In Menator's first example, this function returns immediately.
    def opendialog(self):
        MyDialog(self.parent)  # This does not block.
        print("Hello")
This is fine for showing a message, but would not work for Yes/Now window, a color picker, a file picker, a anything that returns a value that is important window.

Menator's second example does block here:
    def opendialog(self):
        MyDialog(self.parent)  # Will wait for program to close.
        print("Hello")
This is a characteristic of being a dialog, not being modal. Dialogs run their own mainloop(). This blocks the code that opened the dialog.