2010-02-26 4 views
2

Я пытаюсь научиться запускать поток из основного приложения графического интерфейса, чтобы выполнять отправку/получение последовательного порта, сохраняя мой графический интерфейс живым. Мои лучшие попытки Googling приземлили меня на wxpython wiki по: http://wiki.wxpython.org/LongRunningTasks, который содержит несколько примеров. Я решил изучить первый пример, связанный с запуском рабочего потока, когда выбрана конкретная кнопка.wxPython: Threading GUI -> Использование обработчика пользовательских событий

У меня возникли проблемы с пониманием пользовательских-событий-определение:

def EVT_RESULT(win, func): 
    """Define Result Event.""" 
    win.Connect(-1, -1, EVT_RESULT_ID, func) 

class ResultEvent(wx.PyEvent): 
    """Simple event to carry arbitrary result data.""" 
    def __init__(self, data): 
     """Init Result Event.""" 
     wx.PyEvent.__init__(self) 
     self.SetEventType(EVT_RESULT_ID) 
     self.data = data 

В первую очередь

def EVT_RESULT(win, func): 
    """Define Result Event.""" 
    win.Connect(-1, -1, EVT_RESULT_ID, func) 

Я думаю, что EVT_RESULT находится вне классов, с тем чтобы сделать его колл-возможность обоими классы (что делает его глобальным?)

И .. основное приложение GUI отслеживает ход потока через:

# Set up event handler for any worker thread results 
EVT_RESULT(self,self.OnResult) 

Я также заметил, что в большинстве примеров, когда писатель использует

from wx import * 

они просто связать вещи

EVT_SOME_NEW_EVENT(self, self.handler) 

в отличие от

wx.Bind(EVT_SOME_NEW_EVENT, self.handler) 

Какие Безразлично «Помогите мне понять это быстрее. Спасибо,

ответ

2

Вы можете определить такие события:

from wx.lib.newevent import NewEvent 

ResultEvent, EVT_RESULT = NewEvent() 

Вы отправляете событие так:

wx.PostEvent(handler, ResultEvent(data=data)) 

Bind это следующим образом:

def OnResult(event): 
    event.data 

handler.Bind(EVT_RESULT, OnResult) 

Но если вам просто нужно сделать вызов из основного потока в основном потоке, который вы можете использовать wx.CallAfter, here - пример.

Пользовательские события полезны, когда вы не хотите, чтобы жесткий код отвечал за то, что (см. observer design pattern). Например, скажем, у вас есть главное окно и несколько дочерних окон. Предположим, что некоторые дочерние окна необходимо обновить, когда в главном окне происходит определенное изменение. Главное окно могло бы непосредственно обновлять эти дочерние окна в таком случае, но более элегантный подход состоял бы в том, чтобы определить настраиваемое событие и оставить его в главном окне (и не беспокоить, кто должен реагировать на него). Затем дети, которые должны реагировать на это событие, могут сделать это сами по себе, привязавшись к нему (и если есть более одного, важно, чтобы они вызывали event.Skip(), чтобы вызывались все связанные методы).

+0

спасибо за ответ, я буду ссылаться на него, когда работаю над ним. – PPTim

4

Это старый стиль определения пользовательских событий. См. the migration guide для получения дополнительной информации.

Взятые из руководства по миграции:

Если вы создать свое собственное пользовательское событие типы и * функцию EVT_, и вы хотите, чтобы иметь возможность использовать их с помощью метода Bind выше, то вы должны измените EVT_ * на экземпляр wx.PyEventBinder вместо функции . Например, если вы использовали иметь что-то вроде этого:

myCustomEventType = wxNewEventType() 
def EVT_MY_CUSTOM_EVENT(win, id, func): 
    win.Connect(id, -1, myCustomEventType, func) 

Изменить это как так:

myCustomEventType = wx.NewEventType() 
EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1) 

Here is another post, что я сделал с парой примеров программ, которые делают именно то, что вы находясь в поиске.

+0

Спасибо, я посмотрю, что – PPTim

+0

Хорошо, что вы заархивировали эту часть страницы. Он оказался динамичным и не-версированным, поэтому текст больше не существует! Соответствующее чтение: https://wiki.wxpython.org/CustomEventClasses – Pod

0

Возможно, вы захотите использовать потоки и очереди Python, а не настраиваемые события. У меня есть программа wxPython (OpenSTV), которая загружает большие файлы, которые заставляли gui замораживаться во время загрузки. Чтобы предотвратить замораживание, я отправляю поток для загрузки файла и использования очереди для связи между gui и потоком (например, для передачи исключения из GUI).

def loadBallots(self): 
    self.dirtyBallots = Ballots() 
    self.dirtyBallots.exceptionQueue = Queue(1) 
    loadThread = Thread(target=self.dirtyBallots.loadUnknown, args=(self.filename,)) 
    loadThread.start() 

    # Display a progress dialog 
    dlg = wx.ProgressDialog(\ 
     "Loading ballots", 
     "Loading ballots from %s\nNumber of ballots: %d" % 
     (os.path.basename(self.filename), self.dirtyBallots.numBallots), 
     parent=self.frame, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME 
    ) 
    while loadThread.isAlive(): 
     sleep(0.1) 
     dlg.Pulse("Loading ballots from %s\nNumber of ballots: %d" % 
       (os.path.basename(self.filename), self.dirtyBallots.numBallots)) 
    dlg.Destroy() 

if not self.dirtyBallots.exceptionQueue.empty(): 
    raise RuntimeError(self.dirtyBallots.exceptionQueue.get()) 
+1

Я думаю, что очереди - это стандартный способ для многопоточных потоков; но безопасно ли передавать флаг, если все, что мне нужно, это простой «готовый» сигнал? Я не использовал много очередей; мне нужно создать один для каждого направления и в основном иметь приемный конец опроса очереди регулярно? – PPTim

+0

Вам не нужна очередь, чтобы определить, когда поток завершен. Вы можете использовать isAlive(), как используется в примере выше. Вам нужна очередь для связи в каждом направлении, и вы можете увидеть пример этого здесь (http://code.google.com/p/stv/source/browse/trunk/openstv/OpenSTV.py) в runElection (). –