Python 3 使用 Tkinter 的多线程

Python 3 Multi-Threading with Tkinter

我一直在编写一些代码,这些代码最终会从远程和本地(在代码本身内)源获取命令,然后执行并使用 tkinter 显示结果。

我目前遇到的问题是,当我 运行 使用线程和队列的代码出现此错误时,我尝试将 gui 代码放在线程的 for 循环下方的底部,但这有发生另一个错误。

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Python34\lib\threading.py", line 921, in _bootstrap_inner
    self.run()
  File "C:\Python34\lib\threading.py", line 869, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/Eddy/Programing/Python/Sockets/GUI Server.py", line 60, in threader
    t_visuals()
  File "C:/Users/Eddy/Programing/Python/Sockets/GUI Server.py", line 49, in t_visuals
    label = Label(root, width=70, height=30,relief=RIDGE,bd=5,bg="white",textvariable=v,anchor=NW,justify= LEFT,font=("Times New Roman", 12)).grid(row=1,column=0)
  File "C:\Python34\lib\tkinter\__init__.py", line 2604, in __init__
    Widget.__init__(self, master, 'label', cnf, kw)
  File "C:\Python34\lib\tkinter\__init__.py", line 2122, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
RuntimeError: main thread is not in main loop

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Python34\lib\threading.py", line 921, in _bootstrap_inner
    self.run()
  File "C:\Python34\lib\threading.py", line 869, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/Eddy/Programing/Python/Sockets/GUI Server.py", line 58, in threader
    t_connections()
  File "C:/Users/Eddy/Programing/Python/Sockets/GUI Server.py", line 43, in t_connections
    sLog_update("waiting for connection...")
  File "C:/Users/Eddy/Programing/Python/Sockets/GUI Server.py", line 40, in sLog_update
    v.set(g)
  File "C:\Python34\lib\tkinter\__init__.py", line 263, in set
    return self._tk.globalsetvar(self._name, value)
RuntimeError: main thread is not in main loop

这是代码:

from socket import *
import time
from tkinter import *
import threading
from queue import Queue

#server setup
HOST = ''
PORT = 24601
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)

#Window Setup
HEIGHT = 720
WIDTH = 1280
root = Tk()
root.title("Server Controler")
root.geometry("1280x720")

#Variables needed
v =StringVar()
f =StringVar()
g = "" #Server update log

#locked variables
sLog_lock = threading.Lock()

#t_ means threaded
def sLog_update(self):
    with sLog_lock:
        global g
        currentTime = str("["+time.ctime()+"] ")
        g+=str(currentTime)
        g+=str(self)
        g+=str("\n")
        v.set(g)

def t_connections():
    sLog_update("waiting for connection...")
    tcpCliSock, addr = tcpSerSock.accept()
    avr = "connected from: " + str(addr)
    sLog_update(avr)

def t_visuals():
    label = Label(root, width=70, height=30,relief=RIDGE,bd=5,bg="white",textvariable=v,anchor=NW,justify= LEFT,font=("Times New Roman", 12)).grid(row=1,column=0)
    entry = Entry(root, width=105,relief=RIDGE,bd=5,textvariable=f).grid(row=2,column=0)
    button = Button(root,command= lambda:sLog_update(f.get()),text="send").grid(row=3,column=0)
    mainloop()

def threader():
    worker = q.get()
    print(worker)
    if worker == 1:
        t_connections()
    elif worker == 0:
        t_visuals()

q =Queue()

for x in range(2):
    t = threading.Thread(target=threader)
    t.daemon = True
    t.start()

for worker in range(20):
    q.put(worker)

q.join()

您可以通过将所有 GUI 代码保留在主线程中来解决此问题。