在Python中,如何将代码放入多个线程,同时使GUI能够更新? 正在开发一个带有GUI的子警报系统,遇到使GUI冻结的问题,是因为运行了一个循环来检查聊天内容。 如何将现有的GUI和聊天代码合并到一个系统中,使GUI不会冻结,并且文本字段能够实时更新控制台中的内容?
2. 解决方案
使用多线程和Tkinter来实现GUI实时更新而不冻结。Tkinter是一个Python GUI库,可以创建用户界面。多线程允许代码在多个线程中同时运行,从而避免GUI冻结。
以下是如何使用多线程和Tkinter来实现GUI实时更新而不冻结的代码:
导入资源
import re
import socket
import importlib
from Tkinter import *
from modules.IRCCommands import *
定义全局变量
recentSub = 'N/A'
定义函数
# 关闭应用程序
def Close_Window():
frmMain.destroy()
# 启动应用程序
def Start():
## 将列表信息显示在控制台中 ##
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
## 定义基本函数 ##
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
## 结束辅助函数 ##
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("\r\n", data)
data = data_split.pop()
for line in data_split:
#print(line)
#line = str.rstrip(line)
line = str.split(line)
# 保持与服务器的连接 #
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
# 欢迎新订阅者 #
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
## GUI ##
# 启动程序循环
frmMain = Tk()
app = Frame(frmMain)
app.grid()
# 配置GUI
frmMain.title('Subscriber Alert ver. 2.0')
frmMain.geometry('455x357')
frmMain.resizable(0,0)
# 按钮
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)
# 标签
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)
# 控制台
terminal = Text(app, width=56, height=17, wrap=WORD)
terminal.grid(row=3, column=0, columnspan=3)
# 结束程序循环
frmMain.mainloop()
代码在建立套接字连接并发送密码和昵称后,即开始一个无限循环,以便持续接收服务器发来的消息。
然后,GUI部分使用了Tkinter库,其中包括按钮、标签和文本框等控件,以便用户可以与程序进行交互。
最后,程序的主循环(即frmMain.mainloop())使程序继续运行,直到用户关闭窗口。在主循环中,程序会不断更新GUI,以便用户可以实时看到服务器发来的消息。