如何从一个窗口(类)到另一个窗口获取progressbar start()信息? [英] How to get progressbar start() info from one window (class) to other?

查看:96
本文介绍了如何从一个窗口(类)到另一个窗口获取progressbar start()信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个带有菜单和进度条的主窗口。通过菜单命令打开带有OK按钮的对应窗口,然后OK按钮开始该过程(此处为3秒睡眠)。
对应窗口是通过从我在此处未提供的类的继承中创建的(如果需要答案,请告诉我)。方法 apply ok 覆盖父类中的现有方法。

There is a main window with menu and the progressbar. A correspondence window with OK button opens upon menu command and the OK button starts the process (here: 3 sec. sleep). The correspondence window is created via inheritance from a class I have not provided here (If required for answer, please let me know). The methods apply and ok override existing methods in the mother class.

现在我的问题是:由于进度条位于主窗口(App类)中,而进度条(开始)进度条(停止)在对应窗口中,我必须通过母类tkSimpleDialog.Dialog将(开始)和(停止)传递给App类。所以我想我也要覆盖 __ init __(self ..)方法,将 self。提供给progressbar。

Now my problem: Since the progressbar sits in the main window (class App) and progressbar(start) and progressbar(stop) in the correspondence window I somehow have to pass (start) and (stop) via the mother class tkSimpleDialog.Dialog to class App. So I thought I also override the __init__(self..) method, provide self. to progressbar.

如何进行这项工作?

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()

错误消息:单击确定后首先显示

error messages: first after clicking ok:

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'

second:关闭应用程序后

second: after closing app

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


推荐答案

下面是您的代码的有效版本。我必须解决许多问题,因为您没有更改代码中从我的答案到其他

Below is a working version of your code. There were a number of issues I had to fix because you didn't change a number of things in the code from my answer to your other question about progressbars.

这里主要问题的答案基本上是您必须通过该实例周围的实例,并在所涉及的各种类实例中在必要时记住该实例,以便他们的方法在需要时可以通过 self 参数使用它。另外,您尝试派生和覆盖 tkSimpleDialog.Dialog 基类方法既复杂又错误。

The answer to your main question here is basically that you have to pass the instance around and remember it when necessary in the various class instances involved so that their methods will have it available through theself argument when they need it. Also, the way you were trying to derive and override the tkSimpleDialog.Dialog base class methods was both over-complicated and incorrect as well.

通常最好的(也是最简单的)方法就是提供您自己的 validate() apply()方法,因为这是它设计的工作方式。如果您还需要自己的 __ init __()构造函数,那么仅将参数传递给子类中可以理解的基类方法很重要。如果需要更多功能,通常可以通过其他仅派生类的方法来提供,只有它或您也创建的其他类才知道。

Usually the best (and simplest) thing to do is just supply your own validate() and apply() methods since that's how it was designed to work. If you also need your own __init__() constructor, it's important to only pass parameters to the base class' method that it understands from within the one in the subclass. If you need more functionality, it can usually be provided via additional derived-class-only methods, that only it or other classes you've also created know about.

,这就是我最终得到的结果:

Anyway, here's what I ended-up with:

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()

希望这会有所帮助。

这篇关于如何从一个窗口(类)到另一个窗口获取progressbar start()信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆