不允许函数使Tk GUI挂起

时间:2014-03-12 13:24:22

标签: python multithreading sockets tkinter hang

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

  1. 连接到我的MySQL数据库并使用IP提取某些表 地址
  2. 将地址存储在列表中
  3. 对于列表中的每个IP,根据用户首选项,通过套接字,我发送或接收文件到该IP地址
  4. 所以,假设我有一个send()函数,当我从另一个函数按下一个Button时它会启动它并执行此操作:

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

    现在,当服务器处于活动状态时,代码可以正常工 但是,目前我正在进行代码轮询,当服务器未启动,客户端无法连接时,代码执行速度相当慢,并且GUI挂起(例如,当列表有25个IP-s时,函数需要连接到哪个)。 / p>

    所以我想要做的是 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()
    

1 个答案:

答案 0 :(得分:0)

在多处理中启动多个操作相对简单。我通常会把所有东西都放在一个班级来保持一切联系。需要注意的是,只创建一个TK()类实例。不止一个会导致问题。 time.sleep()用于start_running函数而不是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()