У меня есть пользовательский цикл событий для Pyglet, который можно упростить до этого простого куска кода
while True:
pyglet.clock.tick()
for window in pyglet.app.windows:
window.switch_to()
# rendering code
window.flip()
window.dispatch_events() # <--- program hangs
Когда есть только одно окно, цикл обработки событий работает нормально, но когда я пытаюсь получить два окна, цикл зависает в window.dispatch_events (). Вызов функций в другом порядке приводит к одной и той же проблеме. Я также попробовал отладку:
pyglet.options['debug_win32'] = True
Сообщение об ошибке:
...
_user32.UnregisterHotKey(self._hwnd, 0)
b'Hot key is not registered.\r\n'
После еще нескольких попыток мне удалось заставить Windows реагировать грязным хаком, но все же есть немало проблем, возникающих при обработке событий. Фикс вызывал обновление сразу после появления видимого окна.
Пример кода инициализации:
if __name__=="__main__":
engine = Engine()
engine.run()
class Engine: # test program
def __init__(self):
self.application = customLib.Application()
# define windows, by default they are set as not visible
self.window1 = self.application.guiManager.createWindow("Window 1",
(1000, 700),
cursorPath="../data/cursor.png")
self.window2 = self.application.guiManager.createWindow("Window 2",
(1000, 700),
cursorPath="../data/cursor.png")
# load up code such as loading textures and .obj files
self.window1.pygletWindow.set_visible()
self.window1.update() # calling this after setting self.window2 visible will cause original error
self.window2.pygletWindow.set_visible()
self.window2.update()
def run(self):
self.application.run()
### CUSTOMLIB ###
class Application:
...
def run(self):
while True:
pyglet.clock.tick()
self.guiManager.update()
class GUIManager: # manages windows
...
def update(self):
for window in self.windows:
window.update()
class Window: # pyglet window higher level wrapper
pygletWindow = None
...
def update(self):
e = self.pygletWindow.dispatch_events()
# all events are intercepted by a custom class, it transforms all unhandled events (keyboard, mouse, and close button for now) into a list of events that can then be looped through rather than requiring twenty different functions.
# the event list is acquired, looped through and then cleared
for event in self.eventManager.get():
if event.type == customLib.CLOSE:
# close application
elif event.type == customLib.K_W:
# move player forward
# rendering
self.pygletWindow.switch_to()
# window is cleared
# window content rendered
self.pygletWindow.flip()
Обход предыдущей проблемы кажется немного глупым и ненадежным. С текущим циклом событий у меня иногда не работает обратная связь с окном. Например, чтобы закрыть окно, я иногда должен щелкнуть по нему несколько раз, или, когда окно перемещается, оно не всегда захватывает окно. Я dispatch_events()
в каждом цикле, и мой пользовательский обработчик событий не обрабатывает события движения окна. Сбой обработки событий происходит только с несколькими окнами. В одном окне цикл обработки событий безупречен. Эту «ошибку» можно исправить с помощью переменных pyglet EventLoop.
Я пришел к выводу, что минусы пользовательского цикла событий перевешивают его плюсы. Намного легче создать подкласс EventLoop (так как он оптимизирован для ОС) и переопределить любые надоедливые подпрограммы. Еще лучше сделать новый цикл обработки событий, копирующий код инициализации EventLoop и любые подпрограммы бэкэнда (используя PlatformEventLoop), который затем позволяет очень легко реализовать пользовательские подпрограммы. Я оставлю этот вопрос, потому что по этому вопросу очень мало документации.