python - 如何在 tkinter gui 中实现 cmd 输出?
问题描述
我在 stackoverflow 上经历了许多解决方案,但没有一个对我有帮助。我坚持在 tkinter 中实现 cmd 以查看 gui 内的输出并能够在那里输入值。感谢您的帮助,感谢您的提前!
from subprocess import Popen
from tkinter import Tk, Button, messagebox, Label
from PIL import ImageTk, Image
gui = Tk(className='IDPass')
gui.geometry('500x500')
gui.iconbitmap('Turnstile/icons/mini_logo.ico')
img = ImageTk.PhotoImage(Image.open('Turnstile/icons/logo.png'))
panel = Label(gui, image=img)
def run_server():
global process
process = Popen(['python', 'C:/Test/Turnstile/manage.py', 'runserver'])
def run_rfid_scanner():
global process
process = Popen('python C:/Test/Turnstile/rfid_scanner.py')
def run_face_scanner():
global process
process = Popen('python C:/Test/Turnstile/face_scanner.py')
def run_photo_deleter():
global process
process = Popen('python C:/Test/Turnstile/photo_deleter.py')
def run_face_recognizer():
global process
process = Popen('python C:/Test/Turnstile/face_recognizer.py')
def stop_program():
process.kill()
messagebox.showinfo('Информационное окно', 'Программа остановлена')
server = Button(gui, text='Запустить сервер', command=run_server, bg='green')
rfid_scanner = Button(gui, text='Запустить RFID сканер', command=run_rfid_scanner, bg='green')
face_scanner = Button(gui, text='Добавить фото для сканирования', command=run_face_scanner, bg='green')
face_recognizer = Button(gui, text='Начать распознавание лица', command=run_face_recognizer, bg='green')
photo_deleter = Button(gui, text='Удалить фото пользователя', command=run_photo_deleter, bg='grey')
stop_programm = Button(gui, text='Остановить выполнение программы', command=stop_program, bg='grey')
panel.pack()
server.pack()
rfid_scanner.pack()
face_scanner.pack()
face_recognizer.pack()
photo_deleter.pack()
stop_programm.pack()
gui.mainloop()
这就是我想看到的样子
解决方案
尝试这个:
from subprocess import Popen, PIPE
from threading import Thread, Lock
import tkinter as tk
class TkinterPopen(tk.Text):
def __init__(self, master, state="disabled", **kwargs):
super().__init__(master, state=state, **kwargs)
self.commands = []
self.proc = None
self.running = True
self.stdout_buffer = ""
self.stdout_buffer_lock = Lock()
def stdout_loop(self, last_loop:bool=False) -> None:
with self.stdout_buffer_lock:
# Get the data and clear the buffer:
data, self.stdout_buffer = self.stdout_buffer, ""
state = super().cget("state")
super().config(state="normal")
super().insert("end", data)
super().see("end")
super().config(state=state)
if self.proc is None:
if len(self.commands) == 0:
# If we are done with all of the commands:
if last_loop:
return None
super().after(100, self.stdout_loop, True)
else:
# If we have more commands to do call `start_next_proc`
self.start_next_proc()
else:
super().after(100, self.stdout_loop)
def start_next_proc(self) -> None:
command = self.commands.pop(0) # Take the first one from the list
self.proc = Popen(command, stdout=PIPE)
new_thread = Thread(target=self.read_stdout, daemon=True)
new_thread.start()
self.stdout_loop()
def run_commands(self, commands:list) -> None:
self.commands = commands
self.start_next_proc()
def read_stdout(self):
while self.proc.poll() is None:
self._read_stdout()
self._read_stdout()
self.proc = None
def _read_stdout(self) -> None:
line = self.proc.stdout.readline()
with self.stdout_buffer_lock:
self.stdout_buffer += line.decode()
if __name__ == "__main__":
def start_echo():
command = ["echo", "hi"]
tkinter_popen.run_commands([command])
def start_ping():
# For linux use "-c". For windows use "-n"
command = ["ping", "1.1.1.1", "-n", "3"]
tkinter_popen.run_commands([command])
root = tk.Tk()
tkinter_popen = TkinterPopen(root)
tkinter_popen.pack()
button = tk.Button(root, text="Run echo", command=start_echo)
button.pack()
button = tk.Button(root, text="Run ping", command=start_ping)
button.pack()
root.mainloop()
我认为这是您想要的功能。该代码类似于@acw1668,但我stdout
在另一个线程中读取并在名为self.stdout_buffer
.
这只是我在这里给出的答案的副本。
推荐阅读
- angular - 如何阻止父组件css不覆盖子组件css(Angular 5)?
- c++ - *(int*)&data[18] 在这段代码中实际上在做什么?
- html - 我可以在 markdown 中使用 en/em dash 吗?
- haskell - 为什么 Haskell 的 SVGFonts 库中的这个示例无法编译?
- c++ - 返回二叉搜索树特定级别中节点数的函数
- error-handling - ansible-playbook bootstrap.yml 命令中的 tidb-ansible 错误
- mysql - 查询过滤同一列SQL中的相等值和差值
- php - 将用户限制为一个会话
- c# - 取消数据流 ActionBlock 中的特定任务
- python - python - 如何使用pandas或其他方式从python中的CSV文件中拆分值?