【问题标题】:How to prevent multiple instances of the Root-Widget in Kivy如何在 Kivy 中防止 Root-Widget 的多个实例
【发布时间】:2017-11-21 07:10:40
【问题描述】:

好的,我尝试在 Kivy 中制作我的第一个应用程序,但我的根小部件的多个实例出现问题。

我需要在运行时向我的应用程序添加小部件。 (显示电子表格)

但由于 Root 小部件的多个实例,我无法使用 kivy ids 查找对象访问小部件。

https://kivy.org/docs/guide/lang.html

我制作了三个按钮来在控制台中显示问题 按钮 -1-、-2- 和 -3-

请解释一下为什么会有多个实例以及如何防止它,以便代码可以工作。

感谢您的帮助!

文件 --> Match.py​​

    #!python
    from __future__ import print_function
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import ObjectProperty, StringProperty
    from kivy.uix.boxlayout import BoxLayout
    from kivy.app import App
    import gc

    class my_gc():
        def search_g(self):
            for obj in gc.get_objects():
                if isinstance(obj, Root):
                    try:
                        print(obj.ids)
                    except:
                        print('fail')

    #Root Widget
    class Root(BoxLayout):

        sm = ObjectProperty(None)
        sc0 = ObjectProperty(None)
        sc1 = ObjectProperty(None)
        sc2 = ObjectProperty(None)
        sc3 = ObjectProperty(None)

        mylbl0 = StringProperty('screen 0')
        mylbl1 = StringProperty('screen 1')
        mylbl2 = StringProperty('screen 2')
        mylbl3 = StringProperty('screen 3')

        def find_ids(self):
            print(self.ids)

    class Screen_Manager(ScreenManager):
        pass

    class Screen_0(Screen):
        pass

    class Screen_1(Screen):
        pass

    class Screen_2(Screen):
        pass

    class Screen_3(Screen):
        pass

    class Match(App):
        rootwidget = Root()
        sm = Screen_Manager()
        gc = my_gc()

        def build(self):
            pass

    Match().run()

文件 --> Match.kv

    #Root Widget (BoxLayout)
    Root:
        sm: sm
        sc1: sc0
        sc1: sc1
        sc1: sc2
        sc1: sc3
        BoxLayout:
            spacing: '20dp'
            orientation: 'vertical'
            Screen_Manager:
                id: sm
                Screen_0:
                    id: sc0
                    name: 'sc0'
                    manager: 'sm'
                    BoxLayout:
                        id: box_0-0
                        Label:
                            id: lbl_0
                            text: app.rootwidget.mylbl0
                        Label:
                            id: lbl_0-1
                            text: root.mylbl0
                Screen_1:
                    id: sc1
                    name: 'sc1'
                    manager: 'sm'
                    Label:
                        id: lbl1
                        text: root.mylbl1
                Screen_2:
                    id: sc2
                    name: 'sc2'
                    manager: 'sm'
                    Label:
                        id: lbl2
                        text: root.mylbl2
                Screen_3:
                    id: sc3
                    name: 'sc3'
                    manager: 'sm'
                    Label:
                        id: lbl3
                        text: root.mylbl3

            #Tab-Buttons
            BoxLayout:
                size_hint: 1 , None
                height: '60dp'
                orientation: 'horizontal'
                Button:
                    text: '-0-'
                    on_press: root.sm.current = sc0.name
                Button:
                    text: '-1-'
                    on_press: root.sm.current = sc1.name
                Button:
                    text: '-2-'
                    on_press: root.sm.current = sc2.name
                Button:
                    text: '-3-'
                    on_press: root.sm.current = sc3.name
                Button:
                    text: '<'
                    size_hint: None , 1
                    width: '60dp'
                    on_press: root.sm.current = root.sm.previous()
                Button:
                    text: '>'
                    size_hint: None , 1
                    width: '60dp'
                    on_press: root.sm.current = root.sm.next()
                Button:
                    text: '-b1-'
                    size_hint: None , 1
                    width: '60dp'
                    #on_press: root.search_g()              #<-- doesn't work
                    on_press: app.gc.search_g()             #<-- works
                Button:
                    text: '-b2-'
                    size_hint: None , 1
                    width: '60dp'
                    on_press: root.find_ids()               #<-- doesn't work
                    on_press: app.rootwidget.find_ids()     #<-- works
                Button:
                    text: '-b3-'
                    size_hint: None , 1
                    width: '60dp'
                    on_press: print(root.mylbl1)            #<-- works
                    on_press: print(app.rootwidget.mylbl1)  #<-- works

【问题讨论】:

  • 其实显示问题的按钮是-b1-, -b2-, -b3-

标签: python-3.x kivy


【解决方案1】:

多实例 - 根小部件

根据您的代码,您没有根小部件的多个实例。根据 kv 文件 match.kv,您的根小部件是 Root:

root.search_g()

它不起作用,因为您的根类 Root(BoxLayout) 没有 search_g() 方法。

root.find_ids - 有效

当我注释掉 app.rootwidget.find_ids 时,对 root.find_ids 的调用有效,即它打印了 ID。关键字 root 仅在规则定义中可用,表示规则的根小部件(规则的第一个实例)。当你的 kv 文件被解析时,kivy 会收集所有带有 id 标记的小部件并将它们放在 self.ids 字典类型属性中。

app.rootwidget.find_ids

它可以工作,但没有 id,因为它引用了已启动对象、Root 类中的方法 find_ids。 rootwidget 只是一个名称变量,它与 Root: 中的对象不同p>

从随附的屏幕截图中,您会注意到 root.find_ids 和 app.rootwidget.find_ids 的对象位置不同。

动态添加小部件

要在应用运行时将小部件动态添加到应用中,您必须执行以下操作。例如,请参考我在Kivy/python : when i click row then it shows error IndexError: list index out of range的另一篇文章

Python 脚本 - match.py​​

​​>
  1. 添加如下导入语句:

    从 kivy.properties 导入 ObjectProperty

  2. 声明一个变量(例如容器)或 ObjectProperty 类型,例如在根类中

    类根(BoxLayout): 容器 = ObjectProperty(None)

  3. 在添加之前删除所有动态添加的小部件

  4. 动态添加小部件。

kv 文件 - match.kv

  1. 定义布局,例如您的 kv 文件中的 BoxLayout 或 GridLayout。
  2. 为布局指定一个 ID,例如kv 文件中的容器。
  3. 将 ObjectProperty 连接到 id

    根: 容器:容器 ... # 动态添加小部件的容器 盒子布局: id: 容器

解决方案

解决办法是声明一个ObjectProperty,rootwidget如下:

sn-p

class Match(App):
    rootwidget = ObjectProperty(None)
    title = "Solution App"

    gc = my_gc()

    def build(self):
        self.rootwidget = Root()
        return self.rootwidget

match.py​​

​​>
#!python
from __future__ import print_function
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
import gc


class my_gc():
    def search_g(self):
        print("my_gc.search_g called")
        for obj in gc.get_objects():
            if isinstance(obj, Root):
                try:
                    print("obj={0}, ids={1}".format(obj, obj.ids))
                    for key, value in obj.ids.items():
                        print("   key={0}, value={1}".format(key, value))
                except:
                    print('fail')


# Root Widget
class Root(BoxLayout):
    sm = ObjectProperty(None)
    sc0 = ObjectProperty(None)
    sc1 = ObjectProperty(None)
    sc2 = ObjectProperty(None)
    sc3 = ObjectProperty(None)

    mylbl0 = StringProperty('screen 0')
    mylbl1 = StringProperty('screen 1')
    mylbl2 = StringProperty('screen 2')
    mylbl3 = StringProperty('screen 3')

    def find_ids(self):
        print("Root.find_ids called")
        print("self={0}, self.ids={1}".format(self, self.ids))
        for key, value in self.ids.items():
            print("   key={0}, value={1}".format(key, value))


class Screen_Manager(ScreenManager):
    pass


class Screen_0(Screen):
    pass


class Screen_1(Screen):
    pass


class Screen_2(Screen):
    pass


class Screen_3(Screen):
    pass


class Match(App):
    rootwidget = ObjectProperty(None)
    title = "Solution App"

    gc = my_gc()

    def build(self):
        self.rootwidget = Root()
        return self.rootwidget


if __name__ == "__main__":
    Match().run()

match.kv

#Root Widget (BoxLayout)
<Root>:
    sm: sm
    sc1: sc0
    sc1: sc1
    sc1: sc2
    sc1: sc3

    BoxLayout:
        spacing: '20dp'
        orientation: 'vertical'
        Screen_Manager:
            id: sm
            Screen_0:
                id: sc0
                name: 'sc0'
                manager: 'sm'
                BoxLayout:
                    id: box_0-0
                    Label:
                        id: lbl_0
                        text: root.mylbl0
                    Label:
                        id: lbl_0-1
                        text: root.mylbl0
            Screen_1:
                id: sc1
                name: 'sc1'
                manager: 'sm'
                Label:
                    id: lbl1
                    text: root.mylbl1
            Screen_2:
                id: sc2
                name: 'sc2'
                manager: 'sm'
                Label:
                    id: lbl2
                    text: root.mylbl2
            Screen_3:
                id: sc3
                name: 'sc3'
                manager: 'sm'
                Label:
                    id: lbl3
                    text: root.mylbl3

        #Tab-Buttons
        BoxLayout:
            id: secondBoxLayout
            size_hint: 1 , None
            height: '60dp'
            orientation: 'horizontal'
            Button:
                text: '-0-'
                on_press: root.sm.current = sc0.name
            Button:
                text: '-1-'
                on_press: root.sm.current = sc1.name
            Button:
                text: '-2-'
                on_press: root.sm.current = sc2.name
            Button:
                text: '-3-'
                on_press: root.sm.current = sc3.name
            Button:
                text: '<'
                size_hint: None , 1
                width: '60dp'
                on_press: root.sm.current = root.sm.previous()
            Button:
                text: '>'
                size_hint: None , 1
                width: '60dp'
                on_press: root.sm.current = root.sm.next()
            Button:
                text: '-b1-'
                size_hint: None , 1
                width: '60dp'
                on_press:
                    print("\non_press: {}".format(self.text))
                    # root.search_g()              #<-- doesn't work
                    print("    app.gc_search_g()")
                    app.gc.search_g()             #<-- works
            Button:
                text: '-b2-'
                size_hint: None , 1
                width: '60dp'
                on_press:
                    print("\non_press: {}".format(self.text))
                    print("    root.find_ids()")
                    root.find_ids()               #<-- works
                    print("\n    app.root.find_ids()")
                    app.rootwidget.find_ids()     #<-- works
            Button:
                text: '-b3-'
                size_hint: None , 1
                width: '60dp'
                on_press:
                    print("\non_press: {}".format(self.text))
                    print(root.mylbl1)            #<-- works
                    print(app.rootwidget.mylbl1)  #<-- works

输出

【讨论】:

  • 我已经更新了我的帖子,其中包含在应用程序运行时动态添加小部件的步骤和示例。
猜你喜欢
  • 2016-06-25
  • 2016-11-29
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 2011-01-11
相关资源
最近更新 更多