我有这段代码,是我的想象和 ChatGPT 帮助的产物:
import subprocess
import threading
import tkinter as tk
class PingThread(threading.Thread):
def __init__(self, text_widget):
super().__init__()
self.text_widget = text_widget
self.process = None
self.stop_event = threading.Event()
def run(self):
self.process = subprocess.Popen(['cmd'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
self.process.stdin.write(b'ping -t google.com\n')
self.process.stdin.flush()
while not self.stop_event.is_set():
line = self.process.stdout.readline().decode('cp866')
if not line:
break
self.text_widget.insert(tk.END, line)
self.text_widget.see(tk.END)
def stop(self):
if self.process:
self.process.communicate(b'\x03')
self.process.wait() #Window freezes on the .communicate line, so this and line below are not executing at all
self.stop_event.set()
def ping():
ping_thread = PingThread(text)
ping_thread.start()
def handle_ctrl_c(event):
ping_thread.stop()
text.insert(tk.END, '\nProcess terminated.\n')
root.bind('<Control-c>', handle_ctrl_c)
root = tk.Tk()
text = tk.Text(root)
text.pack()
button = tk.Button(root, text='Ping', command=ping)
button.pack()
root.mainloop()
我正在尝试在 Tkinter 中创建控制台模拟。我正在发送 ping 请求并监听控制台的响应。一切正常,除了
Ctrl+C
命令,它应该完成 ping
执行并从控制台响应统计信息。窗口刚刚冻结,当我尝试发送self.process.communicate(b'\x03')
是什么原因造成的?据我所知,这条线应该发送
Ctrl+C
到控制台,while loop
应该从控制台接收最后几行,以及 ping 的统计信息?
只需更换
self.process.communicate(b'\x03')
self.process.wait()
与
self.process.kill()
root.unbind('<Control-c>')
注意当您点击
Ctrl+c
时选择了您的tkinter窗口,因为终端也使用此快捷方式。在这里,您覆盖快捷方式的根键绑定以在 python 中终止子进程。 Ctrl+c
在终端中代表 KeyboardInterrupt 并中断你的整个脚本。
所以现在我更好地理解了你的问题,这是另一种尝试。我的回答并不完美,因为我错过了
STDOUT
中的 2 行,而且我找不到问题所在。
但是,对于您的问题,最重要的两件事是:
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
。如果我理解正确的话,这会为终端和 ping 命令创建一个不同的进程,因此您仍然可以在通过停止信号后从终端获得输出。ping
命令,请在 Windows 上发送 signal.CTRL_BREAK_EVENT
。一般来说,这些信号似乎与操作系统不一致。 (另请参阅@chris_se 的评论)如果你知道为什么我的代码遗漏了一些
STDOUT
行,请告诉我。可能是发送和接收之间的重叠问题......
代码如下:
import subprocess
import threading
import tkinter as tk
import signal
class PingThread(threading.Thread):
def __init__(self, text_widget):
super().__init__()
self.text_widget = text_widget
self.process = None
self.stop_event = threading.Event()
def stop(self):
if self.process:
self.stop_event.set()
self.process.send_signal(signal.CTRL_BREAK_EVENT)
def run(self):
self.process = subprocess.Popen(['cmd'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
self.process.stdin.write(b'ping -t google.com\n')
self.process.stdin.flush()
line = self.process.communicate()
while not self.stop_event.is_set():
self.text_widget.insert(tk.END, line)
self.text_widget.see(tk.END)
self.text_widget.insert(tk.END, line)
self.text_widget.see(tk.END)
self.process.kill()
root.unbind('<Control-c>')
def ping():
ping_thread = PingThread(text)
ping_thread.start()
def handle_ctrl_c(event):
ping_thread.stop()
text.insert(tk.END, '\nProcess terminated.\n')
root.bind('<Control-c>', handle_ctrl_c)
root = tk.Tk()
text = tk.Text(root)
text.pack()
button = tk.Button(root, text='Ping', command=ping)
button.pack()
root.mainloop()