Python |我该如何将其放入多个线程中并允许GUI更新



我正在开发一个带有GUI的子警报系统,我遇到的问题是GUI冻结,因为我正在运行一个检查聊天的循环。

我该如何将现有的GUI和聊天代码合并到一个系统中,在这个系统中,GUI不会冻结,文本字段将根据控制台的内容进行更新。

# Import Resources #
import re
import socket
import importlib
from Tkinter import *
from modules.IRCCommands import *
recentSub= 'N/A'
# Close application #
def Close_Window():
    frmMain.destroy()
# Main application #
def Start():
# List info in the shell #
terminal.insert('1.0', 'Subscriber Alert ver. 1.5 | Created & Modified by RubbixCube' + "n")
terminal.insert("end", 'Important Information:' + "n")
terminal.insert("end", 'HOST = ' + HOST + "n")
terminal.insert("end", 'PORT = ' + str(PORT) + "n")
for c in CHAN:
    terminal.insert("end", 'CHAN = ' + c + "n")
terminal.insert("end", 'n' + "n")
terminal.insert("end", 'Chat:' + "n")
frmMain.update_idletasks
## Define basic Functions ##
def get_sender(msg):
    result = ""
    for char in msg:
        if (char == "!"):
            break
        if (char != ":"):
            result += char
    return result
def get_message(msg):
    result = ""
    i = 3
    length = len(msg)
    while i < length:
        result += msg[i] + " "
        i += 1
    result = result.lstrip(':')
    return result
## End Helper Functions ##
def parse_message(channel, user, msg):
    if len(msg) >= 1:
        msg = msg.split(' ')
        frmMain.update_idletasks

con = socket.socket()
con.connect((HOST, PORT))
send_pass(con, PASS)
send_nick(con, NICK)
for c in CHAN:
    join_channel(con, c)
data = ""

while True:
    try:
        data = data+con.recv(1024)
        data_split = re.split("rn", data)
        data = data_split.pop()
        for line in data_split:
            #print(line)
            #line = str.rstrip(line)
            line = str.split(line)
            # Stay connected to the server #
            if (len(line) >= 1):
                if (line[0] == 'PING'):
                    send_pong(con, line[1])
                if (line[1] == 'PRIVMSG'):
                    sender = get_sender(line[0])
                    message = get_message(line)
                    channel = line[2]
                    terminal.insert("end", sender + ": " + message + "n")
                    frmMain.update_idletasks
                    # Welcome new subs #
                    if (sender == "rubbixcube"):
                        def excuteCommand(con, channel, user, message, isMod, isSub):
                            msg = str.split(message)
                            if re.match('w* subscribed for w* months in a row!', message):
                                recentSub = msg[0]
                                print(recentSub)
                                send_message(con, channel, 'Thanks for your continued contribution %s!' % msg[0])
                            elif re.match('w* just subscribed!', message):
                                recentSub = msg[0]
                                print(recentSub)
                                send_message(con, channel, str.format('Welcome to the channel %s. Enjoy your stay!' % msg[0]))
                            elif (re.match('w* viewers resubscribed while you were away!', message)):
                                send_message(con, channel, 'Thanks for subscribing!')
                        excuteCommand(con, channel, sender, message, False, False)
                    parse_message(channel, sender, message)
    except socket.error:
        print("Socket died")
    except socket.timeout:
       print("Socket timeout")

## GUI ##
# Start loop of program
frmMain = Tk()
app = Frame(frmMain)
app.grid()
# Configure GUI
frmMain.title('Subscriber Alert ver. 2.0')
frmMain.geometry('455x357')
frmMain.resizable(0,0)
# Button
start = Button(app, text='     Start     ')
start['command'] = Start
start.grid(row=0, column=0, pady=5)
close = Button(app, text='      Exit       ')
close['command'] = Close_Window
close.grid(row=0, column=2, pady=5)

# Label
sub_lbl = Label(app, text='Most Recent Subscriber:')
sub_lbl.grid(row=1, column=0, columnspan=2, pady=10, padx=5)
sub_lbl2 = Label(app, text=recentSub)
sub_lbl2.grid(row=1, column=1, columnspan=3, pady=10, padx=5)

# Console
terminal = Text(app, width=56, height=17, wrap=WORD)
terminal.grid(row=3, column=0, columnspan=3)

# End loop of Program
frmMain.mainloop()

感谢

"GUI冻结问题"是Python中网络应用程序的常见问题。通常,您的网络套接字或流被称为阻塞,或者超时被设置为长,管道和io流没有完成刷新,或者GUI的reactor没有设置为与网络io reactor(mainloop)一起工作。

典型的解决方案是使用队列对网络io进行线程处理。Queues(),或者使用支持事件的网络包,因为GUI是事件驱动的。Twisted和asyncio提供事件驱动的io。或者,正如现在经常提供的那样,一些GUI包和网络包有"reactor"(主循环),可以用来与其他特定的包一起工作。Twisted有TKinter和wx的反应器。

最新更新