Search code examples
pythonkivywindows-11

How to restart a kivy window after using ESC key


How to restart a kivy window after using ESC key

I've been trying to open my kivy app a second time after closing the window (because it's a tray app). However I run into an exception, when closing the App using the Esc key and then re-running the app.

This error doesn't happen, when I close the window by clicking the cross in the window bar instead.

Here is some code example reproducing the issue:

from time import sleep

from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget


class MyApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.my_window = Widget()

    def build(self):
        return self.my_window

    def on_stop(self):
        Window.hide()


if __name__ == '__main__':
    Window.top = 30
    app = MyApp()
    app.run()
    # Restart the App after one second
    sleep(1)
    Window.show()
    app.run()

When closing the first window using the esc key, the second window does not appear. Instead I receive this:

Connected to pydev debugger (build 223.8836.43)
[INFO   ] WM_MotionEventProvider <kivy.input.providers.wm_touch.WM_MotionEventProvider object at 0x0000016E2A86E790>
[INFO   ] WM_MotionEventProvider <kivy.input.providers.wm_touch.WM_MotionEventProvider object at 0x0000016E2A8816D0>
[ERROR  ] [Base        ] No event listeners have been created
[ERROR  ] [Base        ] Application will leave
python-BaseException

Is there some way to avoid this problem?

(This happens in kivy2.3.0 on python3.11 and windows11)


Solution

  • This is the full solution I went with, in case anyone else comes across this issue. I've first disabled the built-in escape as suggested by @nigh_anxiety. Then added my own method to close the window.

    from time import sleep
    
    from kivy.app import App
    from kivy.core.window import Window
    from kivy.uix.widget import Widget
    from kivy.config import Config
    
    Config.set('kivy', 'exit_on_escape', '0')  # Disable the built-in feature
    
    
    class MyApp(App):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.my_window = Widget()
    
            self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
            self._keyboard.bind(on_key_down=self._on_keyboard_down)
    
        def _keyboard_closed(self):
            self._keyboard.unbind(on_key_down=self._on_keyboard_down)
            self._keyboard = None
    
        def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
            _, key = keycode
            if key == 'escape':
                app.stop()
    
        def build(self):
            return self.my_window
    
    
    if __name__ == '__main__':
        Window.top = 30
        app = MyApp()
        app.run()
        Window.hide()
        # Restart the App after one second
        sleep(1)
        Window.show()
        app.run()