2

マルチスレッドとtkinterで苦労しています。slxl私が使用するモジュールは動作し、その関数は値を返しません (混乱がないことを確認するためだけです)。

過去に機能したコードは次のとおりです。

    #relevant tkinter code
    def create_widgets():

        self.updatebttn = Button(self, text='Auto Update', command=self.spawnthread)
        self.updatebttn.grid(row=1, column=0, sticky=N)

        self.progressbar = Progressbar(self, orient='horizontal',
                                       length=300, mode='determinate')
        self.progressbar.grid(row=1, column=1, sticky=W)
        self.progressbar["maximum"] = (slxl.sizeFinder()) * 1.1


    def spawnthread(self):
        self.updatebttn.config(state="disabled")
        self.thread = ThreadedClient1(self.queue)
        self.thread.start()
        self.periodiccall()

    def periodiccall(self):
        if self.thread.is_alive():
            self.after(100, self.periodiccall)
            self.progressbar.step(500)
        else:
            self.updatebttn.config(state="active")
            self.progressbar.stop()

class ThreadedClient1(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue
    def run(self):
        time.sleep(1)
        importer = slxl.runImportAndCoordAdder()
        self.queue.put(importer)

問題は、ThreadedClient1 がキューに入れている関数を、この場合slxl.runImportAndCoordAdder()は引数として取得できるようにしたいということです。これはThreadedClient、異なる関数で複数回使用するためです (後でプログラムで同じように使用します)。異なる関数のみ)ThreadedClient1とを持つのは好きではありません。ThreadedClient2唯一の違いはimporter =異なる関数です。

私はそのようなラムダで解決策を試みました:

def spawnthread(self):
    self.updatebttn.config(state="disabled")
    self.thread = ThreadedClient1(self.queue, lambda: slxl.runImportAndCoordAdder())
    self.thread.start()
    self.periodiccall()

#periodic call is the same

class ThreadedClient1(threading.Thread):
    def __init__(self, queue, fcn):
        threading.Thread.__init__(self)
        self.queue = queue
        self.fcn = fcn
    def run(self):
        time.sleep(1)
        self.queue.put(lambda: self.fcn)

私が興味を持っている機能を無視し、プログレスバーを少し動かしたり無効にしたり、ボタンを有効にしたりして終了したため、これは機能しませんでした。

私は何を間違っていますか?

編集: 問題は解決しました。しかし、別のものが出てきました。spawnthreadperiodiccall、およびを私が持っているウィジェット テンプレート モジュールに転送し、ThreadedClientそれらを一般化して簡単に使用できるようにしたいと考えています。これは私がしました:

def spawnthread(self, widget):
    widget.config(state="disabled")
    self.thread = ThreadedClient1(self.queue)
    self.thread.start()
    self.periodiccall()

私も一般化しようとするまで、これはperiodiccallうまくいきました。

    #...
        self.periodiccall(widget=widget)

    def periodiccall(self, widget=None):
        if self.thread.is_alive():
            self.after(100, self.periodiccall)
            self.progressbar.step(500)
            #print widget
        else:
            widget.config(state="active")
            self.progressbar.stop()

print widget属性エラーが発生し続けたので、何が起こっているのかを確認するためにポップインしました。起こっているように見えるのは、最初に「ウィジェット」が何であるかを知っている関数を実行した後、ステートメントNoneで呼び出して、私が望んでいたものに変わるということです。少なくとも、それが起こっていると思います。このエラーを取り除き、この再帰関数でウィジェットを変数にするにはどうすればよいですか?self.periodiccallafter

4

1 に答える 1

1

問題は、関数を引数として使用するときに関数を呼び出していないことですThreadedClient1

class ThreadedClient1(threading.Thread):
    # ...
    def run(self):
        time.sleep(1)
        self.queue.put(lambda: self.fcn)

への呼び出しの結果ではなく、引数として渡すラムダへの参照を返す単なる関数ですslxl.runImportAndCoordAdder()。そのはず:

class ThreadedClient1(threading.Thread):
    # ...
    def run(self):
        time.sleep(1)
        self.queue.put(self.fcn())

または、参照を直接(ラムダなしで)使用する別のソリューション:

def spawnthread(self):
    self.updatebttn.config(state="disabled")
    self.thread = ThreadedClient1(self.queue, slxl.runImportAndCoordAdder)
    self.thread.start()
    self.periodiccall()

class ThreadedClient1(threading.Thread):
    # ...
    def run(self):
        time.sleep(1)
        self.queue.put(self.fcn())
于 2013-07-24T15:48:36.063 に答える