同时运行多个相互通信的Kivy应用程序

bac*_*and 5 python user-interface python-2.7 kivy

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

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

Kivy文档明确声明“ Kivy每个应用程序仅支持一个窗口:请不要尝试创建多个窗口。”

谷歌搜索产生了一种简单的方法,可以从另一个应用程序内简单地生成一个新的应用程序,如下所示:

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()
Run Code Online (Sandbox Code Playgroud)

但是,当我这样做时,它会在同一窗口中启动该应用程序并崩溃,并且我的终端会疯狂地吐出:

Original exception was:
Error in sys.exceptionhook:
Run Code Online (Sandbox Code Playgroud)

我得到同样的结果,如果代替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()
Run Code Online (Sandbox Code Playgroud)
# 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()
Run Code Online (Sandbox Code Playgroud)

这会无误地生成子窗口,但是现在主窗口已锁定(白色画布),并且如果我关闭子窗口,它将重新打开。

他们需要能够彼此之间传递数据。关于如何在Windows中正确执行此操作的任何想法?这篇文章似乎暗示这是可能的,但我不确定从哪里开始。

小智 5

我尝试了 baconwichsand 的代码,可以确认它在 Python 3.6 和 Windows 10 上不起作用。显然,只有顶级对象类可以被 pickle,并且由于两个应用程序都继承自 App 类,因此 python 会抛出错误。然而,仅执行 ChildApp().run() 命令的顶级定义可以被腌制并起作用。这是我的工作代码。

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()
Run Code Online (Sandbox Code Playgroud)

这是我正在使用的代码,包括为两个窗口使用共享 .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()
Run Code Online (Sandbox Code Playgroud)


bac*_*and 2

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()
Run Code Online (Sandbox Code Playgroud)
# 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()
Run Code Online (Sandbox Code Playgroud)