Очередь событий wxPython прекращает обработку событий, когда отображается wxMessageDialog

#python-3.x #wxpython #wxwidgets

Вопрос:

Может ли кто-нибудь объяснить, почему пользовательский обработчик событий перестает вызываться при отображении диалогового окна сообщения?

 import threading
import time
import wx
from wx.lib.newevent import NewEvent


CustomEvent, EVT_CUSTOM = NewEvent()


class EventProducer(threading.Thread):
    def __init__(self, consumer):
        self.running = True
        self._consumer = consumer
        self._production_count = 0
        super().__init__(daemon=True)
        
    def run(self):
        while self.running:
            data_string = f'Test Data:{self._production_count}'
            print(f'Producing Event: {data_string}')
            event = CustomEvent(data=data_string)
            wx.PostEvent(self._consumer, event)
            self._production_count  = 1
            time.sleep(0.5)
            
            
class TestPanel(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.button_id = wx.NewIdRef()      
        self._button = wx.Button(self, id=self.button_id, label='Test Button')
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(selenter code heref._button, proportion=1, flag=wx.EXPAND)
        self.SetSizer(sizer)
        
        self.Bind(EVT_CUSTOM, self._handle_custom_event)
        self.Bind(wx.EVT_BUTTON, self._handle_button_event, id=self.button_id)
        self._producer = EventProducer(self)
                
    def _handle_custom_event(self, event):
        print(f'tConsuming Event: {event.data}')
        
    def _handle_button_event(self, event):
        dlg = wx.MessageDialog(self, 'Test Message', 'Test Message')
        dlg.ShowModal()

    def start_events(self):
        self._producer.start()


class MainFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='Test Frame')
        self._panel = TestPanel(self)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self._panel, proportion=1, flag=wx.EXPAND)
        self.SetSizer(sizer)
        
        self._panel.start_events()
        
class App(wx.App):
    def __init__(self):
        super().__init__()
        self._frame = None
        
    def OnInit(self):
        self._frame = MainFrame()
        self._frame.Show()
        return True


if __name__ == '__main__':
    app = App()
    app.MainLoop()
 

Затем выведите данные из программы:

 Producing Event: Test Data:0
    Consuming Event: Test Data:0
Producing Event: Test Data:1
    Consuming Event: Test Data:1
Producing Event: Test Data:2
    Consuming Event: Test Data:2
Producing Event: Test Data:3
    Consuming Event: Test Data:3
Producing Event: Test Data:4
    Consuming Event: Test Data:4
Producing Event: Test Data:5
    Consuming Event: Test Data:5
Producing Event: Test Data:6
    Consuming Event: Test Data:6
 

При нажатии кнопки и отображении диалогового окна сообщения дескриптор события пользовательского события перестает вызываться. Он действительно вызывается, когда мышь перемещается по основному кадру, как показано ниже. Если мышь полностью отодвинута от кадра, дескриптор события вообще перестает вызываться.

 Producing Event: Test Data:7
Producing Event: Test Data:8
    Consuming Event: Test Data:7
    Consuming Event: Test Data:8
Producing Event: Test Data:9
Producing Event: Test Data:10
    Consuming Event: Test Data:9
    Consuming Event: Test Data:10
Producing Event: Test Data:11
Producing Event: Test Data:12
Producing Event: Test Data:13
Producing Event: Test Data:14
Producing Event: Test Data:15
Producing Event: Test Data:16
    Consuming Event: Test Data:11
    Consuming Event: Test Data:12
    Consuming Event: Test Data:13
    Consuming Event: Test Data:14
    Consuming Event: Test Data:15
    Consuming Event: Test Data:16
Producing Event: Test Data:17
Producing Event: Test Data:18
Producing Event: Test Data:19
Producing Event: Test Data:20
Producing Event: Test Data:21
Producing Event: Test Data:22
Producing Event: Test Data:23
    Consuming Event: Test Data:17
    Consuming Event: Test Data:18
    Consuming Event: Test Data:19
    Consuming Event: Test Data:20
    Consuming Event: Test Data:21
    Consuming Event: Test Data:22
    Consuming Event: Test Data:23
Producing Event: Test Data:24
    Consuming Event: Test Data:24
Producing Event: Test Data:25
    Consuming Event: Test Data:25
 

Комментарии:

1. диалоговое окно запускает свою собственную очередь событий.

2. Да, я так считаю, проблема в том, что диалог может быть открыт в течение длительного периода времени, прежде чем он будет проверен. В течение этого времени пользовательское событие будет потреблять память / оставаться необслуживаемым. Я предполагаю, что диалоговые окна сообщений не предназначены для такого использования. Или есть ли что-то, что я могу сделать с очередями событий, чтобы гарантировать, что пользовательские события все еще обрабатываются ?

3. что вы имеете в виду под consume memory/go unserviced этим ? И если вы все еще хотите обработать событие, вы можете написать его обработчик в диалоговом окне, и оно будет обработано. Вам просто нужно отправить это событие соответствующим образом, если откроется диалоговое окно.

4. Я не рассматривал это подробно, но ключ может быть в ShowModal этом . Диалоги — все они «модальные», захватывающие поток управления до тех пор, пока пользователь не закроет диалог, чтобы упростить их использование в приложении.