在tkinter中调用API时,对话框未打开/应用程序冻结



当我在tkinter应用程序中调用API时,我想得到一个加载对话框。我在其中实现了一个自定义对话框,但对话框基本上没有出现——整个应用程序冻结,加载对话框也没有出现。

这是一个示例函数,当我单击提交按钮时运行,然后这个函数运行api调用,并在api进行调用时打开对话框,还更改帧/导航到其他帧。

def login_button_fuction():
top = tk.Toplevel(self)
top.title("loading")
top.geometry("200x100")
top.resizable(0, 0)
bar = ttk.Progressbar(top, orient="horizontal",
length=100, mode="indeterminate")
bar.pack(pady=25)
bar.start()
url = "XXXXXXXXXXXXXXXXXXX"
payload = json.dumps(
{"username": username_entry.get(), "password": password_entry.get()})
headers = {'Content-Type': 'application/json'}
response = requests.post(url+"/users/getuser", data=payload, headers=headers)
if response.json()["resultCode"] == 100:
print("success")
data = {
"realname": response.json()["data"]["realname"],
"phone": response.json()["data"]["phone"]}
with open("user_data.dat", "wb") as f:
pickle.dump(data, f)
controller.show_frame(dashboardPage.dashboard_page)
else:
print("error")
bar.grid_forget()
top.destroy()

此外,如果有人能告诉我如何从tkinter中删除最小化和关闭按钮对话框它将非常有帮助。加载对话框应在进行API调用时出现,并应在进行API调用后自动关闭。

我试过这个,但它挂起了整个应用程序并使其崩溃。


class login_page(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#functions for buttons
def try_login():
url = "XXXXXXXXXXXXXXX"
payload = json.dumps(
{"username": username_entry.get(), "password": password_entry.get()})
headers = {'Content-Type': 'application/json'}
response = requests.post(
url+"/users/getuser", data=payload, headers=headers)
return response
def login_button_fuction():
top = tk.Toplevel(self)
top.title("loading")
top.geometry("200x100")
top.resizable(0, 0)
bar = ttk.Progressbar(top, orient="horizontal",
length=100, mode="indeterminate")
bar.pack(pady=25)
bar.start()
response = threading.Thread(target=try_login)
response.start()
response.join()
print(response)
if response.json()["resultCode"] == 100:
print("success")
data = {
"realname": response.json()["data"]["realname"],
"phone": response.json()["data"]["phone"],
"email": response.json()["data"]["email"]}
with open("user_data.dat", "wb") as f:
pickle.dump(data, f)
controller.show_frame(dashboardPage.dashboard_page)
else:
print("error")
bar.grid_forget()
top.destroy()

您需要在不同的线程中进行任何工作,但是所有的gui更新都应该在主线程中进行,否则可能会有点不稳定

类似以下未经测试的代码应该可以工作(可能有一些小改动(

def do_login(username,password,callback):
# this should run in a thread so it does not block the gui
# since it is run in a thread it SHOULD NOT update the gui
payload = json.dumps({"username": username, "password": password})
headers = {'Content-Type': 'application/json'}
callback(requests.post(url+"/users/getuser", data=payload, headers=headers))
import threading
def login_button_fuction():
# this is called by the gui when the button is clicked
top = tk.Toplevel(self)
top.title("loading")
top.geometry("200x100")
top.resizable(0, 0)
bar = ttk.Progressbar(top, orient="horizontal",
length=100, mode="indeterminate")
bar.pack(pady=25)
def on_response(response):
# after the call completes it will call back
# to this function, once again in the main thread
# since this is run in the main thread you CAN update the gui            
print("Got response... hide bar...or something",data)
if response.json()["resultCode"] == 100:
print("success")
data = {
"realname": response.json()["data"]["realname"],
"phone": response.json()["data"]["phone"]
}
with open("user_data.dat", "wb") as f:
pickle.dump(data, f)

controller.show_frame(dashboardPage.dashboard_page)
else:
print("error")
bar.grid_forget()
top.destroy()
# End callback function
bar.start()
# callback needs to run in the main thread
# root.after does not accept args so it needs to be another lambda
# that calls the main thread ... there may be a more elegant way to do this
callback = lambda data:root.after(1,lambda:on_response(data))
# trigger a new thread to actually do the fetch
threading.Thread(target=do_login,args=[user_entry.get(),pass_entry.get(),callback]).start()

查看有关根的其他信息。之后

一些额外的答案,特别是关于根。触发主线程之后

下面你可以找到一个100%验证的工作示例(你可以只是复制/粘贴(,其中有一些额外的打印来演示";"破旧";

import functools
import threading
import time
import requests
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('400x150')
root.title('Tkinter Login Form - pythonexamples.org')
# username label and text entry box
usernameLabel = ttk.Label(root, text="User Name").grid(row=0, column=0)
username = tk.StringVar()
usernameEntry = ttk.Entry(root, textvariable=username).grid(row=0, column=1)
# password label and password entry box
passwordLabel = ttk.Label(root, text="Password").grid(row=1, column=0)
password = tk.StringVar()
passwordEntry = ttk.Entry(root, textvariable=password, show='*').grid(row=1, column=1)
labelVar = tk.StringVar(value="Waiting For Event")
label = ttk.Label(root, textvariable=labelVar).grid(row=10,column=0)
label = ttk.Label(root, text="Valid:'eve.holt@reqres.in'").grid(row=0,column=2)
def do_actual_login(username,password,callback):
print("current thread(doing login request):", threading.current_thread())
url="https://reqres.in/api/login"
data={"username":username,"password":password}
# fake delay to show not blocking...(request is pretty fast)
time.sleep(5)
print("ok really do request in thread")
return callback(requests.post(url,data))
def validateLogin(username, password):
print("current thread(on click handler):", threading.current_thread())
bar = ttk.Progressbar(root, orient="horizontal",
length=100, mode="indeterminate")
bar.grid(row=10,column=0)
bar.start()
def login_complete(response):
print("current thread(login_complete):",threading.current_thread())
bar.grid_remove()
if response.status_code == 200:
print("LOGIN SUCCESS!!!")
labelVar.set("Login Success")
else:
print("LOGIN FAILED:",response,response.json())
labelVar.set(response.json().get("error","Unknown Error Occurred"))
# setup our thread and callback
callback = lambda data:root.after(1,lambda:login_complete(data))
threading.Thread(
target = do_actual_login,
args = [username.get(),password.get(),callback]
).start()

validateLogin = functools.partial(validateLogin, username, password)
# login button
loginButton = ttk.Button(root, text="Login", command=validateLogin).grid(row=4, column=0)
root.mainloop()

您可以使用用户名eve.holt@reqres.in和您想要的任何密码来测试成功登录(我认为(任何其他用户名都应该失败,因为应该省略密码

最新更新