Выполнение скрипта Python и отображение прогресса внутри графического интерфейса WXPython - PullRequest
1 голос
/ 19 марта 2019

Как мы можем запустить скрипт python внутри графического интерфейса WXPython и показать журнал.Я пытался, но он не работает, вместо этого он открывает cmd и работает там.Ранее я просто запускал скрипт Python из командной строки, и он выполнял свою работу, но новое требование - не открывать командную строку, вместо этого графический интерфейс должен открывать и выполнять основные скрипты Python.Я новичок в Python (причина делать в Python, чтобы сделать его независимым от платформы).

`
import wx, os, logging, sys, subprocess

logger = logging.getLogger(__name__)

class WxTextCtrlHandler(logging.Handler):

   def __init__(self, ctrl):
       logging.Handler.__init__(self)
       self.ctrl = ctrl

   def emit(self, record):
       s = self.format(record) + '\n'
       wx.CallAfter(self.ctrl.WriteText, s)`


class WindowClass(wx.Frame):

   def __init__(self):
       TITLE = "wxPython Logging To A Control"
       wx.Frame.__init__(self, None, wx.ID_ANY, TITLE)
       panel = wx.Panel(self, wx.ID_ANY)
       log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,200), style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
       py = os.path.join(os.getcwd(), 'test1.py')
       log = subprocess.call([sys.executable, py])
       sizer = wx.BoxSizer(wx.VERTICAL)
       sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)
       panel.SetSizer(sizer)
       handler = WxTextCtrlHandler(log)
       logger.addHandler(handler)
       #self.Centre
       FORMAT = "%(asctime)s %(levelname)s %(message)s"
       handler.setFormatter(logging.Formatter(FORMAT))
       logger.log(1,"More? click again!")
       label = wx.StaticText(panel, label = "Hello World", pos = (100,50))
       self.Show()

app = wx.App(False)
WindowClass()
app.MainLoop()`

1 Ответ

1 голос
/ 19 марта 2019

Я никогда не использовал logging, но я полагаю, что вы хотите что-то вроде ниже:
Вам нужно будет использовать subprocess.Popen вместо subprocess.call, а затем poll результаты.
Если GuiЧтобы оставаться активным, вам также нужно будет вызвать Yield, потому что вы будете в цикле, поэтому wx MainLoop будет эффективно заморожен.

Основная программа

import wx
import subprocess
from signal import SIGKILL
import os

class MyFrame(wx.Frame):

    def __init__(self, parent, id=-1, title='External program test',
                 pos=wx.DefaultPosition, size=(600, 600)):
        wx.Frame.__init__(self, parent, id, title, pos, size)
        self.text1 = wx.TextCtrl(self, -1, '', wx.DefaultPosition, wx.Size(500,500),
                            wx.NO_BORDER | wx.TE_MULTILINE)
        stop_button = wx.Button(self, wx.ID_ANY, "&Stop", pos=(400,520))
        self.Bind(wx.EVT_BUTTON, self.OnStop)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Show()
        #Call python with -u for unbuffer I/O
        p = subprocess.Popen(["python", "-u", "testp.py"], stdout=subprocess.PIPE, bufsize=-1)
        self.pid = p.pid
        #Poll process for output
        while p.poll() is None:
            x = p.stdout.readline().decode() #decode bytes but don't strip linefeeds
            self.text1.write(x)
            wx.GetApp().Yield() # Yield to MainLoop for interactive Gui
        self.text1.write("\nProcess has ended")

    def OnStop(self, event):
        try:
            os.kill(int(self.pid), SIGKILL)
            self.text1.write("\nProcess killed")
        except:
            self.text1.write("\nProcess has ended")

    def OnClose(self, event):
        self.Destroy()

if __name__ == '__main__':
    app = wx.App()
    frame = MyFrame(None)
    app.MainLoop()

Вызываемая программа

import time
counter = 0
while counter < 40:
    print ("Counter:",counter)
    counter += 1
    time.sleep(0.5)

Результат enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...