【问题标题】:Don't allow function to make Tk GUI hang不允许函数使 Tk GUI 挂起
【发布时间】:2014-03-12 13:24:22
【问题描述】:

所以我有一个程序正在执行以下操作:

  1. 连接到我的 MySQL 数据库并使用 IP 提取某些表 地址
  2. 在列表中存储地址
  3. 对于列表中的每个 IP,根据用户偏好,我通过套接字向该 IP 地址发送或接收文件

所以,假设我有一个 send() 函数,它在我按下另一个函数的按钮时开始,它会这样做:

for host in IP_list:
    socket.connect((host,5005))...
    socket.send(data)...

现在,当服务器处于活动状态时,代码可以正常工作并且所有内容都非常快速地复制。 但是,目前我正在处理代码轮询,当服务器未启动且客户端无法连接时,代码执行速度相当慢,并且 GUI 挂起(例如,当列表有 25ish IP-s 到该函数需要连接时)。

所以我想做的是 socket.connect((host,5005)) 在另一个线程中(或任何不挂我的 GUI)

现在,我尝试使用线程,但它的行为很奇怪。它在 tkinter 上从来都不能很好地工作,因为除了上面的代码行之外,我在该函数中还有 tk.progressbar 和其他一些 Tk 东西。

我不知道如何使用多处理来做到这一点,而且显然它对 IO 挂起没有影响。

谁能给我一些想法?

这是我尝试使用线程的方法:

def connect():
    global host
    global socket
    socket.connect((host,5005))


def my_original_function():
    global host
    global socket
    t1=threading.Thread(target=connect)
    for host in IP_list:
        t1.start()
        t1.join()

【问题讨论】:

  • 你能告诉我们你是如何尝试线程的吗?

标签: python multithreading sockets tkinter freeze


【解决方案1】:

在多处理中启动不止一件事是相对简单的。我通常将所有内容都放在一个班级中以保持所有内容之间的联系。一个警告是只创建一个 TK() 类实例。不止一个会导致问题。在 start_running 函数中使用 time.sleep() 代替 after() 来模拟一个线程挂起。如果您打算使用 Tkinter 并进行更高级的编程,恕我直言,使用类将简化您的生活。

from multiprocessing import Process
import time

try:
    import Tkinter as tk    ## Python 2.x
except:
    import tkinter as tk    ## Python 3.x

class ProgressBar():
    def __init__(self, root):
        self.root=root
        self.root.geometry("75x50+900+100")
        self.ctr=25

    def mainloop(self):
        self.root.mainloop()

    def start_countdown(self):
        """ a separate process in a separate GUI
        """
        self.root.withdraw()
        self.top_count=tk.Toplevel(self.root)
        self.top_count.geometry("75x50+750+50")
        self.label_ctr = tk.IntVar()
        self.label_ctr.set(self.ctr)
        label = tk.Label(self.top_count, textvariable=self.label_ctr)
        label.pack()
        if self.ctr > 0:
            self.top_count.after(750, self.update)

    def start_running(self):
        """ create the progress bar widget
        """
        self.top=tk.Toplevel(self.root, takefocus=True)
        self.top.title("Progress Bar")
        self.top.geometry("+700+200")
        canvas = tk.Canvas(self.top, width=261, height=60, bg='lightgray')
        canvas.pack()

        rc2 = canvas.create_rectangle(15, 20, 243, 50, outline='blue',                                       fill='lightblue')
        rc1 = canvas.create_rectangle(24, 20, 34, 50, outline='white',                                       fill='blue')

        total=100
        x = 5
        ## only use after() while the countdown is running (self.ctr > 0)
        ## to avoid a dangling after() when the program terminates
        while self.ctr:        ## move the small rectangle +5 or -5 units
            total += x
            if total > 311:
                x = -5
            elif total < 100:
                x = 5
            time.sleep(0.2)
            canvas.move(rc1, x, 0)
            canvas.update()

    def update(self):
        self.ctr -= 1
        self.label_ctr.set(self.ctr)

        if self.ctr > 0:
            self.top_count.after(750, self.update)
        else:
            ## sleep to allow any remaining after() to execute
            ## can also use self.root.after_cancel(id)
            self.top_count.after(500, self.root.destroy) ## destroy root when ctr==0

root = tk.Tk()

PB=ProgressBar(root)
pr1=Process(target=PB.start_countdown(), args=())
pr1.start()

pr2=Process(target=PB.start_running(), args=())
pr2.start()

## start mainloop in a separate process as a function of the class
## don't know if this is really necessary or not
## the theory is, it is detached from the other 2 processes and so
##    can react to both independently
## also the mainloop() process can be killed=shut down properly
pr3=Process(target=PB.mainloop(), args=())
pr3.start()

## safety clean up
pr1.terminate()
pr2.terminate()
pr3.terminate()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-31
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多