【问题标题】:Kivy with Asyncio Exits applicationKivy 与 Asyncio 退出应用程序
【发布时间】:2018-06-23 19:33:34
【问题描述】:

这是一个非常棘手的问题,它是客户端服务器,所以我很抱歉只是客户端代码。不过,也许有人可以给我一些指导。

首先,在客户端中有一个名为listen 的异步函数。此函数读取来自服务器的输入并执行操作。当前的问题是,当 RPGMessage 消息以非弹出消息的形式出现时,它会使应用程序崩溃而没有错误,只是“让应用程序处于进程中”。也许我可以在 Kivy 中扩展一些调试方式?

async def listen():
    while True:
        for message in CLIENT.get_reader_queue():
            message = loads(message, cls=CustomJSONDecoder)

            if isinstance(message, RPGMenu):
                CLIENT_SCREEN.set_current_menu(message)
                CLIENT_SCREEN.refresh()

                if message.description is not None:
                    CLIENT_SCREEN.add_text_item(message.description)
            elif isinstance(message, RPGMessage):
                if message.popup is False:
                    CLIENT_SCREEN.add_text_item(message.text, message.font) <-- THIS IS THE LINE IT WILL TRIGGER.
                else:
                    layout = BoxLayout(orientation='vertical')
                    layout.add_widget(Label(text=message.text))
                    button = Button(text='close', size_hint_y=0.25)
                    layout.add_widget(button)

                    popup = Popup(title='Server Message',
                                  content=layout,
                                  size_hint=(None, None), size=(400, 400), auto_dismiss=False)
                    button.bind(on_press=popup.dismiss)

                    popup.open()
            elif isinstance(message, RPGMedia):
                PopupWindow(message.name, message.text, message.image)
            elif isinstance(message, RPGResultFailure):
                PopupWindow(message.name, message.description)
            elif isinstance(message, RPGResult):
                CLIENT.result = message

        await asyncio.sleep(0.1)

以上调用 CLIENT_SCREEN.add_text_item() 如下所示;

def add_text_item(self, text: str, font: str=None):
    text_input = Label()
    text_input.padding_x = 10
    text_input.size_hint_y = None
    text_input.markup = True
    text_input.text = text + '\n'
    if font is not None:
        text_input.font_name = font
    text_input.font_size = '20sp'

    text_input.bind(size=self.on_size_text_label)
    self.text_grid_layout.add_widget(text_input)
    self.text_scroll_view.scroll_to(text_input)
    text_input.bind(on_ref_press=self.on_reference_press)

这也是我要开始的循环;

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    # loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)

    CLIENT = Client('127.0.0.1', 9000, loop)

    executer = ThreadPoolExecutor(2)

    # asyncio.ensure_future(test())
    # asyncio.ensure_future(console())
    asyncio.ensure_future(listen())

    # MyApp().run()
    loop.run_in_executor(executer, MyApp().run)
    loop.run_forever()

当我运行调试器时,它会添加文本项,然后返回到 asyncio 循环,但 kivy 死了。

有什么想法吗?我知道这是一个很难传达的问题。

谢谢。

更新; 我试图用 - 来增加调试,但对这个问题没有帮助;

Config.set('kivy', 'log_level', 'debug')

【问题讨论】:

  • 有趣的是,当前的回调来自一个文本 REF 回调,如果相同的函数来自一个按钮,它就可以正常工作。我不知所措。我也尝试过在 python 中使用调试模式来显示回溯但无济于事。

标签: python kivy python-asyncio


【解决方案1】:

我已经找到了解决办法。

为了让我混合 Kivy 和 asyncio,我能够在附加到 Kivy 应用程序的线程中启动我的 asyncio 循环。这似乎清理了整个情况。

class MyApp(App):
    def build(self):
        from kivy.core.window import Window

        sm = ScreenManager()
        sm.transition = NoTransition()

        login_screen = LoginScreen(name='login')
        client_screen = ClientScreen(name='client')

        sm.add_widget(login_screen)
        sm.add_widget(client_screen)

        sm.current = 'login'

        Window.size = (300, 120)
        self.title = 'xNemesis Client V0'

        asyncio.ensure_future(listen(client_screen))

        x = threading.Thread(target=loop.run_forever)
        x.start()

        return sm

所以应用程序构建完成,最后我启动异步循环的线程。这样我也不会使用全局变量,我认为这是不受欢迎的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2015-12-02
    • 2019-06-27
    • 1970-01-01
    • 2021-07-29
    相关资源
    最近更新 更多