Python Tkinter:当主应用程序最小化时,进度条不会被最小化

时间:2014-09-26 23:12:02

标签: python multithreading tkinter progress-bar

请运行以下示例。

我为我的应用程序创建了一个进度条,按下“打开”按钮会弹出一个进度条。但是,当主应用程序最小化时,进度条不会被最小化。

我已尝试过以下代码行,但只有在我注释掉self.master.overrideredirect(True)时它才有效:

self.master.transient(parent)

示例(Python 2.7.3,Linux,Tkinter版本$ Revision:81008 $):

from Tkinter import Tk, Frame, BOTH, Label, Toplevel, Canvas, Button
import threading

class ProgressBar:
   def __init__(self, parent, width, height):
      master = Toplevel(parent)
      master.protocol('WM_DELETE_WINDOW', self.hide )
      self.master = master
      self.master.overrideredirect(True)
      ws = self.master.winfo_screenwidth()
      hs = self.master.winfo_screenheight()
      w = (True and ws*0.2) or 0.2
      h = (True and ws*0.15) or 0.15
      x = (ws/2) - (w/2) 
      y = (hs/2) - (h/2)
      self.master.geometry('%dx%d+%d+%d' % (width, height * 2.5, x, y))

      self.mode = 'percent'
      self.ONOFF = 'on'
      self.width = width
      self.height = height
      self.frame = None
      self.canvas = None
      self.progressBar = None
      self.backgroundBar = None
      self.progressformat = 'percent'
      self.label = None
      self.progress = 0

      self.createWidget()
      self.frame.pack()
      self.set(0.0)                  # initialize to 0%

      #self.master.transient(parent)
   def createWidget(self):
      self.frame = Frame(self.master, borderwidth = 1, relief = 'sunken')
      self.canvas = Canvas(self.frame)
      self.backgroundBar = self.canvas.create_rectangle(0, 0, self.width, self.height, fill = 'darkblue')
      self.progressBar = self.canvas.create_rectangle(0, 0, self.width, self.height, fill = 'blue')
      self.setWidth()
      self.setHeight()
      self.label = Label(self.frame, text = 'Loading...', width = 20)
      self.label.pack(side = 'top') # where text label should be packed
      self.canvas.pack()
   def setWidth(self, width = None):
      if width is not None:
         self.width = width
      self.canvas.configure(width = self.width)
      self.canvas.coords(self.backgroundBar, 0, 0, self.width, self.height)
      self.setBar() # update progress bar
   def setHeight(self, height = None):
      if height is not None:
         self.height = height
      self.canvas.configure(height = self.height)
      self.canvas.coords(self.backgroundBar, 0, 0, self.width, self.height)
      self.setBar() # update progress bar
   def set(self, value):
      if self.ONOFF == 'off': # no need to set and redraw if hidden
         return
      if self.mode == 'percent':
         self.progress = value
         self.setBar()
         return
   def setBar(self):
      self.canvas.coords(self.progressBar,0, 0, self.width * self.progress/100.0, self.height)
      self.canvas.update_idletasks()
   def hide(self):
      if isinstance(self.master, Toplevel):
         self.master.withdraw()
      else:
         self.frame.forget()
      self.ONOFF = 'off'
   def configure(self, **kw):
      mode = None
      for key,value in kw.items():
         if key=='mode':
            mode = value
         elif key=='progressformat':
            self.progressformat = value
      if mode:
         self.mode = mode
def ProgressBarLoop(window, bar, i = 0, direction = "a"):
   bar.configure(mode = 'percent', progressformat = 'ratio')
   if not window.loading:
      bar.hide()
      return
   bar.set(i)
   if direction == "a":
      i += 1
   else:
      i -= 1
   if i == 101:
      direction = "d"
   elif i == 0 and direction == "d":
      direction = "a"
   window.parent.after(1, ProgressBarLoop, window, bar, i, direction)

class Application(Frame):
   def __init__(self, parent):
      Frame.__init__(self, parent)
      self.parent = parent
      self.pack(fill = BOTH, expand = True)
      parent.geometry('%dx%d+%d+%d' % (100, 100, 0, 0))
      Button(parent, text = "Open", command = self.onOpen).pack()
   def onOpen(self, event = None):
      self.loading = True
      bar = ProgressBar(self, width=150, height=18)
      t = threading.Thread(target=ProgressBarLoop, args=(self, bar))
      t.start()
root = Tk()
Application(root)
root.mainloop()

1 个答案:

答案 0 :(得分:0)

您可以设置自己的绑定来管理overrideredirect-ed窗口的可见性。当窗口小部件被图标化或未图标化时,Tkinter会生成事件<Map><UnMap>。因此,将绑定添加到主窗口以在弹出窗口中调用wm_deiconifywithdraw