子进程完成后为按钮着色

发布于 2024-08-14 17:15:43 字数 861 浏览 10 评论 0原文

我有一个 Tk python 程序,它在当前目录中创建一个 python 文件列表,并为每个文件生成一个按钮。当您单击按钮时,相应的 python 程序将通过新的 gnome 终端中的子进程启动。我想在子进程在新终端上完成执行后将按钮的颜色切换为红色。不幸的是,按钮几乎立即改变颜色。

from Tkinter import *
import os, subprocess

root = Tk()
buttonsD = {}

def launch(ourfile):
    p=subprocess.Popen(["gnome-terminal","-e","python " + ourfile], shell=False)
    buttonsD[ourfile].configure(bg='red')

dirlist=os.listdir(os.getcwd())
for fname in dirlist:
    if fname.endswith('py') and fname != 'gui2.py':
        buttonsD[fname] = Button(root,text=fname,command=lambda i=fname: launch(i))
        buttonsD[fname].pack(side=TOP,expand=YES,fill=BOTH)

root.mainloop()

几乎立即意味着我可以在 p.poll == None 时等待,并看到创建 gnome-terminal 需要一些时间。但是,一旦创建了终端,按钮就会变成红色,即使进程仍在新终端中运行。我无法创建新的 gnome 终端,然后传达我想要运行的进程。看起来 gnome-terminal 只是创建了一个新的 bash 实例,然后返回完成,因此如果我尝试与其标准输入进行通信,则会出现管道错误。

I have a Tk python program that creates a list of python files in the current directory and generates a button for each of them. When you click a button the corresponding python program is launched via subprocess in a new gnome-terminal. I'd like to switch the button's color to red after the subprocess has finished executing on the new terminal. Unfortunately, the button is changing color almost immediately.

from Tkinter import *
import os, subprocess

root = Tk()
buttonsD = {}

def launch(ourfile):
    p=subprocess.Popen(["gnome-terminal","-e","python " + ourfile], shell=False)
    buttonsD[ourfile].configure(bg='red')

dirlist=os.listdir(os.getcwd())
for fname in dirlist:
    if fname.endswith('py') and fname != 'gui2.py':
        buttonsD[fname] = Button(root,text=fname,command=lambda i=fname: launch(i))
        buttonsD[fname].pack(side=TOP,expand=YES,fill=BOTH)

root.mainloop()

Almost immediately means that I can wait while p.poll == None, and see that it takes a moment for gnome-terminal to be created. But as soon as the terminal is created the button goes red, even though a process is still running in the new terminal. I can't create a new gnome-terminal and then communicate the process I'd like to run either. It seems gnome-terminal just creates a new instance of bash and then returns done, so there's a pipe error if I try to communicate to its stdin.

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

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

发布评论

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

评论(2

半透明的墙 2024-08-21 17:15:43

我相信 gnome 终端正在执行双分叉,以便将自身与其父进程的进程组分离——因此,正如您所观察到的,实际上您的子进程几乎立即终止,并且所有事情都发生在您没有直接关系的进一步后代中访问。

不幸的是,我不相信 gnome 终端提供任何方法来禁用这种双分叉行为;因此,要查明“进一步的后代”何时完成,您必须识别该过程并定期监视它。直接与它交互也是一个相当艰巨的任务——并不比与任何不相关的“随机”进程交互更容易:-(。

I believe gnome terminal is doing a double fork, in order to detach itself from the process group of its parent -- so what's actually your subprocess terminates almost immediately, as you observe, and everything is happening in a further descendant that you have no direct access to.

Unfortunately I don't believe gnome terminal offers any way to disable this double fork behavior; so, to find out when the "further descendant" is finished, you'll have to identify that process and monitor it periodically. Interacting directly with it is also a pretty tall order -- no easier than interacting with any "random" process you're not related to:-(.

只有一腔孤勇 2024-08-21 17:15:43

这里有两个问题:使用什么命令行在 gnome-terminal 中启动 Python 程序,以及如何在 Tkinter 应用程序中使用 subprocess 。我只知道后者。

subprocess.Popen 立即返回,这就是按钮立即变成红色的原因。我认为您可能需要列出正在运行的程序。然后编写一个函数poll_processes,它在每个正在运行的进程上调用poll(),当结果不是None时,将其从列表中删除并将按钮变为红色。

然后您所要做的就是安排 Tkinter 定期调用该函数,您可以通过调用 frame.after(msec, poll_processes) 安排第一次调用 poll_processes 然后让 poll_processes 做同样的事情来安排下一次调用。

There are two questions here: what command line to use to launch a Python program in gnome-terminal, and how to use subprocess in a Tkinter app. I only know about the latter.

subprocess.Popen returns immediately, which is why the button is turning red immediately. I think you probably need to make a list of which programs are running. Then write a function poll_processes which calls poll() on each running process, and when the result is not None, removes it from the list and turns the button red.

Then all you have to do is arrange for Tkinter to periodically call that function, which you can do by calling frame.after(msec, poll_processes) to schedule the first call to poll_processes and then having poll_processes do the same thing to schedule the next call.

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