1

すべてのwxPythonコードを含むGUIスクリプトと、GUIからの入力に基づいて実行する一連のタスクを含む別のtestSequencesモジュールがあります。タスクの完了には長い時間がかかるため(20秒から3分)、スレッド化する必要があります。そうしないと、実行中にGUIがロックされます。また、すべて同じハードウェアを使用しているため、次々に実行する必要があります。(スレッド化の背後にある私の理論的根拠は、GUIがロックアップしないようにすることです。)「実行中」メッセージ(その後のピリオドの数を変えて、「実行中」、「実行中」、「実行中」を表示したい。 "など)。これにより、ユーザーは、表示されていなくても、進行状況が発生していることを知ることができます。このスクリプトでテストシーケンスを別々のスレッドで実行したいのですが、2番目のスレッドが実行されないように順番に実行します。最初のものが完了するまで作成して実行します。これはスレッドの目的とは正反対なので、これを行う方法についての情報を実際に見つけることはできません...助けていただければ幸いです。

前もって感謝します!

gui.py

import testSequences
from threading import Thread

#wxPython code for setting everything up here...
for j in range(5):
    testThread = Thread(target=testSequences.test1)
    testThread.start()
    while testThread.isAlive():
        #wait until the previous thread is complete
        time.sleep(0.5)
        i = (i+1) % 4
        self.status.SetStatusText("Running"+'.'*i)

testSequences.py

import time
def test1():
    for i in range(10):
        print i
        time.sleep(1)

(明らかに、これは実際のテストコードではありませんが、考え方は同じです。)

4

2 に答える 2

2

イベントキューの処理をブロックするため、whileループでGUIスレッドで待機することはできません。1つの解決策は、タイマーを使用してスレッドの状態をポーリングすることです。

import wx 
import time
from threading import Thread

def test1():
    for i in range(10):
        print i
        time.sleep(1)

class TestFrame(wx.Frame): 
    def __init__(self): 
        wx.Frame.__init__(self, None, -1, "Test") 
        panel = wx.Panel(self, -1) 
        sizer = wx.BoxSizer(wx.VERTICAL) 
        panel.SetSizer(sizer) 

        self.button = wx.Button(panel, 0, "Start")
        sizer.Add(self.button, 0, wx.ALIGN_LEFT) 
        self.button.Bind(wx.EVT_BUTTON, self.OnButton)

        self.text = wx.StaticText(panel, 0, "No test is running")
        sizer.Add(self.text, 0, wx.ALIGN_LEFT) 

        self.timer = wx.Timer(self)

    def OnButton(self, event):
        self.testThread = Thread(target=test1)
        self.testThread.start()
        self.text.SetLabel("Running")
        self.button.Disable()
        self.Bind(wx.EVT_TIMER, self.PollThread)
        self.timer.Start(20, oneShot=True)
        event.Skip()

    def PollThread(self, event):
        if self.testThread.isAlive():
            self.Bind(wx.EVT_TIMER, self.PollThread)
            self.timer.Start(200, oneShot=True)
            self.text.SetLabel(self.text.GetLabel() + ".")
        else:
            self.button.Enable()
            self.text.SetLabel("Test completed")


app = wx.PySimpleApp() 
TestFrame().Show() 
app.MainLoop()
于 2012-10-13T18:38:50.710 に答える
2

これを行う方法を考え出しました。gui.pyでスレッドを作成する代わりに、Threadから継承するクラスを作成し、そのクラスのすべてのテストを実行して、1つのテストが完了したとき(ステータスバーを更新できるようにするため)とすべてのテスト時にwxPythonイベントを投稿します完了しました(すべてのテストが完了したことをユーザーに通知できます。

myEVT_TESTDONE = wx.NewEventType()
EVT_TESTDONE = wx.PyEventBinder(myEVT_TESTDONE , 1)
myEVT_ALLDONE = wx.NewEventType()
EVT_ALLDONE = wx.PyEventBinder(myEVT_ALLDONE, 1)

class TestDone(wx.PyCommandEvent):
    def __init__(self, etype, eid, val=None):
        wx.PyCommandEvent.__init__(self, etype, eid)
        self._val = val
    def GetValue(self):
        return self._val

class AllDone(wx.PyCommandEvent):
    def __init__(self, etype, eid):
        wx.PyCommandEvent.__init__(self, etype, eid)

class TestSequence(Thread):
    def __init__(self, parent, queue):
        Thread.__init__(self)
        self._queue = queue
        self._parent = parent
        self.start()
    def run(self):
        testCount = 0
        for test in self._queue:
            #Time-intensive task goes here
            for i in range(10):
                print i
                sleep(1)
            evt = TestDone(myEVT_TESTDONE, -1, i)
            wx.PostEvent(self._parent, evt)
        evt = AllDone(myEVT_ALLDONE, -1)
        wx.PostEvent(self._parent, evt)

class MainSequence(wx.Frame):
    def __init__(self, parent, id, title):
        self.Bind(EVT_TESTDONE, self.testDoneEvt)
        self.Bind(EVT_ALLDONE, self.allDoneEvt)
        #...the rest of the wxPython code
    def testDoneEvt(self, event):
        #Set what to be done after every test, e.g. update progress bar
        step = event.GetValue()
    def allDoneEvt(self, event):
        #Set what to be done after all tests, e.g. display "Tests complete"

program = wx.App()
window = MainSequence(None, -1, 'App title')
program.MainLoop()
于 2012-10-15T18:30:27.013 に答える