Ejecutando múltiples aplicaciones Kivy al mismo tiempo que se comunican entre sí.

Me gustaría que mi aplicación Kivy pueda generar múltiples aplicaciones (es decir, nuevas ventanas) en una máquina con Windows que puedan comunicarse entre sí.

Las opciones de ScreenManager y Popup no lo cortarán porque viven en la misma ventana … Necesito poder arrastrar nuevas pantallas a través de múltiples monitores y, por lo tanto, necesito múltiples ventanas.

Kivy docs declara explícitamente que “Kivy admite solo una ventana por aplicación: no intente crear más de una”.

Una búsqueda en Google produce este enfoque simple de generar una nueva aplicación desde otra aplicación, como por ejemplo:

from kivy.app import App from kivy.uix.button import Button from kivy.uix.label import Label class ChildApp(App): def build(self): return Label(text='Child') class MainApp(App): def build(self): b = Button(text='Launch Child App') b.bind(on_press=self.launchChild) return b def launchChild(self, button): ChildApp().run() if __name__ == '__main__': MainApp().run() 

Sin embargo, cuando hago esto, se inicia la aplicación dentro de la misma ventana y se bloquea, y mi terminal escupe como loca:

 Original exception was: Error in sys.exceptionhook: 

Obtengo el mismo resultado si en lugar de ChildApp().run() hago multiprocessing.Process(target=ChildApp().run()).start()

El uso de la biblioteca de subprocess me acerca a lo que quiero:

 # filename: test2.py from kivy.app import App from kivy.uix.label import Label class ChildApp(App): def build(self): return Label(text='Child') if __name__ == '__main__': ChildApp().run() 

 # filename: test.py from kivy.app import App from kivy.uix.button import Button import subprocess class MainApp(App): def build(self): b = Button(text='Launch Child App') b.bind(on_press=self.launchChild) return b def launchChild(self, button): subprocess.call('ipython test2.py', shell=True) if __name__ == '__main__': MainApp().run() 

Esto genera la ventana secundaria sin error, sin embargo, ahora la ventana principal está bloqueada (canvas en blanco) y si cierro la ventana secundaria, simplemente se vuelve a abrir.

Necesitan poder pasar datos entre ellos. ¿Alguna idea sobre cómo hacer esto correctamente en Windows? Esta publicación parece sugerir que esto es posible, pero no estoy seguro de por dónde empezar.

Probé el código de baconwichsand y puedo confirmar que con Python 3.6 y Windows 10 no funciona. Al parecer, solo las clases de objetos de nivel superior pueden ser decapadas, y dado que ambas aplicaciones heredan de la clase de aplicación, python genera un error. Sin embargo, una definición de nivel superior que simplemente ejecuta el comando ChildApp (). Run () puede ser decapada y funciona. Aquí está mi código de trabajo.

 import multiprocessing from kivy.app import App from kivy.uix.label import Label class MainApp(App): def build(self): return Label(text='Main App Window') class OtherApp(App): def build(self): return Label(text='Other App Window') def open_parent(): MainApp().run() def open_child(): OtherApp().run() if __name__ == '__main__': a = multiprocessing.Process(target=open_parent) b = multiprocessing.Process(target=open_child) a.start() b.start() 

Y aquí está el código que estoy usando, incluido el Generador para usar un archivo .kv compartido para ambas ventanas.

 import multiprocessing from kivy.lang import Builder from kivy.app import App from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.widget import Widget class MainRoot(Widget): pass class OtherRoot(Widget): pass class MainApp(App): def build(self): Builder.load_file('B:\Python_Codes\Testing Grounds\shared.kv') main = MainRoot() return main class OtherApp(App): def build(self): Builder.load_file('B:\Python_Codes\Testing Grounds\shared.kv') other = OtherRoot() return other def open_parent(): MainApp().run() def open_child(): OtherApp().run() if __name__ == '__main__': a = multiprocessing.Process(target=open_parent) b = multiprocessing.Process(target=open_child) a.start() b.start() 

No estoy seguro de por qué no funciona con multiprocesamiento (nunca lo he intentado), pero al menos debería funcionar con subprocess . La razón por la que su ventana principal está bloqueada es porque subprocess.call bloquea el subproceso que lo llama mientras espera que el subproceso termine y devuelva un resultado.

Desea utilizar subprocess.Popen lugar, que no bloquea.

La respuesta de bj0 con respecto al subproceso fue correcta.

Aún mejor, descubrí cómo hacerlo a través del multiprocesamiento, lo que permite una mejor comunicación y transmisión de información entre aplicaciones. No funcionaba antes porque hice multiprocessing.Process(target=ChildApp().run()).start() cuando debería ser multiprocessing.Process(target=ChildApp().run).start() . Los siguientes trabajos

 # filename: test.py from kivy.app import App from kivy.uix.button import Button from test2 import ChildApp import multiprocessing class MainApp(App): def build(self): b = Button(text='Launch Child App') b.bind(on_press=self.launchChild) return b def launchChild(self, button): app = ChildApp() p = multiprocessing.Process(target=app.run) p.start() if __name__ == '__main__': MainApp().run() 

 # filename: test2.py from kivy.app import App from kivy.uix.label import Label class ChildApp(App): def build(self): return Label(text='Child') if __name__ == '__main__': ChildApp().run()