如何 运行 从属模式下的 Kivy EventLoop?
How to run a Kivy EventLoop in slave mode?
相关问题here
我发现 runTouchApp
函数的 slave
属性 可以阻止 Kivy 的事件循环 运行ning 并强制从其他地方更新它。
这是 app.py
的一部分,其中使用了 属性:
# we are in a slave mode, don't do dispatching.
if slave:
return
try:
if EventLoop.window is None:
_run_mainloop()
else:
EventLoop.window.mainloop()
finally:
stopTouchApp()
在这里,如果应用程序未 运行 从属模式,我们有两种选择如何 运行 主循环。
第一个,_run_mainloop()
函数工作起来非常简单——它简单地调用 EventLoop.run()
,后者又无限地调用 EventLoop.idle()
.
这可能会让我们相信要保持 GUI 运行ning,我们只需要调用 idle
.
但是还有第二个选项,它调用 kivy.core.window.WindowSDL
的方法 mainloop
。
该方法通过调用另一个方法 _mainloop
来工作,这就是它变得有趣的地方。所述方法的定义是huge,它处理各种事件。
好吧,我 运行 我的应用处于从属模式:
class TestApp(App):
def start_event(self):
pass
def build(self):
return Button(text = "hello")
def run(self):
# This definition is copied from the superclass
# except for the start_event call and slave set to True
if not self.built:
self.load_config()
self.load_kv(filename=self.kv_file)
root = self.build()
if root:
self.root = root
if self.root:
Window.add_widget(self.root)
window = EventLoop.window
if window:
self._app_window = window
window.set_title(self.get_application_name())
icon = self.get_application_icon()
if icon:
window.set_icon(icon)
self._install_settings_keys(window)
self.dispatch('on_start')
runTouchApp(slave = True)
self.start_event() # Here we start updating
self.stop()
现在,如果我把它放在 start_event
方法中(按预期):
def start_event(self):
while True:
EventLoop.idle()
你猜怎么着,应用程序不响应触摸事件并冻结。
所以我试着调用 Window 的主循环:
def start_event(self):
EventLoop.window.mainloop()
然后突然一切又开始正常工作了。但这里的问题是这样的调用永远阻塞,因为它是一个无限循环,所以没有像 EventLoop.idle
这样的一次性更新调用
如何使用此类一次性调用来保持应用程序 运行ning?
好吧,这是 Python 所以假设你想坚持使用 WindowSDL
供应商,你总是可以猴子修补这个 mainloop
函数所以它不会是无限的:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.base import EventLoop
Builder.load_string('''
<MyWidget>:
Button:
text: 'test'
on_press: print('doing my job')
''')
# https://github.com/kivy/kivy/blob/master/kivy/core/window/window_sdl2.py#L630
def mainloop(self):
# replaced while with if
if not EventLoop.quit and EventLoop.status == 'started':
try:
self._mainloop()
except EventLoop.BaseException as inst:
# use exception manager first
r = EventLoop.ExceptionManager.handle_exception(inst)
if r == EventLoop.ExceptionManager.RAISE:
EventLoop.stopTouchApp()
raise
else:
pass
class MyWidget(BoxLayout):
pass
if __name__ == '__main__':
from kivy.base import runTouchApp
runTouchApp(MyWidget(), slave=True)
# monkey patch
EventLoop.window.mainloop = mainloop
while True:
EventLoop.window.mainloop(EventLoop.window)
print('do the other stuff')
if EventLoop.quit:
break
虽然它真的很 hacky,因此我不建议 运行 在生产代码中使用类似的东西。
相关问题here
我发现 runTouchApp
函数的 slave
属性 可以阻止 Kivy 的事件循环 运行ning 并强制从其他地方更新它。
这是 app.py
的一部分,其中使用了 属性:
# we are in a slave mode, don't do dispatching.
if slave:
return
try:
if EventLoop.window is None:
_run_mainloop()
else:
EventLoop.window.mainloop()
finally:
stopTouchApp()
在这里,如果应用程序未 运行 从属模式,我们有两种选择如何 运行 主循环。
第一个,_run_mainloop()
函数工作起来非常简单——它简单地调用 EventLoop.run()
,后者又无限地调用 EventLoop.idle()
.
这可能会让我们相信要保持 GUI 运行ning,我们只需要调用 idle
.
但是还有第二个选项,它调用 kivy.core.window.WindowSDL
的方法 mainloop
。
该方法通过调用另一个方法 _mainloop
来工作,这就是它变得有趣的地方。所述方法的定义是huge,它处理各种事件。
好吧,我 运行 我的应用处于从属模式:
class TestApp(App):
def start_event(self):
pass
def build(self):
return Button(text = "hello")
def run(self):
# This definition is copied from the superclass
# except for the start_event call and slave set to True
if not self.built:
self.load_config()
self.load_kv(filename=self.kv_file)
root = self.build()
if root:
self.root = root
if self.root:
Window.add_widget(self.root)
window = EventLoop.window
if window:
self._app_window = window
window.set_title(self.get_application_name())
icon = self.get_application_icon()
if icon:
window.set_icon(icon)
self._install_settings_keys(window)
self.dispatch('on_start')
runTouchApp(slave = True)
self.start_event() # Here we start updating
self.stop()
现在,如果我把它放在 start_event
方法中(按预期):
def start_event(self):
while True:
EventLoop.idle()
你猜怎么着,应用程序不响应触摸事件并冻结。
所以我试着调用 Window 的主循环:
def start_event(self):
EventLoop.window.mainloop()
然后突然一切又开始正常工作了。但这里的问题是这样的调用永远阻塞,因为它是一个无限循环,所以没有像 EventLoop.idle
如何使用此类一次性调用来保持应用程序 运行ning?
好吧,这是 Python 所以假设你想坚持使用 WindowSDL
供应商,你总是可以猴子修补这个 mainloop
函数所以它不会是无限的:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.base import EventLoop
Builder.load_string('''
<MyWidget>:
Button:
text: 'test'
on_press: print('doing my job')
''')
# https://github.com/kivy/kivy/blob/master/kivy/core/window/window_sdl2.py#L630
def mainloop(self):
# replaced while with if
if not EventLoop.quit and EventLoop.status == 'started':
try:
self._mainloop()
except EventLoop.BaseException as inst:
# use exception manager first
r = EventLoop.ExceptionManager.handle_exception(inst)
if r == EventLoop.ExceptionManager.RAISE:
EventLoop.stopTouchApp()
raise
else:
pass
class MyWidget(BoxLayout):
pass
if __name__ == '__main__':
from kivy.base import runTouchApp
runTouchApp(MyWidget(), slave=True)
# monkey patch
EventLoop.window.mainloop = mainloop
while True:
EventLoop.window.mainloop(EventLoop.window)
print('do the other stuff')
if EventLoop.quit:
break
虽然它真的很 hacky,因此我不建议 运行 在生产代码中使用类似的东西。