私はPythonを初めて使用し、現在個人用の小さなアプリケーションを開発しています。GUIにtkinterを使用しています。
私がやろうとしているのは、ログイン試行の進行状況に応じてテキストを変更するラベル付きのトップレベル ポップアップを作成することです。したがって、tk が実行されているメイン スレッドが動的テキストを含むポップアップを表示している間に、スレッドを開始して最大 5 回ログインを試み、「logindata」というグローバル変数を設定してメイン スレッドに報告したいと考えています。
AuctioneerGUI の _login() メソッドと LoginThread クラスは、ここで重要な唯一のものであり、残りは無視できますが、関連があると見なされる場合があります。
ログインボタンが押されると、_login() メソッドが呼び出されます。これが行うことは、ログインを試みて logindata を設定することだけです。その間、メイン スレッドは、LoginThread が変数を設定したことに気付くまでループし、3 つすべてを収集すると、残りのロジックに進みます (完全には実装されていませんが、問題には関係ありません)。
ここで起こることは、LoginThread が開始された後にメイン スレッドが停止し、それが終了したときにのみ続行することです。LoginThread は別のスレッドで実行する必要があるため、メイン スレッドを停止しないでください。そのため、ポップアップは、LoginThread が実行するタスクが完了した後にのみ表示されます。ポップアップが表示され、ユーザーに更新を与えるラベルを表示したいと思います。どうすればいいですか?
印刷を使用してこれを判断したため、スレッドがメインスレッドを停止していることに問題があると確信しています。
また、もう 1 つ小さな質問があります。popup.destroy() は何もしていないようです。TopLevel はそこにとどまります。
テキストの壁で申し訳ありませんが、私を助けてくれてありがとう. 私はすでにいくつかの異なることを試す必要があるよりも多くの時間を費やしましたが、それを機能させることができませんでした.
何か不明な点があれば教えてください。時には非効率的またはばかげたロジックを気にしないでください。きれいにする前に、少なくとも機能するようにしたいと思います。
-大安
global logindata
logindata = {"counter": -1, "status": -1, "success": -1}
class AuctioneerGUI:
def __init__(self):
root = Tk()
root.title("Path of Exile Auctioneer")
self._setupGUI(root)
self._loggingin = False
root.protocol("WM_DELETE_WINDOW", lambda: root.quit())
root.mainloop()
def _setupGUI(self, root):
frame = Frame(root)
email = StringVar()
pass_ = StringVar()
thread = StringVar()
email.set("email")
pass_.set("password")
thread.set("76300")
email_label = Label(frame, text="email")
self._email_box = Entry(frame, takefocus=True, width=50, textvariable=email)
self._email_box.focus_set()
pass_label = Label(frame, text="password")
self._pass_box = Entry(frame, takefocus=True, show="*", width=50, textvariable=pass_)
thread_label = Label(frame, text="thread id")
self._thread_box = Entry(frame, takefocus=True, width=10, textvariable=thread)
self._login_button = Button(frame, text="login", command=lambda: self._login(root), takefocus=True)
frame.pack()
email_label.pack()
self._email_box.pack()
pass_label.pack()
self._pass_box.pack()
thread_label.pack()
self._thread_box.pack()
self._login_button.pack()
def _login(self, root):
self._login_button.configure(command=None)
email = self._email_box.get()
pass_ = self._pass_box.get()
thread = self._thread_box.get()
# Check email validity
# no whitespaces, 1 @ sign 1 . after the @ sign
try:
thread = int(thread)
except ValueError:
return -1
#invalid thread
if not re.match(r"[^@]+@[^@]+\.[^@]+", email) or not email.find(" ") == -1:
return -1
#invalid mail
self._sm = SessionManager(email, pass_, thread)
self._message = StringVar()
self._message.set("Attempt 1/5.")
popup = Toplevel(root)
popup.title("Logging in...")
message_label = Label(popup, text = self._message.get(), textvariable = self._message)
message_label.pack()
_thread = LoginThread(self._sm)
_thread.start()
loop = True
while loop:
counter = -1
success = -1
status = -1
while counter == -1:
counter = logindata["counter"]
print(counter)
while success == -1:
success = logindata["success"]
print(success)
while status == -1:
status = logindata["status"]
print(status)
if success:
self._message.set("Attempt {}/5. Success.".format(counter))
elif status == 200:
self._message.set("Attempt {}/5. Failed: wrong password.".format(counter))
else:
self._message.set("Attempt {}/5. Failed: connection error. {}".format(counter, status))
updatebar = not success
logindata["counter"] = -1
logindata["status"] = -1
logindata["success"] = -1
if counter == 5:
break
popup.destroy()
self._login_button["command"] = lambda: self._login(root)
self._setup_main_layout(root)
def _setup_main_layout(self, root):
pass
class LoginThread(threading.Thread):
def __init__(self, sessionmanager):
threading.Thread.__init__(self)
self._sm = sessionmanager
def run(self):
success = False
counter = 1
while not success:
if counter > 5:
break
data = self._sm.login()
status = data[1]
success = data[0]
logindata["counter"] = counter
logindata["success"] = success
logindata["status"] = status
counter += 1
print("done")
アップデート:
いくつかの調査の後、ウィジェットにパイプされ、次の例のようにキューを介して通信するラベルから継承する ThreadSafeLabel を作成することで、問題を解決します。