【问题标题】:tkinter Text used for user notificationtkinter 用于用户通知的文本
【发布时间】:2021-10-13 13:36:20
【问题描述】:

我对 python 和 tkinter 还很陌生。我正在构建一个 GUI 来管道使用多个外部 .exe 程序的进程我希望能够通知用户其中一个 .exe 进程已经启动或停止,因为它们可能需要很长时间,我希望用户能够能够知道它当前在进程中的哪个位置。

使用我当前的代码,文本框更新会在所有内容结束时同时发生,而不是在每个步骤之后发生。有没有办法让这个更新在每一步都发生,或者有没有我不知道的更好的方法?我愿意打开命令行并打印到它。

import tkinter as tk
import subprocess as s

root = tk.Tk()
root.minsize(650,250)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

container = tk.Frame(root).grid(row=0, column=0)
exe_1_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_1.exe')
exe_2_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_2.exe')
exe_3_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_3.exe')
config_file_path = tk.StringVar(root, value = 'C:\\Users\\Config.txt')
output_path = tk.StringVar(root, value = 'C:\\Users\\Output')

def start_processing():
    # notifu user that we are starting to process the data
    output_window.insert(tk.END, 'Starting to process data for exe1.\n')
    # I want the textbox to update here
    s.check_call([exe_1_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe1.\n')
    # I want the textbox to update and here
    output_window.insert(tk.END, 'Starting to process data for exe2.\n')
    # I want the textbox to update and here
    s.check_call([exe_2_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe2.\n')
    # I want the textbox to update and here
    output_window.insert(tk.END, 'Starting to process data for exe3.\n')
    # I want the textbox to update and here
    s.check_call([exe_3_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe3.\n')
    # I want the textbox to update and here

start_button = tk.Button(container, text='Start', width=10, command = start_processing)
start_button.grid(row = 0, pady=10, padx=20)

output_window = tk.Text(root, height = 10, width = 75, bg = 'black', fg = 'white')
output_window.grid(row = 1, pady=10, padx=20)

root.mainloop()

【问题讨论】:

  • 调用check_call() 将使您的脚本挂起或冻结,直到它返回。您需要定期检查子流程的状态并相应地更新 GUI。为了帮助您,您需要发布更完整的minimal reproducible example (MRE)。
  • 您可以在每个check_call()之前添加output_window.update_idletasks()
  • @acw1668 在check_call 运行时不会挂起tkinter 吗?我的意思是它会比现在好一些,但仍然会冻结
  • @Matiiss OP 没有询问冻结问题。
  • @acw1668 这正是我想要的,谢谢。我不担心 tkinter 挂起,而子进程工作只是想要一种通知用户进度的方法。

标签: python tkinter concurrency subprocess


【解决方案1】:

要更新 output_window 中的文本,请使用 output_window.update()

例子:

import tkinter as tk
import subprocess as s

root = tk.Tk()
root.minsize(650,250)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

container = tk.Frame(root).grid(row=0, column=0)
exe_1_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_1.exe')
exe_2_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_2.exe')
exe_3_path = tk.StringVar(root, value = 'C:\\Users\\Process_data_step_3.exe')
config_file_path = tk.StringVar(root, value = 'C:\\Users\\Config.txt')
output_path = tk.StringVar(root, value = 'C:\\Users\\Output')

def start_processing():
    # notifu user that we are starting to process the data
    output_window.insert(tk.END, 'Starting to process data for exe1.\n')
    # I want the textbox to update here
    s.check_call('python example_subprocess1.py')
    #s.check_call([exe_1_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe1.\n')
    output_window.update()
    # I want the textbox to update and here
    output_window.insert(tk.END, 'Starting to process data for exe2.\n')
    # I want the textbox to update and here
    s.check_call('python example_subprocess1.py')
    #s.check_call([exe_2_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe2.\n')
    output_window.update()
    # I want the textbox to update and here
    output_window.insert(tk.END, 'Starting to process data for exe3.\n')
    # I want the textbox to update and here
    s.check_call('python example_subprocess1.py')
    #s.check_call([exe_3_path.get(), '-c', config_file_path.get(), 'o', output_path.get])
    output_window.insert(tk.END, 'Finished processing data for exe3.\n')
    output_window.update()
    # I want the textbox to update and here

start_button = tk.Button(container, text='Start', width=10, command = start_processing)
start_button.grid(row = 0, pady=10, padx=20)

output_window = tk.Text(root, height = 10, width = 75, bg = 'black', fg = 'white')
output_window.grid(row = 1, pady=10, padx=20)

root.mainloop()

示例子流程在哪里(对您来说已经很简单但对其他人和以后使用):

import tkinter
from tkinter import *
import numpy as np
from tkinter import messagebox

import time

#luodaan kuva...
ikkuna=tkinter.Tk()
ikkuna.title("Example subprocess 1 (here some serial data processing...)")
ikkuna.geometry("800x400")


kanvaasi=Canvas(ikkuna,width=800,height=400)
kanvaasi.pack(fill="both",expand=True)

kanvaasi.create_text(370,80,text="V1")
kanvaasi.create_text(370,130,text="V2")
kanvaasi.create_text(370,180,text="V3")
kanvaasi.create_text(370,220,text="VPack")
kanvaasi.create_text(370,270,text="Capacity")

def read():
    global v1,v2,v3,vpack,capacity
    global kv1,kv2,kv3,kv4,kv5

    #this is only simulation, in real case replace the simulation code with the real one...
    v1=np.random.random(1)[0].round(decimals=2)
    v2=np.random.random(1)[0].round(decimals=2)
    v3=np.random.random(1)[0].round(decimals=2)
    vpack=np.random.random(1)[0].round(decimals=2)
    capacity=np.random.random(1)[0].round(decimals=2)
    #...end of simulation

    try:
        kanvaasi.delete(kv1)
        kanvaasi.delete(kv2)
        kanvaasi.delete(kv3)
        kanvaasi.delete(kv4)
        kanvaasi.delete(kv5)
    except:
        pass

    #let's update the tkinter accordingly...
    kv1=kanvaasi.create_text(430,80,text=v1)
    kv2=kanvaasi.create_text(430,130,text=v2)
    kv3=kanvaasi.create_text(430,180,text=v3)
    kv4=kanvaasi.create_text(430,220,text=vpack)
    kv5=kanvaasi.create_text(430,270,text=capacity)

    ikkuna.destroy()


painike1=Button(ikkuna,text="Read",command=read,height=14,width=20)
painike1_ikkuna=kanvaasi.create_window(120,70,anchor="nw",window=painike1)

ikkuna.mainloop()

【讨论】:

    猜你喜欢
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多