同时运行多个Kivy应用程序,彼此之间进行通信

时间:2015-07-16 15:21:26

标签: python python-2.7 user-interface kivy

我希望我的Kivy应用程序能够在可以相互通信的Windows机器上生成多个应用程序(即新窗口)。

ScreenManagerPopup选项不会削减它,因为它们位于同一个窗口中。我需要能够在多个监视器上拖动新屏幕,因此需要多个窗口。

Kivy docs明确声明"Kivy supports only one window per application: please don't try to create more than one."

Google搜索会在另一个应用中生成this simple approach简单的新应用,例如:

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

然而,当我这样做时,它会在同一个窗口中启动应用程序并崩溃,我的终端就像疯了一样吐出来:

Original exception was:
Error in sys.exceptionhook:

如果不是ChildApp().run()multiprocessing.Process(target=ChildApp().run()).start()

,我会得到相同的结果

使用subprocess库让我更接近我想要的东西:

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

这会生成子窗口而不会出现错误,但现在主窗口被锁定(白色画布),如果我关闭子窗口,它就会重新打开。

他们需要能够在彼此之间传递数据。有关如何在Windows中正确执行此操作的任何想法?这post似乎表明这是可能的,但我不知道从哪里开始。

3 个答案:

答案 0 :(得分:3)

我尝试过baconwichsand的代码,可以用Python 3.6和Windows 10确认它不起作用。显然只有顶级对象类可以被pickle,并且因为两个应用程序都继承自App类python会引发错误。但是,只需执行ChildApp()。run()命令的顶级定义就可以进行pickle和工作。这是我的工作代码。

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

这是我正在使用的代码,包括Builder为两个窗口使用共享的.kv文件。

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

答案 1 :(得分:1)

我不确定为什么它不能用于多处理(我从未尝试过),但它至少应该与subprocess一起使用。主窗口被锁定的原因是因为subprocess.call在等待子进程完成并返回结果时阻塞调用它的线程。

您想要使用subprocess.Popen,而不是阻止。

答案 2 :(得分:1)

bj0关于子流程的答案是正确的。

更好的是,我想出了如何通过多处理来实现这一点,这样可以在应用程序之间更好地进行通信和传递信息。它之前没有工作,因为我应该multiprocessing.Process(target=ChildApp().run()).start() multiprocessing.Process(target=ChildApp().run).start()# 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()
/token (creates capability for making calls - seems like this is where I pass in who is doing the call??)
/call (create twiml for Dial/Number)
/callstatus (handles status when call is over - intention is to perform some action on my backend to uupdate the specfic user account that started the call)