您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何在wxPython TextCtrl中捕获在单独进程中运行的Shell脚本的输出?

如何在wxPython TextCtrl中捕获在单独进程中运行的Shell脚本的输出?

我找到了一个解决方案,该解决方案在Roger Stuckey的Simpler wxPython Multiprocessing Example框架之上实现了修改后的输出Queue 。下面的代码 比他的代码还要简单。也可以将其清除一点。希望它可以帮助 别人。我仍然有na的感觉,尽管应该有一种更 直接的方法来做到这一点。

import getopt, math, random, sys, time, types, wx, subprocess

from multiprocessing import Process, Queue, cpu_count, current_process, freeze_support
from Queue import Empty

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.Point(700, 500), wx.Size(300, 200))

        self.panel = wx.Panel(self, wx.ID_ANY)

        #widgets
        self.start_bt = wx.Button(self.panel, wx.ID_ANY, "Start")
        self.Bind(wx.EVT_BUTTON, self.OnButton, self.start_bt)

        self.output_tc = wx.TextCtrl(self.panel, wx.ID_ANY, style=wx.TE_MULTILINE|wx.TE_READONLY)

        # sizer
        self.sizer = wx.GridBagSizer(5, 5)
        self.sizer.Add(self.start_bt, (0, 0), flag=wx.ALIGN_CENTER|wx.LEFT|wx.TOP|wx.RIGHT, border=5)
        self.sizer.Add(self.output_tc, (1, 0), flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=5)
        self.sizer.AddGrowableCol(0)
        self.sizer.AddGrowableRow(1)
        self.panel.SetSizer(self.sizer)

        # Set some program flags
        self.keepgoing = True
        self.i = 0
        self.j = 0


    def OnButton(self, event):
        self.start_bt.Enable(False)

        self.numtasks = 4
        self.numproc = 2
        #self.numproc = cpu_count()
        self.output_tc.AppendText('Number of processes = %d\n' % self.numproc)

        # Create the queues
        self.taskQueue = Queue()
        self.outputQueue = Queue()

        # Create the task list
        self.Tasks = range(self.numtasks)

        # The worker processes...
        for n in range(self.numproc):
            process = Process(target=self.worker, args=(self.taskQueue, self.outputQueue))
            process.start()

        # Start processing tasks
        self.processTasks(self.update)

        if (self.keepgoing):
            self.start_bt.Enable(True)

    def processTasks(self, resfunc=None):
        self.keepgoing = True

        # Submit first set of tasks
        numprocstart = min(self.numproc, self.numtasks)
        for self.i in range(numprocstart):
            self.taskQueue.put(self.Tasks[self.i])

        self.j = -1 # done queue index
        self.i = numprocstart - 1 # task queue index
        while (self.j < self.i):
            # Get and print results
            self.j += 1
            output = None
            while output != 'STOP!':
                try:
                    output = self.outputQueue.get() 
                    if output != 'STOP!': 
                        resfunc(output)
                except Empty:
                    break

            if ((self.keepgoing) and (self.i + 1 < self.numtasks)):
                # Submit another task
                self.i += 1
                self.taskQueue.put(self.Tasks[self.i])

    def update(self, output):
        self.output_tc.AppendText('%s PID=%d Task=%d : %s\n' % output)
        wx.YieldIfNeeded()

    def worker(self, inputq, outputq):
        while True:
            try:
                tasknum = inputq.get()
                print '## Now Running: ', tasknum #this goes to terminal/console. Add it to outputq if you'd like it on the TextCtrl.
                command = ['./script.sh']
                p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                while True:
                    r = p.stdout.readline()
                    if not r:
                        outputq.put('STOP!')
                        break
                    outputq.put(( current_process().name, current_process().pid, tasknum, r.rstrip()))
            except Empty:
                break

    # The worker must not require any existing object for execution!
    worker = classmethod(worker)

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, -1, 'stdout to GUI using multiprocessing')
        self.frame.Show(True)
        self.frame.Center()
        return True

if __name__ == '__main__':
    freeze_support()
    app = MyApp(0)
    app.MainLoop()
python 2022/1/1 18:52:46 有284人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶