【问题标题】:Running multiple Kivy apps at same time that communicate with each other同时运行多个相互通信的 Kivy 应用程序
【发布时间】:2015-10-06 03:24:56
【问题描述】:

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

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

Kivy 文档明确声明 "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:

如果我用multiprocessing.Process(target=ChildApp().run()).start()代替ChildApp().run(),我会得到相同的结果

使用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 似乎表明这是可能的,但我不知道从哪里开始。

【问题讨论】:

    标签: python python-2.7 user-interface kivy


    【解决方案1】:

    我尝试了 baconwichsand 的代码,可以用 Python 3.6 和 Windows 10 确认它不起作用。显然只能腌制顶级对象类,并且由于两个应用程序都从 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()
    

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

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

    【讨论】:

    • 它不适用于我在带有 Kivy 2.0.0rc2 和 Python 3.8.5 的 Ubuntu Focal 上。主窗口在移动和冻结时有时会变黑。
    【解决方案2】:

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

    您想改用subprocess.Popen,它不会阻止。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 可能是 Python 3.4 或者可能是 OS X,但我可以确认在这些条件下这不起作用。
      • 嗨,我通过运行上述两个脚本得到了一个EOFError : Ran out of input,知道为什么吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-29
      • 2022-11-23
      • 2020-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多