没有与菜单和进度主窗口。 与OK按钮的对应窗口在菜单命令打开和确定按钮开始处理(这里:3秒睡眠)。 通过从我这里没有提供的类继承创建的对应窗口(如果需要的答案,请让我知道)。 该方法apply
和ok
覆盖现有的母亲类的方法。
现在我的问题:由于进度坐在主窗口(类APP)和progressbar(start)
和progressbar(stop)
通过母亲类tkSimpleDialog.Dialog在对应的窗口,我无论如何都必须通过(开始)和(停止)类应用。 所以我想我也覆盖__init__(self..)
方法,提供self.
对进度。
我怎样才能使这项工作?
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time, threading
class App:
def __init__(self, master, progressbar):
self.progress_line(master)
def progress_line (self, master):
self.progressbar = ttk.Progressbar(master, mode='indeterminate')
self.progressbar.place(anchor = 'ne', height = "20", width = "150", x = "175", y = "30")
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
def menu_bar(self):
menu_bar = Tkinter.Menu(self.master)
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff = False)
self.create_menu.add_command(label = "do", command = self.do)
self.menu_bar.add_cascade(label = "now", menu = self.create_menu)
def do(self):
do1 = Dialog(self.master, progressbar)
class Dialog(tkSimpleDialog.Dialog):
def __init__(self, parent, progressbar):
tkSimpleDialog.Dialog.__init__(self, parent, progressbar)
self.transient(parent)
self.parent = parent
self.result = None
self.progressbar = progressbar
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox()
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
def ok(self, event=None):
self.withdraw()
self.start_foo_thread()
self.cancel()
def apply(self):
time.sleep(5)
def start_foo_thread(self):
global foo_thread
self.foo_thread = threading.Thread(target=self.apply)
self.foo_thread.daemon = True
self.progressbar.start()
self.foo_thread.start()
master.after(20, check_foo_thread)
def check_foo_thread(self):
if self.foo_thread.is_alive():
root.after(20, self.check_foo_thread)
else:
self.progressbar.stop()
master = Tkinter.Tk()
progressbar = None
app = App(master, progressbar)
appmenu = AppMenu(master, progressbar)
master.mainloop()
错误信息:首先单击确定后:
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
File "ask-progressbar.py", line 57, in ok
self.start_foo_thread()
File "ask-progressbar.py", line 66, in start_foo_thread
self.progressbar.start()
AttributeError: Dialog2 instance has no attribute 'progressbar'
第二:关闭应用后
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
File "ask-progressbar.py", line 26, in do
do1 = Dialog2(self.master, progressbar)
File "ask-progressbar.py", line 33, in __init__
self.transient(parent)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1652, in wm_transient
TclError: can't invoke "wm" command: application has been destroyed
下面是你的代码的工作版本。 有一些问题,我不得不解决,因为你并没有将代码从我的回答改变了一些东西,你的其他问题有关progressbars。
答案在这里你的主要问题基本上是,你必须通过周围的实例,并记住它在必要时所涉及的各种类的实例,以使他们的方法将它可通过self
的说法,当他们需要它。 此外,您试图获得并重写的方式tkSimpleDialog.Dialog
基类的方法是既过于复杂和不正确的为好。
通常是最好的(最简单的)事情做的仅仅是提供自己validate()
和apply()
方法,因为这是它是如何设计的工作。 如果您还需要你自己的__init__()
构造函数,它只能传递参数,它从一个在子类中了解到的基类的方法是很重要的。 如果你需要更多的功能,它通常可以通过附加的派生类唯一方法提供的,只有它和其他类,您还创建了了解。
总之,这里是我最终-了:
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time, threading
class App:
def __init__(self, master):
self.progress_line(master)
def progress_line(self, master):
# the value of "maximum" determines how fast progressbar moves
self._progressbar = ttk.Progressbar(master, mode='indeterminate',
maximum=4) # speed of progressbar
self._progressbar.place(anchor='ne', height="20", width="150",
x="175", y="30")
@property
def progressbar(self):
return self._progressbar # return value of private member
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
self.progressbar = progressbar
def menu_bar(self):
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff=False)
self.create_menu.add_command(label="do", command=self.do)
self.menu_bar.add_cascade(label="now", menu=self.create_menu)
def do(self):
Dialog(self.master, self.progressbar) # display the dialog box
class Dialog(tkSimpleDialog.Dialog):
def __init__(self, parent, progressbar):
self.progressbar = progressbar
tkSimpleDialog.Dialog.__init__(self, parent, title="Do foo?")
def apply(self):
self.start_foo_thread()
# added dialog methods...
def start_foo_thread(self):
self.foo_thread = threading.Thread(target=self.foo)
self.foo_thread.daemon = True
self.progressbar.start()
self.foo_thread.start()
master.after(20, self.check_foo_thread)
def check_foo_thread(self):
if self.foo_thread.is_alive():
master.after(20, self.check_foo_thread)
else:
self.progressbar.stop()
def foo(self): # some time-consuming function...
time.sleep(3)
master = Tkinter.Tk()
master.title("Foo runner")
app = App(master)
appmenu = AppMenu(master, app.progressbar)
master.mainloop()
希望这可以帮助。
这里还有一个更简单的解决方案,它不需要使用线程的 - 因此可能会更容易使用/适应你的情况。 它的耗时过程调用进度widget的update_idletasks()方法多次foo()
函数。 再次,它说明了如何通过周围的进度给需要它的代码的各个部分。
import Tkinter, ttk, tkFileDialog, tkSimpleDialog, time
class App:
def __init__(self, master):
self.progress_line(master)
def progress_line(self, master):
self._progressbar = ttk.Progressbar(master, mode='indeterminate')
self._progressbar.place(anchor='ne', height="20", width="150",
x="175", y="30")
@property
def progressbar(self):
return self._progressbar # return value of private member
class AppMenu(object):
def __init__(self, master, progressbar):
self.master = master
self.menu_bar()
self.progressbar = progressbar
def menu_bar(self):
self.menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=self.menu_bar)
self.create_menu = Tkinter.Menu(self.menu_bar, tearoff=False)
self.create_menu.add_command(label="do foo", command=self.do_foo)
self.menu_bar.add_cascade(label="now", menu=self.create_menu)
def do_foo(self):
confirm = ConfirmationDialog(self.master, title="Do foo?")
self.master.update() # needed to completely remove conf dialog
if confirm.choice:
foo(self.progressbar)
class ConfirmationDialog(tkSimpleDialog.Dialog):
def __init__(self, parent, title=None):
self.choice = False
tkSimpleDialog.Dialog.__init__(self, parent, title=title)
def apply(self):
self.choice = True
def foo(progressbar):
progressbar.start()
for _ in range(50):
time.sleep(.1) # simulate some work
progressbar.step(10)
progressbar.update_idletasks()
progressbar.stop()
master = Tkinter.Tk()
master.title("Foo runner")
app = App(master)
appmenu = AppMenu(master, app.progressbar)
master.mainloop()
文章来源: Python: How to get progressbar start() info from one window (class) to other