如何实现两个Tkinter GUI脚本间的变量交互与通信?
跨Tkinter脚本通信解决方案
方案一:多进程+队列(推荐)
Tkinter的mainloop是单线程阻塞的,多进程能让两个GUI独立运行,通过multiprocessing.Queue安全传递数据,完全保留原有目录结构和依赖文件。
步骤1:重构GUI为类结构
把每个GUI封装成类,避免全局变量冲突,同时方便进程调用。
修改后的gui1.py
from tkinter import * from multiprocessing import Queue class GUI1: def __init__(self, data_queue): self.begin = Tk() self.begin.title("Window 1") self.data_queue = data_queue self.textBox = Text(self.begin) self.button = Button(self.begin, text="发送数据到Window2", command=self.send_data) self.textBox.grid(row=0) self.button.grid(row=1) def send_data(self): # 获取输入框内容并放入队列 content = self.textBox.get("1.0", END).strip() if content: self.data_queue.put(content) def run(self): self.begin.mainloop() if __name__ == "__main__": # 单独运行时的测试逻辑 q = Queue() app = GUI1(q) app.run()
修改后的gui2.py
from tkinter import * from multiprocessing import Queue import threading class GUI2: def __init__(self, data_queue): self.begin = Tk() self.begin.title("Window 2") self.data_queue = data_queue self.textBox = Text(self.begin) self.textBox.grid(row=0) # 启动监听队列的线程,不阻塞mainloop self.listen_thread = threading.Thread(target=self.listen_queue, daemon=True) self.listen_thread.start() def listen_queue(self): while True: data = self.data_queue.get() # 用after把UI更新抛回Tkinter主线程,避免线程安全问题 self.begin.after(0, self.update_text, data) def update_text(self, data): self.textBox.insert(END, f"收到数据:{data}\n") def run(self): self.begin.mainloop() if __name__ == "__main__": # 单独运行时的测试逻辑 q = Queue() app = GUI2(q) app.run()
步骤2:创建启动脚本
在根目录新建start_both.py,用来同时启动两个GUI进程:
from multiprocessing import Process, Queue import gui1 import gui2 if __name__ == "__main__": # 创建进程间共享的队列 data_queue = Queue() # 启动两个GUI进程 p1 = Process(target=lambda: gui1.GUI1(data_queue).run()) p2 = Process(target=lambda: gui2.GUI2(data_queue).run()) p1.start() p2.start() p1.join() p2.join()
运行方式
直接执行python start_both.py,两个窗口会同时启动,点击Window1的按钮,输入内容会同步到Window2的文本框中。
方案二:Socket通信(适合复杂场景)
如果需要跨机器通信或更灵活的数据交互,可使用本地socket实现。
修改后的gui1.py(发送端)
from tkinter import * import socket class GUI1: def __init__(self): self.begin = Tk() self.begin.title("Window 1") self.textBox = Text(self.begin) self.button = Button(self.begin, text="发送数据", command=self.send_data) self.textBox.grid(row=0) self.button.grid(row=1) # 连接到Window2的socket服务 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(("localhost", 12345)) def send_data(self): content = self.textBox.get("1.0", END).strip() if content: self.sock.sendall(content.encode("utf-8")) def run(self): self.begin.mainloop() self.sock.close() if __name__ == "__main__": app = GUI1() app.run()
修改后的gui2.py(接收端)
from tkinter import * import socket import threading class GUI2: def __init__(self): self.begin = Tk() self.begin.title("Window 2") self.textBox = Text(self.begin) self.textBox.grid(row=0) # 启动socket服务端线程 self.server_thread = threading.Thread(target=self.start_server, daemon=True) self.server_thread.start() def start_server(self): server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_sock.bind(("localhost", 12345)) server_sock.listen(1) conn, addr = server_sock.accept() while True: data = conn.recv(1024) if not data: break content = data.decode("utf-8") self.begin.after(0, self.update_text, content) conn.close() server_sock.close() def update_text(self, content): self.textBox.insert(END, f"收到数据:{content}\n") def run(self): self.begin.mainloop() if __name__ == "__main__": app = GUI2() app.run()
运行方式
先执行python gui2.py启动服务端,再执行python gui1.py启动客户端,即可实现跨窗口数据传递。
关键注意事项
- Tkinter的UI更新必须在主线程执行,所以用
after(0, callback)将更新操作抛回主线程队列,避免线程异常。 - 多进程方案的队列是进程安全的,无需额外加锁。
- 原有依赖文件(
add_func1_*.py、add_func2_*.py)可直接在各自GUI类中导入,不受重构影响。
内容的提问来源于stack exchange,提问作者lipa
相关产品推荐
相关产品推荐

