用于接收数据的套接字的Tkinter线程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用于接收数据的套接字的Tkinter线程相关的知识,希望对你有一定的参考价值。
我正在为我的网络类工作,这是一个与服务器交互的客户端,该服务器托管由我们的教授编写的基于文本的游戏。
我几乎所有的一切都想通了,但我有一个主要问题,我不太了解python并且很难实现线程连续从服务器接收数据。
RuntimeError:主线程不在主循环中
这是我得到的错误,我相信这是因为tkinter必须始终在主线程中,并且它与我的接收函数冲突。我已经看到队列可能是这个问题的解决方案,但我无法理解如何在我的代码中实现这一点,任何帮助都将非常感谢。
from tkinter import *
import tkinter.simpledialog
from sys import exit
from struct import *
from socket import *
import threading
import tkinter.scrolledtext as tkst
skt = socket(AF_INET, SOCK_STREAM)
skt.connect(("domainname.com", 5191))
root = Tk()
def main():
thread = threading.Thread(target = recieve)
thread.start()
thread.join()
root.mainloop()
def start_func():
m = 6
def create_func():
m = 10
def change_func():
m = 2
print(m)
def fight_func():
m = 3
print(m)
def pvp_func():
m = 4
print(m)
def loot_func():
m = 5
skt.send(m)
print(m)
def leave_func():
m = 12
print(m)
def submit_value():
global userEntry
length = len(userEntry.get())
e1.delete(0, END)
class TestClient(Frame):
def __init__(self, master):
global userEntry
Frame.__init__(self, master)
self.pack()
for n in range(3):
self.grid_rowconfigure(n, weight=1)
for n in range(8):
self.grid_columnconfigure(n, weight=1)
self.Messg_text = tkst.ScrolledText(self,wrap = WORD, width=80)
self.Messg_text.grid(row=0, column=0, columnspan=8)
la1 = Label(self, text="Value entry:")
la1.grid(row=1, column=0)
userEntry = StringVar()
global e1
e1 = Entry(self, width=40, textvariable=userEntry)
e1.grid(row=1, column=1, columnspan=6)
e2 = Button(self, text="Enter", command=submit_value)
e1.delete(0, END)
e2.grid(row=1, column=5, columnspan=10)
b1 = Button(self, text="Start", width=10,padx=10,pady=10, command=start_func)
b1.grid(row=2, column=0)
b0 = Button(self, text="Create Character", width=10,padx=10,pady=10, command=create_func)
b0.grid(row=2, column=1)
b2 = Button(self, text="Change Room", width=10,padx=10,pady=10, command=change_func)
b2.grid(row=2, column=3)
b3 = Button(self, text="FIGHT", width=10,padx=10,pady=10, command=fight_func)
b3.grid(row=2, column=4)
b4 = Button(self, text="PvP FIGHT", width=10,padx=10,pady=10, command=pvp_func)
b4.grid(row=2, column=5)
b5 = Button(self, text="Loot", width=10,padx=10,pady=10, command=loot_func)
b5.grid(row=2, column=6)
b6 = Button(self, text="Leave", width=10,padx=10,pady=10, command=leave_func)
b6.grid(row=2, column=7)
tw = TestClient(root)
def recieve():
while(True):
mesg_type = skt.recv(1)
if(mesg_type == b'x01'):
msg_Len = skt.recv(2)
msg_int_Len = struct.unpack('h',msg_Len)
Recip_Name = skt.recv(32)
sender_Name = skt.recv(32)
mesg = skt.recv(msg_int_Len)
PostMessage(Recip_Name,sender_Name,mesg)
elif(mesg_type == b'x0b'):
init_Points = skt.recv(2)
statLim = skt.recv(2)
descriptLen = skt.recv(2)
descriptLen = unpack('h',descriptLen)
gameDiscript = skt.recv(descriptLen[0])
print(gameDiscript.decode("utf-8"))
Post11Message(str(gameDiscript)[0:-2])
def PostMessage(name, senderName, Message):
tw.Messg_text.insert(INSERT,Message)
def Post11Message(gameDiscript):
tw.Messg_text.insert(INSERT,gameDiscript)
main()
答案
我很确定你遇到问题的原因是因为thread.join
在做下一步之前等待线程完成。所以,在你的情况下,你从来没有真正调用root.mainloop()
。解决方案就是取出主要的thread.join
线。
此外,在您的情况下,队列是必要的,因为您无法在另一个线程中更改Tkinter小部件。
没有太多的编辑,这就是你的代码的样子。
from tkinter import *
import tkinter.simpledialog
from sys import exit
from struct import *
from socket import *
import Queue
import threading
import tkinter.scrolledtext as tkst
skt = socket(AF_INET, SOCK_STREAM)
skt.connect(("domainname.com", 5191))
root = Tk()
def main():
thread = threading.Thread(target = recieve)
thread.start()
root.mainloop()
def start_func():
m = 6
def create_func():
m = 10
def change_func():
m = 2
print(m)
def fight_func():
m = 3
print(m)
def pvp_func():
m = 4
print(m)
def loot_func():
m = 5
skt.send(m)
print(m)
def leave_func():
m = 12
print(m)
def submit_value():
global userEntry
length = len(userEntry.get())
e1.delete(0, END)
class TestClient(Frame):
def __init__(self, master):
global userEntry
Frame.__init__(self, master)
self.pack()
for n in range(3):
self.grid_rowconfigure(n, weight=1)
for n in range(8):
self.grid_columnconfigure(n, weight=1)
self.Messg_text = tkst.ScrolledText(self,wrap = WORD, width=80)
self.Messg_text.grid(row=0, column=0, columnspan=8)
la1 = Label(self, text="Value entry:")
la1.grid(row=1, column=0)
userEntry = StringVar()
global e1
e1 = Entry(self, width=40, textvariable=userEntry)
e1.grid(row=1, column=1, columnspan=6)
e2 = Button(self, text="Enter", command=submit_value)
e1.delete(0, END)
e2.grid(row=1, column=5, columnspan=10)
b1 = Button(self, text="Start", width=10,padx=10,pady=10, command=start_func)
b1.grid(row=2, column=0)
b0 = Button(self, text="Create Character", width=10,padx=10,pady=10, command=create_func)
b0.grid(row=2, column=1)
b2 = Button(self, text="Change Room", width=10,padx=10,pady=10, command=change_func)
b2.grid(row=2, column=3)
b3 = Button(self, text="FIGHT", width=10,padx=10,pady=10, command=fight_func)
b3.grid(row=2, column=4)
b4 = Button(self, text="PvP FIGHT", width=10,padx=10,pady=10, command=pvp_func)
b4.grid(row=2, column=5)
b5 = Button(self, text="Loot", width=10,padx=10,pady=10, command=loot_func)
b5.grid(row=2, column=6)
b6 = Button(self, text="Leave", width=10,padx=10,pady=10, command=leave_func)
b6.grid(row=2, column=7)
#Data Queue
self.queue = Queue.Queue()
self.queue_check()
def queue_check(self):
try:
#Inserts Data
text = self.queue.get_nowait(0)
self.Messg_text.insert(INSERT, text)
#If Nothing In Queue
except Queue.Empty:
#Repeats Itself After 100 ms
self.after(100, self.queue_check)
tw = TestClient(root)
def recieve():
while(True):
mesg_type = skt.recv(1)
if(mesg_type == b'x01'):
msg_Len = skt.recv(2)
msg_int_Len = struct.unpack('h',msg_Len)
Recip_Name = skt.recv(32)
sender_Name = skt.recv(32)
mesg = skt.recv(msg_int_Len)
PostMessage(Recip_Name,sender_Name,mesg)
elif(mesg_type == b'x0b'):
init_Points = skt.recv(2)
statLim = skt.recv(2)
descriptLen = skt.recv(2)
descriptLen = unpack('h',descriptLen)
gameDiscript = skt.recv(descriptLen[0])
print(gameDiscript.decode("utf-8"))
Post11Message(str(gameDiscript)[0:-2])
def PostMessage(name, senderName, Message):
#Adds Message To Queue
tw.queue.put(Message)
def Post11Message(gameDiscript):
#Adds gameDiscript to Queue
tw.queue.put(gameDiscript)
main()
以上是关于用于接收数据的套接字的Tkinter线程的主要内容,如果未能解决你的问题,请参考以下文章