tkinter 求助
为了方便非技术人员,连接高速公路超速提示的电子大屏,自己写的一个开关由于连接四块屏幕的地址会出现偶尔的异常,在连接的过程中,开关的界面会卡死,于是设计当点击按钮时关掉初始的开关界面,打开一个假的进度条界面,当连接过程完毕并且报错时,,关掉进度条界面,弹出最终通知界面,正常建立连接时,则只需要关闭进度条界面即可。。但是,我的进度条界面关闭不掉,一直在运行,请大佬帮忙看看,怎么改一改,或者优化一下
import tkinter as tk
from tkinter import messagebox
from tkinter.ttk import Progressbar
import socket
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.ip = ["61.18.238.7", "61.18.238.8", "61.18.238.9", "61.18.238.10"]
self.port = 1234
self.out = ["setr=1", "setr=0"]
self.title('开关控制')
self.geometry('600x300')
self.resizable(0,0)
tk.Button(self, text='打开',
font=('楷体', 30),
anchor='center', command=self.open,
height=2, width=8, bd=6).place(relx=0.15, rely=0.3)
tk.Button(self, text='关闭',
font=('楷体', 30),
anchor='center', command=self.close,
height=2, width=8, bd=6).place(relx=0.55, rely=0.3)
self.mainloop()
def run_gui(self):
self.run = tk.Tk()
self.run.title('正在运行')
self.run.geometry("400x200")
self.run.resizable(0, 0)
jdt = Progressbar(self.run, length=200, mode='indeterminate')
jdt.place(y=50, relx=0.5, anchor='center')
jdt.start()
label = tk.Label(self.run, text=' 正在连接,请稍等...',
font=('标楷体', 15))
label.place(relx=0.5, rely=0.5, anchor='center')
self.run.mainloop()
def end_gui(self, res_str):
win = tk.Tk()
win.geometry('0x0+999999+0')
messagebox.showerror('开关控制', ' {}失败,请联系工作人员!'.format(res_str))
win.destroy()
def connect(self, ip, port, out):
for i in ip:
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((i, port))
outdata = out
tcp_client.send(outdata.encode())
recdata = tcp_client.recv(1024)
print("server:", recdata.decode())
tcp_client.close()
def open(self):
self.destroy()
self.run_gui()
try:
self.connect(self.ip, self.port, self.out)
except:
self.end_gui("打开")
finally:
self.run.destroy()
def close(self):
self.destroy()
self.run_gui()
try:
self.connect(self.ip, self.port, self.out)
except:
self.end_gui("关闭")
finally:
self.run.destroy()
if __name__ == "__main__":
app = Application()
你的代码中有一个主要的问题:你在run_gui和end_gui函数中都使用了mainloop() ,这在 Tkinter 中可能会导致问题,因为它启动了一个新的事件循环。在同一个应用程序中,应该只有一个 mainloop()。
你的代码中的每个窗口(root 和 Toplevel)应该只有一个主窗口调用 mainloop()。其他的窗口应该是这个主窗口的子窗口。当主窗口关闭时,所有的子窗口都会关闭。
为了解决你的问题,我将你的run_gui和end_gui函数中的窗口更改为Toplevel 。这样,你就可以在主窗口中调用 mainloop(),并在需要时打开和关闭子窗口。
在下面的代码中,我也将connect方法的try/except语句更改为try/except/else 。 else语句将在没有异常的情况下执行,所以在connect方法成功执行后,进度条窗口将被销毁。
这是你的代码的修改版:
import tkinter as tk
from tkinter import messagebox
from tkinter.ttk import Progressbar
import socket
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.ip = ["61.18.238.7", "61.18.238.8", "61.18.238.9", "61.18.238.10"]
self.port = 1234
self.out = ["setr=1", "setr=0"]
self.title('开关控制')
self.geometry('600x300')
self.resizable(0,0)
tk.Button(self, text='打开',
font=('楷体', 30),
anchor='center', command=self.open,
height=2, width=8, bd=6).place(relx=0.15, rely=0.3)
tk.Button(self, text='关闭',
font=('楷体', 30),
anchor='center', command=self.close,
height=2, width=8, bd=6).place(relx=0.55, rely=0.3)
def run_gui(self):
self.run = tk.Toplevel(self)
self.run.title('正在运行')
self.run.geometry("400x200")
self.run.resizable(0, 0)
jdt = Progressbar(self.run, length=200, mode='indeterminate')
jdt.place(y=50, relx=0.5, anchor='center')
jdt.start()
label = tk.Label(self.run, text=' 正在连接,请稍等...',
font=('标楷体', 15))
label.place(relx=0.5, rely=0.5, anchor='center')
def end_gui(self, res_str):
win = tk.Toplevel(self)
win.geometry('0x0+999999+0')
messagebox.showerror('开关控制', ' {}失败,请联系工作人员!'.format(res_str))
win.destroy()
def connect(self, ip, port, out):
for i in ip:
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((i, port))
outdata = out
tcp_client.send(outdata.encode())
recdata = tcp_client.recv(1024)
print("server:", recdata.decode())
tcp_client.close()
def open(self):
self.withdraw()
self.run_gui()
try:
self.connect(self.ip, self.port, self.out)
except:
self.end_gui("打开")
else:
self.run.destroy()
self.deiconify()
def close(self):
self.withdraw()
self.run_gui()
try:
self.connect(self.ip, self.port, self.out)
except:
self.end_gui("关闭")
else:
self.run.destroy()
self.deiconify()
if __name__ == "__main__":
app = Application()
app.mainloop()
在这个修改后的代码中,我使用了withdraw()方法隐藏主窗口,然后显示进度条窗口。一旦连接建立(或连接尝试失败),我销毁进度条窗口并使用deiconify()方法显示主窗口。
请注意,我将mainloop()方法移动到了程序的最后,这样就只有一个mainloop()在程序中运行。
这样的修改应该可以解决你的问题。如果你还有其他问题,欢迎继续提问。 本帖最后由 来自星星的小明 于 2023-5-15 19:59 编辑
isdkz 发表于 2023-5-15 19:24
你的代码中有一个主要的问题:你在run_gui和end_gui函数中都使用了mainloop() ,这在 Tkinter 中 ...
大佬,不行啊,点完按钮,不弹出进度条窗口,,知道连接建立完毕,进度条窗口和最后的通知窗口一起弹出了 在 `run_gui()` 方法中,您创建了一个新的 Tk() 对象,而不是使用主应用程序的对象。
这就是为什么进度条界面关闭不掉的原因:应用程序的主循环与进度条界面的循环相互独立,无法退出两个窗口。
要解决该问题,您可以使用 `Toplevel()` 而不是新建一种 Tk() 对象。 Toplevel() 是一个子窗口,它依赖于完整的主窗口,当你关闭子窗口时,主窗口也能随之关闭,示例如下:
def run_gui(self):
self.run = tk.Toplevel()
self.run.title('正在运行')
self.run.geometry("400x200")
self.run.resizable(0, 0)
jdt = Progressbar(self.run, length=200, mode='indeterminate')
jdt.place(y=50, relx=0.5, anchor='center')
jdt.start()
label = tk.Label(self.run, text=' 正在连接,请稍等...',
font=('标楷体', 15))
label.place(relx=0.5, rely=0.5, anchor='center')
除此之外,您可能需要处理进度条界面的异常退出情况,例如添加关闭按钮来正常关闭进度条界面。 sfqxx 发表于 2023-5-15 20:03
在 `run_gui()` 方法中,您创建了一个新的 Tk() 对象,而不是使用主应用程序的对象。
这就是为什么进度 ...
我按您说的改了之后,点完按钮,进度条窗口根本不弹出了,,直到建立连接的方法运行完之后才和最终的窗口一起弹出
页:
[1]