3

Tkinter (および ttk) と Python を使用した GUI を使用して、コードを使用可能でバグの少ないプログラムに整理するのに問題があります。基本的に、今のところネットから画像をダウンロードするだけですが、そのための単純なGUIでさえ問題があります。コンソールではすべてが機能していましたが、GUI を作成するのは悪夢でした。そして今、私はそれを機能させていますが、頻繁にクラッシュし、正しくアクセスされていないGUIの変数のエラーを取得して間違ったことをしていることは明らかです(確認するために自分で機能を追加したコンソールのエラーメッセージでさえも)正常に動作します)、一定のクラッシュが発生します。

基本的に私はこのようなものを持っています。

プログラムの集中部分 (現在はスレッドに含まれている) に送信される entrytext からのユーザー入力文字列、GUI のプログレスバーをステップ実行する集中部分、テキストメッセージをサーバーに送信する集中部分。 GUI のない textbox/logger と集中的な部分のクラッシュ。また、集中的な部分は、GUI が完全に読み込まれるとすぐに開始し、準備ができたらテキストボックスに起動メッセージを送信する必要があります。

集中的な部分は他のことを処理しますが、画像の実際のダウンロードと保存、ブラウジング、ファイル I/O などの GUI に干渉することはありません。とにかく、ほとんどの場合、問題はありませんでした。

Queues and Threading とチュートリアルについても読んだことがありますが、とにかく理解できないようです。特に、GUI にテキスト メッセージを送信しながら、プログラムが GUI のプログレスバーを常にステップするようにする方法 (たとえば、非常に遅くて CPU を集中的に使用する While および If ループと複数のループを実行することなく、キューからアプローチする方法など)単純な例では、単純な while と queue.get() を待機させるだけで、ほとんどリソースを消費しないので便利です)。だから私の質問は、これのためにどのような構造を実装する必要があるかということです。可能であれば、例を1つまたは2つ入手できますか(ドキュメントを読むよりも例からよく学びます)? どうもありがとうございました。

from Tkinter import *
import ttk
import Threading
import #a bunch of other stuff

class myHardWorkerThread (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.myClass = ModifiedConsoleClass()

    def run(self):
            #thread needs to wait at least a little otherwise the thread begins too
            #fast and causes even more errors, probably due to it sending text to
            #the textbox upon startup among other things and just overall no
            #organization
            time.sleep(3)
            self.myClass.BeginDoingStuff()

class ApplyMyGuiAndStartThread():
    def __init__(self, root, thread):

        root.geometry('500x500')
        root.resizable(0,0)

        #Put backgrounds or images or logos  here
        self.canvas = Canvas(root)
        self.canvas.pack()

        #My textbox that acts like a Log/Console output
        self.txtLogger = Text(root,state="disabled",wrap="word")
        self.txtLogger.place()
        self.scrollbar = Scrollbar(root)
        self.scrollbar.place()

        #Progressbar
        self.myVal = IntVar()
        self.TProgressbar = ttk.Progressbar(root, orient=HORIZONTAL, variable = self.myVal, mode='determinate')
        self.TProgressbar.place()

        #Entrybox for user input
        self.txbEntryText = StringVar()
        self.txtbEntry = ttk.Entry (root, textvariable=self.txbEntryText)
        self.txtbEntry.place()
        self.txtbEntry.bind("<Return>", self.SendFromGUItoThread)

        self.thread = thread
        self.thread.start()

    def SendFromGUItoThread(self,arg=None):

        myentry = str(self.txtbEntry.get())
        self.txtbEntry.delete(0, END)
        self.thread.myClass.entryBoxValueCopy = myentry


    def SendFromThreadToGUI(self,msg):
        try:
            self.txtLogger['state'] = 'normal'
            self.txtLogger.insert('end', msg)
            self.txtLogger['state'] = 'disabled'
        except:
            print "Could not be printed"


class ModifiedConsoleCode():
    def __init__(self):
        #constants here like
        self.entryBoxValueCopy = None

    def BeginDoingStuff():
        #Thread does the bulk of work  here, includes connecting to websites,
        #collecting info, sending text messages to GUI, downloading images and
        #stepping the progressbar by a calculated amount by file size

    def OneOfManyFunctionsUsedInsideBeginDoingStuff():
        #Breaks things down like looping time.sleep waits for user input in the entry box
        #showing up in entryBoxValueCopy, and using the user input to surf websites and
        #collect images

if __name__ == '__main__':

        root = Tk()
        root.title(titleOfTheProgram)

        worker = myHardWorkerThread()

        w = ApplyMyGuiAndStartThread(root,worker)

        root.mainloop()
        os._exit(0)
4

3 に答える 3

3

簡単に言うと、ワーカー スレッドからウィジェットを操作することはできません。唯一の選択肢は、ワーカー スレッドにスレッド セーフ キューに何かをプッシュさせ、メイン スレッドにそれをポーリングさせることです。

キューをポーリングするために while ループは必要ありません。既に無限ループ (イベント ループ (例: mainloop)) があるため、追加のループを追加する必要はありません。

メイン スレッドからキューをポーリングする方法は次のようになります。

def pollQueue(self):
    <look at the queue, act on the results>
    self.after(100, self.pollQueue)

これが行うことは、100 ミリ秒ごとにキューをポーリングするように手配することです。もちろん、ポーリング間隔は任意に設定できます。

于 2013-05-31T14:16:53.120 に答える