鱼C论坛

 找回密码
 立即注册
查看: 801|回复: 4

[已解决]tkinter 求助

[复制链接]
发表于 2023-5-15 19:13:51 | 显示全部楼层 |阅读模式
10鱼币
为了方便非技术人员,连接高速公路超速提示的电子大屏,自己写的一个开关
由于连接四块屏幕的地址会出现偶尔的异常,在连接的过程中,开关的界面会卡死,于是设计当点击按钮时关掉初始的开关界面,打开一个假的进度条界面,当连接过程完毕并且报错时,,关掉进度条界面,弹出最终通知界面,正常建立连接时,则只需要关闭进度条界面即可。。但是,我的进度条界面关闭不掉,一直在运行,请大佬帮忙看看,怎么改一改,或者优化一下
  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter.ttk import Progressbar
  4. import socket


  5. class Application(tk.Tk):
  6.     def __init__(self):
  7.         super().__init__()

  8.         self.ip = ["61.18.238.7", "61.18.238.8", "61.18.238.9", "61.18.238.10"]
  9.         self.port = 1234
  10.         self.out = ["setr=1", "setr=0"]

  11.         self.title('开关控制')
  12.         self.geometry('600x300')
  13.         self.resizable(0,0)
  14.         tk.Button(self, text='打开',
  15.                 font=('楷体', 30),
  16.                 anchor='center', command=self.open,
  17.                 height=2, width=8, bd=6).place(relx=0.15, rely=0.3)
  18.         tk.Button(self, text='关闭',
  19.                 font=('楷体', 30),
  20.                 anchor='center', command=self.close,
  21.                 height=2, width=8, bd=6).place(relx=0.55, rely=0.3)
  22.         self.mainloop()

  23.     def run_gui(self):
  24.         self.run = tk.Tk()
  25.         self.run.title('正在运行')
  26.         self.run.geometry("400x200")
  27.         self.run.resizable(0, 0)

  28.         jdt = Progressbar(self.run, length=200, mode='indeterminate')
  29.         jdt.place(y=50, relx=0.5, anchor='center')
  30.         jdt.start()

  31.         label = tk.Label(self.run, text=' 正在连接,请稍等...',
  32.                          font=('标楷体', 15))
  33.         label.place(relx=0.5, rely=0.5, anchor='center')
  34.         self.run.mainloop()

  35.     def end_gui(self, res_str):
  36.         win = tk.Tk()
  37.         win.geometry('0x0+999999+0')
  38.         messagebox.showerror('开关控制', ' {}失败,请联系工作人员!'.format(res_str))
  39.         win.destroy()

  40.     def connect(self, ip, port, out):
  41.         for i in ip:
  42.             tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  43.             tcp_client.connect((i, port))
  44.             outdata = out
  45.             tcp_client.send(outdata.encode())
  46.             recdata = tcp_client.recv(1024)
  47.             print("server:", recdata.decode())
  48.             tcp_client.close()

  49.     def open(self):
  50.         self.destroy()
  51.         self.run_gui()
  52.         try:
  53.             self.connect(self.ip, self.port, self.out[0])
  54.         except:
  55.             self.end_gui("打开")
  56.         finally:
  57.             self.run.destroy()


  58.     def close(self):
  59.         self.destroy()
  60.         self.run_gui()
  61.         try:
  62.             self.connect(self.ip, self.port, self.out[1])
  63.         except:
  64.             self.end_gui("关闭")
  65.         finally:
  66.             self.run.destroy()


  67. if __name__ == "__main__":
  68.     app = Application()
复制代码
最佳答案
2023-5-15 19:13:52
你的代码中有一个主要的问题:你在  run_gui  和  end_gui  函数中都使用了  mainloop() ,这在 Tkinter 中可能会导致问题,因为它启动了一个新的事件循环。在同一个应用程序中,应该只有一个 mainloop()。

你的代码中的每个窗口(root 和 Toplevel)应该只有一个主窗口调用 mainloop()。其他的窗口应该是这个主窗口的子窗口。当主窗口关闭时,所有的子窗口都会关闭。

为了解决你的问题,我将你的  run_gui  和  end_gui  函数中的窗口更改为  Toplevel 。这样,你就可以在主窗口中调用 mainloop(),并在需要时打开和关闭子窗口。

在下面的代码中,我也将  connect  方法的  try/except  语句更改为  try/except/else 。 else  语句将在没有异常的情况下执行,所以在  connect  方法成功执行后,进度条窗口将被销毁。

这是你的代码的修改版:

  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter.ttk import Progressbar
  4. import socket


  5. class Application(tk.Tk):
  6.     def __init__(self):
  7.         super().__init__()

  8.         self.ip = ["61.18.238.7", "61.18.238.8", "61.18.238.9", "61.18.238.10"]
  9.         self.port = 1234
  10.         self.out = ["setr=1", "setr=0"]

  11.         self.title('开关控制')
  12.         self.geometry('600x300')
  13.         self.resizable(0,0)
  14.         tk.Button(self, text='打开',
  15.                 font=('楷体', 30),
  16.                 anchor='center', command=self.open,
  17.                 height=2, width=8, bd=6).place(relx=0.15, rely=0.3)
  18.         tk.Button(self, text='关闭',
  19.                 font=('楷体', 30),
  20.                 anchor='center', command=self.close,
  21.                 height=2, width=8, bd=6).place(relx=0.55, rely=0.3)

  22.     def run_gui(self):
  23.         self.run = tk.Toplevel(self)
  24.         self.run.title('正在运行')
  25.         self.run.geometry("400x200")
  26.         self.run.resizable(0, 0)

  27.         jdt = Progressbar(self.run, length=200, mode='indeterminate')
  28.         jdt.place(y=50, relx=0.5, anchor='center')
  29.         jdt.start()

  30.         label = tk.Label(self.run, text=' 正在连接,请稍等...',
  31.                          font=('标楷体', 15))
  32.         label.place(relx=0.5, rely=0.5, anchor='center')

  33.     def end_gui(self, res_str):
  34.         win = tk.Toplevel(self)
  35.         win.geometry('0x0+999999+0')
  36.         messagebox.showerror('开关控制', ' {}失败,请联系工作人员!'.format(res_str))
  37.         win.destroy()

  38.     def connect(self, ip, port, out):
  39.         for i in ip:
  40.             tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  41.             tcp_client.connect((i, port))
  42.             outdata = out
  43.             tcp_client.send(outdata.encode())
  44.             recdata = tcp_client.recv(1024)
  45.             print("server:", recdata.decode())
  46.             tcp_client.close()

  47.     def open(self):
  48.         self.withdraw()
  49.         self.run_gui()
  50.         try:
  51.             self.connect(self.ip, self.port, self.out[0])
  52.         except:
  53.             self.end_gui("打开")
  54.         else:
  55.             self.run.destroy()
  56.             self.deiconify()


  57.     def close(self):
  58.         self.withdraw()
  59.         self.run_gui()
  60.         try:
  61.             self.connect(self.ip, self.port, self.out[1])
  62.         except:
  63.             self.end_gui("关闭")
  64.         else:
  65.             self.run.destroy()
  66.             self.deiconify()


  67. if __name__ == "__main__":
  68.     app = Application()
  69.     app.mainloop()
复制代码

在这个修改后的代码中,我使用了  withdraw()  方法隐藏主窗口,然后显示进度条窗口。一旦连接建立(或连接尝试失败),我销毁进度条窗口并使用  deiconify()  方法显示主窗口。

请注意,我将  mainloop()  方法移动到了程序的最后,这样就只有一个  mainloop()  在程序中运行。

这样的修改应该可以解决你的问题。如果你还有其他问题,欢迎继续提问。

最佳答案

查看完整内容

你的代码中有一个主要的问题:你在 run_gui 和 end_gui 函数中都使用了 mainloop() ,这在 Tkinter 中可能会导致问题,因为它启动了一个新的事件循环。在同一个应用程序中,应该只有一个 mainloop()。 你的代码中的每个窗口(root 和 Toplevel)应该只有一个主窗口调用 mainloop()。其他的窗口应该是这个主窗口的子窗口。当主窗口关闭时,所有的子窗口都会关闭。 为了解决你的问题,我将你的 run_gui 和 end_gui 函 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-15 19:13:52 | 显示全部楼层    本楼为最佳答案   
你的代码中有一个主要的问题:你在  run_gui  和  end_gui  函数中都使用了  mainloop() ,这在 Tkinter 中可能会导致问题,因为它启动了一个新的事件循环。在同一个应用程序中,应该只有一个 mainloop()。

你的代码中的每个窗口(root 和 Toplevel)应该只有一个主窗口调用 mainloop()。其他的窗口应该是这个主窗口的子窗口。当主窗口关闭时,所有的子窗口都会关闭。

为了解决你的问题,我将你的  run_gui  和  end_gui  函数中的窗口更改为  Toplevel 。这样,你就可以在主窗口中调用 mainloop(),并在需要时打开和关闭子窗口。

在下面的代码中,我也将  connect  方法的  try/except  语句更改为  try/except/else 。 else  语句将在没有异常的情况下执行,所以在  connect  方法成功执行后,进度条窗口将被销毁。

这是你的代码的修改版:

  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter.ttk import Progressbar
  4. import socket


  5. class Application(tk.Tk):
  6.     def __init__(self):
  7.         super().__init__()

  8.         self.ip = ["61.18.238.7", "61.18.238.8", "61.18.238.9", "61.18.238.10"]
  9.         self.port = 1234
  10.         self.out = ["setr=1", "setr=0"]

  11.         self.title('开关控制')
  12.         self.geometry('600x300')
  13.         self.resizable(0,0)
  14.         tk.Button(self, text='打开',
  15.                 font=('楷体', 30),
  16.                 anchor='center', command=self.open,
  17.                 height=2, width=8, bd=6).place(relx=0.15, rely=0.3)
  18.         tk.Button(self, text='关闭',
  19.                 font=('楷体', 30),
  20.                 anchor='center', command=self.close,
  21.                 height=2, width=8, bd=6).place(relx=0.55, rely=0.3)

  22.     def run_gui(self):
  23.         self.run = tk.Toplevel(self)
  24.         self.run.title('正在运行')
  25.         self.run.geometry("400x200")
  26.         self.run.resizable(0, 0)

  27.         jdt = Progressbar(self.run, length=200, mode='indeterminate')
  28.         jdt.place(y=50, relx=0.5, anchor='center')
  29.         jdt.start()

  30.         label = tk.Label(self.run, text=' 正在连接,请稍等...',
  31.                          font=('标楷体', 15))
  32.         label.place(relx=0.5, rely=0.5, anchor='center')

  33.     def end_gui(self, res_str):
  34.         win = tk.Toplevel(self)
  35.         win.geometry('0x0+999999+0')
  36.         messagebox.showerror('开关控制', ' {}失败,请联系工作人员!'.format(res_str))
  37.         win.destroy()

  38.     def connect(self, ip, port, out):
  39.         for i in ip:
  40.             tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  41.             tcp_client.connect((i, port))
  42.             outdata = out
  43.             tcp_client.send(outdata.encode())
  44.             recdata = tcp_client.recv(1024)
  45.             print("server:", recdata.decode())
  46.             tcp_client.close()

  47.     def open(self):
  48.         self.withdraw()
  49.         self.run_gui()
  50.         try:
  51.             self.connect(self.ip, self.port, self.out[0])
  52.         except:
  53.             self.end_gui("打开")
  54.         else:
  55.             self.run.destroy()
  56.             self.deiconify()


  57.     def close(self):
  58.         self.withdraw()
  59.         self.run_gui()
  60.         try:
  61.             self.connect(self.ip, self.port, self.out[1])
  62.         except:
  63.             self.end_gui("关闭")
  64.         else:
  65.             self.run.destroy()
  66.             self.deiconify()


  67. if __name__ == "__main__":
  68.     app = Application()
  69.     app.mainloop()
复制代码

在这个修改后的代码中,我使用了  withdraw()  方法隐藏主窗口,然后显示进度条窗口。一旦连接建立(或连接尝试失败),我销毁进度条窗口并使用  deiconify()  方法显示主窗口。

请注意,我将  mainloop()  方法移动到了程序的最后,这样就只有一个  mainloop()  在程序中运行。

这样的修改应该可以解决你的问题。如果你还有其他问题,欢迎继续提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-5-15 19:58:48 | 显示全部楼层
本帖最后由 来自星星的小明 于 2023-5-15 19:59 编辑
isdkz 发表于 2023-5-15 19:24
你的代码中有一个主要的问题:你在  run_gui  和  end_gui  函数中都使用了  mainloop() ,这在 Tkinter 中 ...


Snipaste_2023-05-15_19-55-44.png
大佬,不行啊,点完按钮,不弹出进度条窗口,,知道连接建立完毕,进度条窗口和最后的通知窗口一起弹出了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-15 20:03:14 | 显示全部楼层
在 `run_gui()` 方法中,您创建了一个新的 Tk() 对象,而不是使用主应用程序的对象。

这就是为什么进度条界面关闭不掉的原因:应用程序的主循环与进度条界面的循环相互独立,无法退出两个窗口。

要解决该问题,您可以使用 `Toplevel()` 而不是新建一种 Tk() 对象。 Toplevel() 是一个子窗口,它依赖于完整的主窗口,当你关闭子窗口时,主窗口也能随之关闭,示例如下:

  1. def run_gui(self):
  2.     self.run = tk.Toplevel()
  3.     self.run.title('正在运行')
  4.     self.run.geometry("400x200")
  5.     self.run.resizable(0, 0)

  6.     jdt = Progressbar(self.run, length=200, mode='indeterminate')
  7.     jdt.place(y=50, relx=0.5, anchor='center')
  8.     jdt.start()

  9.     label = tk.Label(self.run, text=' 正在连接,请稍等...',
  10.                      font=('标楷体', 15))
  11.     label.place(relx=0.5, rely=0.5, anchor='center')
复制代码

除此之外,您可能需要处理进度条界面的异常退出情况,例如添加关闭按钮来正常关闭进度条界面。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-5-15 20:37:13 | 显示全部楼层
sfqxx 发表于 2023-5-15 20:03
在 `run_gui()` 方法中,您创建了一个新的 Tk() 对象,而不是使用主应用程序的对象。

这就是为什么进度 ...

我按您说的改了之后,点完按钮,进度条窗口根本不弹出了,,直到建立连接的方法运行完之后才和最终的窗口一起弹出
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-5 18:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表