The following code is from https://github.com/PacktPublishing/Modern-Python-Standard-Library-Cookbook/blob/master/Chapter13/gui_03.py.
Using Python 3.9.
With root.withdraw() The idea is to show a widget without the default tk window appearing. This works with other widgets. However, in this case, if left in p = ProgressDialog does not appear either.
I do not have enough experience to be confident that this warrants a bug report. Am I missing something? Is there a workaround?
import tkinter
from tkinter import simpledialog
from tkinter import ttk
from queue import Queue
class ProgressDialog(simpledialog.SimpleDialog):
def __init__(self, master, text='', title=None, class_=None):
super().__init__(master=master, text=text, title=title, class_=class_)
self.default = None
self.cancel = None
self._queue = Queue()
self._bar = ttk.Progressbar(self.root, orient="horizontal",
length=200, mode="determinate")
self._bar.pack(expand=True, fill=tkinter.X, side=tkinter.BOTTOM)
self.root.attributes("-topmost", True)
self.root.after(200, self._update)
def set_progress(self, value):
self._queue.put(value)
def _update(self):
while self._queue.qsize():
try:
self._bar['value'] = self._queue.get(0)
except Queue.Empty:
pass
self.root.after(200, self._update)
if __name__ == '__main__':
root = tkinter.Tk()
root.withdraw() # The idea is to show the widget without default tk window appearing.
# However if left in p = ProgressDialog does not appear either.
p = ProgressDialog(master=root, text='Downloading Something...',
title='Download')
import threading
def _do_progress():
import time
for i in range(1, 11):
time.sleep(0.5)
p.set_progress(i*10)
p.done(0)
t = threading.Thread(target=_do_progress)
t.start()
p.go()
print('Download Completed!')
CodePudding user response:
It is because SimpleDialog
makes itself a transient window of its parent, so it will be hidden if its parent is hidden.
One work around is to override SimpleDialog._set_transient()
:
import tkinter
from tkinter import simpledialog
from tkinter import ttk
from queue import Queue
class ProgressDialog(simpledialog.SimpleDialog):
def __init__(self, master, text='', title=None, class_=None):
super().__init__(master=master, text=text, title=title, class_=class_)
self.default = None
self.cancel = None
self._queue = Queue()
def _set_transient(self, master, relx=0.5, rely=0.3):
self.root.withdraw()
# add the progress bar
self._bar = ttk.Progressbar(self.root, orient="horizontal",
length=200, mode="determinate")
self._bar.pack(expand=True, fill=tkinter.X, side=tkinter.BOTTOM)
# put the dialog at desired position on screen based on relx and rely arguments
master.update_idletasks()
m_width, m_height = master.winfo_screenwidth(), master.winfo_screenheight()
w_width, w_height = self.root.winfo_width(), self.root.winfo_height()
x = int(m_width*relx) - w_width//2
y = int(m_height*rely) - w_height//2
self.root.geometry(f' {x} {y}')
self.root.attributes("-topmost", True)
self.root.deiconify()
# start the update loop
self.root.after(200, self._update)
def set_progress(self, value):
self._queue.put(value)
def _update(self):
while self._queue.qsize():
try:
self._bar['value'] = self._queue.get(0)
except Queue.Empty:
pass
self.root.after(200, self._update)
if __name__ == '__main__':
root = tkinter.Tk()
root.withdraw() # The idea is to show the widget without default tk window appearing.
p = ProgressDialog(master=root, text='Downloading Something...',
title='Download')
import threading
def _do_progress():
import time
for i in range(1, 11):
time.sleep(0.5)
p.set_progress(i*10)
p.done(0)
t = threading.Thread(target=_do_progress)
t.start()
p.go()
print('Download Completed!')