Python tkinter:在子进程调用之间更新 GUI

发布于 2024-12-10 17:27:35 字数 1708 浏览 0 评论 0原文

我编写了一个 GUI,它多次调用 .cmd 文件(使用不同的参数)

class App:
    def process(self):
        for filename in os.listdir(path):
            subprocess.call(['script.cmd', filename])
            self.output('processed ' + filename)

    def output(self, line):
        self.textarea.config(state = NORMAL)
        self.textarea.tag_config("green", background="green", foreground="black")
        self.textarea.insert(END, line, ("green"))
        self.textarea.yview(END)
        self.textarea.config(state = DISABLED)
        self.textarea.update_idletasks()

root = Tk()
app = App()
app.build_gui(root)
app.pack_gui(root)

root.mainloop()

按下按钮时调用 process()

我还尝试了 subprocess.Popen() 和旧的 os.spawnv() 总是一样的。处理文件时 GUI 没有反应。仅在处理完所有文件后,GUI 才会使用所有“已处理 XYZ”消息进行更新。

update_idletasks() 不应该在每次子进程调用后更新 GUI 吗?

谢谢

编辑: 我将问题缩小到这个简单的代码:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def go():
    labeltext.set('los')
    for filename in file_list:
        labeltext.set('processing ' + filename + '...')
        label.update_idletasks()

        proc = subprocess.call(["C:\\test\\process.exe", filename])
    labeltext.set('all done!')


root = Tk()

Button(root, text="Go!", command=go).pack(side=TOP)

labeltext = StringVar()
labeltext.set('Press button to start')

label = Label(root, textvariable=labeltext)
label.pack(side=TOP)

root.mainloop()

现在,脚本是否正常工作取决于 process.exe。如果我编写一个简单的忙循环C程序(例如process.exe的源代码:int i=0; while(i<1e9){ i++; }),则GUI会随着每个文件1-5而更新。当我调用我想要使用的原始 .exe 文件时,它显示“正在处理文件 1”并切换到“正在处理文件 2”,但然后冻结直到程序终止(“全部完成!”)。

我真的不明白这里发生了什么。显然这与调用的过程有关。有人有想法吗?

I programmed a GUI that calls a .cmd file several times (with different parameters)

class App:
    def process(self):
        for filename in os.listdir(path):
            subprocess.call(['script.cmd', filename])
            self.output('processed ' + filename)

    def output(self, line):
        self.textarea.config(state = NORMAL)
        self.textarea.tag_config("green", background="green", foreground="black")
        self.textarea.insert(END, line, ("green"))
        self.textarea.yview(END)
        self.textarea.config(state = DISABLED)
        self.textarea.update_idletasks()

root = Tk()
app = App()
app.build_gui(root)
app.pack_gui(root)

root.mainloop()

process() is called when pressing a button

I also tried subprocess.Popen() and the old os.spawnv()
It's always the same. The GUI is not reacting when processing the files. Only after all files have been processed, the GUI is updated with all the 'processed XYZ' messages.

Shouldn't update_idletasks() update the GUI after every subprocess call?

Thank you

edit:
I narrowed the problem to this simple code:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def go():
    labeltext.set('los')
    for filename in file_list:
        labeltext.set('processing ' + filename + '...')
        label.update_idletasks()

        proc = subprocess.call(["C:\\test\\process.exe", filename])
    labeltext.set('all done!')


root = Tk()

Button(root, text="Go!", command=go).pack(side=TOP)

labeltext = StringVar()
labeltext.set('Press button to start')

label = Label(root, textvariable=labeltext)
label.pack(side=TOP)

root.mainloop()

Now it depends on the process.exe if the script works properly. If I write a simple C program with busy-looping (e.g. source code of process.exe: int i=0; while(i<1e9){ i++; }), the GUI is updated with every file1-5. When I call the original .exe-file I wanted to use, it displays "processing file1" and switches to "processing file2" but then freezes until program termination ("all done!").

I dont really understand whats up here. Obviously it has something to do with the process called. Does anyone have an idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

素衣风尘叹 2024-12-17 17:27:35

我找到了一个肮脏的解决方案:
我在每个 subprocess.call() 之前调用 root.update() 。

为了确保在处理过程中没有按下任何按钮(根据快速谷歌搜索,这似乎是 root.update() 的问题),我在子进程启动之前将它们全部禁用,

如下所示:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def button():
    b_process.configure(state=DISABLED)
    go()
    b_process.configure(state=NORMAL)

def go():
    for filename in file_list:
        label.configure(text="processing " + filename)
        root.update()

        proc = subprocess.call(["C:\\DTNA\\stat\\run.exe", filename])
        print 'process terminated with return code ' + str(proc)     
    label.configure(text="all done!")

root = Tk()

b_process = Button(root, text="Go!", command=button)
b_process.pack(side=TOP)

label = Label(root, text='Press button to start')
label.pack(side=TOP)

root.mainloop()

I found a dirty solution:
I call root.update() before every subprocess.call().

To make sure that no buttons are pressed during processing (that seems to be a problem with root.update() according to a quick google search), I disable them all before the subprocesses are started

like this:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def button():
    b_process.configure(state=DISABLED)
    go()
    b_process.configure(state=NORMAL)

def go():
    for filename in file_list:
        label.configure(text="processing " + filename)
        root.update()

        proc = subprocess.call(["C:\\DTNA\\stat\\run.exe", filename])
        print 'process terminated with return code ' + str(proc)     
    label.configure(text="all done!")

root = Tk()

b_process = Button(root, text="Go!", command=button)
b_process.pack(side=TOP)

label = Label(root, text='Press button to start')
label.pack(side=TOP)

root.mainloop()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文