J'aimerais que mon application Kivy puisse générer plusieurs applications (c'est-à-dire de nouvelles fenêtres) sur une machine Windows pouvant communiquer entre elles.

ScreenManager et Popup ne le coupent pas car elles vivent dans la même fenêtre .. Je dois pouvoir faire glisser de nouveaux écrans sur plusieurs surveille et a donc besoin de plusieurs fenêtres.

Les documents Kivy indiquent explicitement que "Kivy ne prend en charge qu'une seule fenêtre par application: veuillez ne pas en créer plusieurs. "

Une recherche google produit cette approche simple de création simple d'une nouvelle application à partir d'une autre application, comme ceci:

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()

Cependant, lorsque je fais cela, il lance l'application dans la même fenêtre et se bloque, et mon terminal crache comme un fou:

Original exception was:
Error in sys.exceptionhook:

J'obtiens le même résultat si au lieu de ChildApp().run() je fais multiprocessing.Process(target=ChildApp().run()).start()

L'utilisation de la bibliothèque subprocess me rapproche de ce que je veux:

# 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()

Cela engendre la fenêtre enfant sans erreur, mais maintenant la fenêtre principale est verrouillée (toile blanche) et si je ferme la fenêtre enfant, elle est juste rouverte.

Ils doivent pouvoir passer des données entre eux. Des idées sur la façon de procéder correctement dans Windows? Ce message semble suggérer que cela est possible mais je ne sais pas par où commencer.

7
baconwichsand 16 juil. 2015 à 18:21

3 réponses

Meilleure réponse

La réponse de bj0 concernant le sous-processus était correcte.

Encore mieux, j'ai compris comment le faire via le multitraitement, ce qui permet une meilleure communication et le transfert d'informations entre les applications. Cela ne fonctionnait pas auparavant parce que j'ai fait multiprocessing.Process(target=ChildApp().run()).start() quand il devrait être multiprocessing.Process(target=ChildApp().run).start(). Les oeuvres suivantes

# 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()
1
baconwichsand 16 juil. 2015 à 17:34

Je ne sais pas pourquoi cela ne fonctionne pas avec le multitraitement (je ne l'ai jamais essayé), mais il devrait au moins fonctionner avec subprocess. La raison pour laquelle votre fenêtre principale est verrouillée est que subprocess.call bloque le thread qui l'appelle pendant qu'il attend que le sous-processus se termine et renvoie un résultat.

Vous souhaitez utiliser subprocess.Popen à la place, ce qui ne pas bloquer.

1
bj0 16 juil. 2015 à 16:48

J'ai essayé le code de baconwichsand et je peux confirmer avec Python 3.6 et Windows 10 que cela ne fonctionne pas. Apparemment, seules les classes d'objets de niveau supérieur peuvent être décapées, et puisque les deux applications héritent de la classe App, python génère une erreur. Cependant, une définition de niveau supérieur qui exécute simplement la commande ChildApp (). Run () peut être décapée et fonctionne. Voici mon code de travail.

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()

Et voici le code que j'utilise, y compris le Builder pour utiliser un fichier .kv partagé pour les deux fenêtres.

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()
3
WolframBeta 7 juin 2017 à 22:45