使用Tkinter和python顺序运行外部独立进程

时间:2012-11-20 05:03:40

标签: python tkinter subprocess

背景:
*我正在使用Tkinter(Portable PYscripter,python v2.7.3)创建批量模拟作业选择器+调度程序 *该程序将作为商业解算器程序的前端 *程序需要允许用户选择一堆文件来依次模拟。
*它还需要具有从现有/正在运行的作业列表中修改(添加/删除)作业的功能 *每次模拟肯定会运行几个小时。
*模拟的输出将在单独的程序中查看,我不需要任何管道到输出。如果需要,将从GUI调用外部查看器。

***我有一个主GUI窗口,允许用户:
    选择工作文件,提交工作,查看提交日志,停止运行工作(逐个)
以上效果很好。

问题:
*如果我使用subprocess.Popen(“command”):所有模拟输入文件同时启动。它必须是顺序的(由于许可和内存限制)

*如果我使用subprocess.call(“”)或wait()方法,则GUI挂起,并且没有停止/添加/修改作业列表的范围。即使“作业提交”命令位于独立窗口上,父窗口也会挂起,直到作业完成。

问题1:
*如何按顺序启动模拟作业(如subprocess.call)并允许主GUI窗口用于修改作业列表或停止作业?
作业位于列表中,使用“askopenfilenames”获取,然后使用For循环运行。

守则的相关部分:

cfx5solvepath=r"c:\XXXX"
def file_chooser_default(): 
    global flist1
    flist1=askopenfilename(parent = root2, filetypes =[('.def', '*.def'),('All', '*.*'),('.res', '*.res')], title ="Select Simulation run files...", multiple = True)[1:-1].split('} {')

def ext_process():
    o=list(flist1)
    p=list(flist1)
    q=list(flist1)
    i=0
    while i < len(flist1):
        p[i]='"%s" -def "%s"'%(cfx5solvepath,flist1[i])
        i+=1
    i=0
    while i < len(p):
        q[i]=subprocess.call(p[i])
        i+=1

root2 = Tk()
root2.minsize(300,300)
root2.geometry("500x300")
root2.title("NEW WINDOW")
frame21=Frame(root2, borderwidth=3, relief="solid").pack()
w21= Button(root2,fg="blue", text="Choose files to submit",command=file_chooser_default).pack()
w2a1=Button(root2,fg="white", text= 'Display chosen file names and order', command=lambda:print_var(flist1)).pack()
w2b1= Button (root2,fg="white", bg="red", text="S U B M I T", command=ext_process).pack()
root2.mainloop()

如果您需要任何其他信息,请与我们联系。期待您的帮助。

* 编辑*
在合并@Tim建议的更改时,GUI保持空闲。由于有一个与主解算器程序关联的特定子程序来停止作业,我可以使用正确的命令停止作业。

当前正在运行的作业停止后,列表中的下一个作业将自动启动,正如我所希望的那样。

这是用于停止工作的代码:

def  stop_select(): #Choose the currently running files which are to be stopped
    global flist3
    flist3=askdirectory().split('} {')

def sim_stop(): #STOP the chosen simulation
    st=list(flist3)
    os.chdir("%s"%flist3[0])
    st= subprocess.call('"%s" -directory "%s"'%(defcfx5stoppath,flist3[0]))
    ret1=tkMessageBox.showinfo("INFO","Chosen simulation stopped successfully")
    os.chdir("%s" %currentwd)


问题2: *完成上述作业后,使用start_new_thread,GUI不响应。当作业在后台运行时,GUI可以正常工作。但是start_new_thread文档说该线程应该在函数返回时以静默方式退出。

*此外,我有一个HTML日志文件,在每个作业完成时写入/更新。当我使用start_new_thread时,日志文件内容仅在所有作业完成后才可见。然而,内容和时间戳是正确的。在不使用start_new_thread的情况下,我能够刷新HTML文件以获取更新的提交日志。

***几次使用任务管理器退出GUI程序时,我突然无法使用start_new_thread函数!!我已经尝试重新安装PYscripter并重新启动计算机。我无法从追溯中找出任何合理的东西,即:

Traceback (most recent call last):
File "<string>", line 532, in write
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 439, in _async_request
seq = self._send_request(handler, args)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 229, in _send_request
self._send(consts.MSG_REQUEST, seq, (handler, self._box(args)))
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 244, in _box
if brine.dumpable(obj):
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in dumpable
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in <genexpr>
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in dumpable
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in <genexpr>
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\Python_Working_folder\v350.py", line 138, in ext_process
q[i]=subprocess.call(p[i])
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 493, in call
return Popen(*popenargs, **kwargs).wait()
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 679, in __init__
errread, errwrite)
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 896, in _execute_child
startupinfo)
WindowsError: [Error 2] The system cannot find the file specified

1 个答案:

答案 0 :(得分:0)

我建议使用单独的线程进行工作启动。最简单的方法是使用thread模块中的start_new_thread方法。

将提交按钮的命令更改为command=lambda:thread.start_new_thread(ext_process, ())

您可能希望在单击按钮时禁用该按钮,并在启动完成后启用它。这可以在ext_process内完成。

如果要允许用户取消作业,则会变得更加复杂。这个解决方案不会处理。