Kivy:获取小部件 ID 并通过唯一属性访问小部件 [英] Kivy: Get widgets ids and accessing widgets by unique property

查看:34
本文介绍了Kivy:获取小部件 ID 并通过唯一属性访问小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Kivy 的新手,我有一个演示我的问题的小演示片段:

I'm new to Kivy and I have this little demo snippet that demonstrates my problem:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder


class KivyGuiApp(App):
    def build(self):
        return root_widget


class MyBox(BoxLayout):
    def print_ids(self, *args):
        print("
ids:")
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.id))
    def print_names(self, *args):
        print("
names:")
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.name))



root_widget = Builder.load_string("""
MyBox:
    id: screen_manager
    name: 'screen_manager'

    SimpleLayout:
        id: simple_layout
        name: 'simple_layout'


<SimpleLayout@BoxLayout>:
    id: simple_layout_rule
    name: 'simple_layout_rule'
    Button:
        id: button_ids
        name: 'button_ids'
        text: 'print ids to console'
        on_release: app.root.print_ids()
    Button:
        id: button_names
        name: 'button_names'
        text: 'print names to console'
        on_release: app.root.print_names()
""")


if __name__ == '__main__':
    KivyGuiApp().run()

所以当你运行代码时会有两个按钮:

So When you run the code there will be two buttons:

  • 首先遍历所有小部件并打印它们的名称(按预期工作 - 为每个小部件返回名称"),
  • 第二个按钮也可以遍历所有小部件,但不是名称而是打印它们的 id(这不起作用 - 每个 id 都返回 None).

我的问题是:

  1. id"不是和name"一样的属性吗?
  2. 如何从 python 端访问每个小部件的 id?

额外问题:

  1. 我可以通过它的 id 全局"访问一个小部件(假设所有 id 都是唯一的)吗?全局"是指例如从MyBox:"小部件访问(在上面的代码中)id,而不引用父子,而只是通过 id(或者可能是每个小部件唯一的任何其他属性).我正在考虑为所有小部件创建一个字典 { id : widget object } 以便于访问,除非有另一种我不知道的方式?强调一下 - 我试图避免通过子父方式引用(当您以后想要更改小部件树时,这会很混乱)并且我想用 .kv 语言生成小部件.那么最好的方法是什么?

所以这是我能想到的通过唯一全局"ID 引用小部件的最简单方法.

So here's the easiest way I could think of to reference widgets by unique "global" id.

首先我创建了一个类,它将被我的 App 类继承:

First I created a class which will be inherited by my App class:

class KivyWidgetInterface():
    ''' interface for  global widget access '''
    global_widgets = {}
    def register_widget(self, widget_object):
        ''' registers widget only if it has unique gid '''
        if widget_object.gid not in self.global_widgets:
            self.global_widgets[widget_object.gid] = widget_object

    def get_widget(self, widget_gid):
        ''' returns widget if it is registered '''
        if widget_gid in self.global_widgets:
            return self.global_widgets[widget_gid]
        else:
            return None

因此,只有当它具有 gid - 一个小部件类变量 - 并且它是唯一的时,才会注册小部件.这样我就可以在这个字典中只存储重要的小部件.此外,从 .kv 和 python 端都可以轻松访问它.

So the widget will be registered only if it has gid - a widget class variable - and it is unique. This way I can store only vital widgets in this dict. Also, it is easily accessible from both .kv and python side.

现在我创建 gid 变量并将它们注册到 .kv 中的字典:

Now i create the gid variables and register them to the dict in .kv:

<PickDirectory>:
    gid: 'pick_directory'
    on_pos: app.register_widget(self)
    on_selection: app.get_widget('filelist').some_func()
<FileListView>:
    gid: 'filelist'
    on_pos: app.register_widget(self)   
    Button:
        name: 'not important'
    Button:
        gid: 'tab_browse_button1'
        on_pos: app.register_widget(self)

实际上困扰我的是,我在这个全局"字典中使用 'on_pos' 事件注册了我的小部件......我真的不喜欢,但我找不到任何可靠的方法来调用寄存器小部件初始化后的方法(on_pos 在 init 阶段之后立即调用,当小部件被定位时,以后很少,所以......根据我对 kivy api 的了解,似乎是最不麻烦的方式,订单小部件被初始化使用 .kv 语言等;所以如果有更好的方法,我会非常感谢任何指针).

Thing that bothers me actually is that I register my widgets in this "global" dictionary with the 'on_pos' event... which I really don't like, but I was unable to find any reliable way of calling a register method after the widget was initialized (on_pos is called right after the init phase, when widget is positioned and later very rarely, so... seemed like the least bothering way of doing that with my knowledge of kivy api, the order widgets are initialized with .kv language etc; so if there is a better way I'd be very grafeul for any pointers).

无论如何,通过这种方式,我可以轻松地从 .kv 将任何事件绑定到任何类中的任何方法

Anyhow, this way I can easy bind any event to any method in any class right from the .kv

要记住的一件事是 gid(全局 id)需要在全球范围内唯一,但我发现没有比在本地保持 id 唯一更令人不安的了(这对我来说可能同样或什至更令人困惑).正如我所说 - 我想以不同的方式注册小部件,但我找不到任何其他可靠的方法来做到这一点(而且我不认为 Clock 对于这些事情是可靠的).

One thing to remember is that the gid (global id's) need to be unique globally, but I don't find that any more disturbing than keeping ids unique locally(which could be equally or even more confusing for me). And as I said - I'd like to register the widgets differently, but I couldn't find any other reliable way of doing this (and I don't find Clock to be reliable for such things).

推荐答案

其实没有.您的小部件中的 name 是一个变量,而 id 只是一个小部件引用,weakref 根据文档.也许 python 文档 会帮助您了解它的工作原理.您所做的是打印 id,而不是小部件内的变量id".

Actually, no. name in your widgets is a variable and id is just a widget reference, weakref according to the docs. Maybe python docs will help you understand how it works. What you did was printing id, not a variable "id" inside a widget.

kivy docs 中解释说,在 kv 之后解析后,将 id 收集到 ObservableDict 中.id 的工作方式类似于 python dict 键 id:Widget,但只有通过字典 (ids) 访问.我认为 kv 解析器只是将所有 id 放入 dict 并且仅适用于它创建的 dict.

In the kivy docs it's explained that after kv is parsed, ids are collected into a ObservableDict. The id works like a python dict key id:Widget but only if accessed through the dictionary(ids). I think kv parser just takes all ids into dict and works only with the dict it creates.

Button:
    id: test
    text: 'self.id'
#or
Button:
    id: 'test'
    text: 'self.id'

即使它写成字符串,也没有任何变化.所以我希望解析器的行为是这样的:抓取 id: 之后的任何整个单词,变成一个字符串,附加到 ids 字典 <id_string>:Widget_weakref,忘记你的 .kv 中的 id,或者如果它再次与 .kv 一起工作,则忽略它.因此,当直接调用 id 时(不是像字典一样的 d[key]),它的行为就像一个空/None 变量.我希望我是对的.

Even if it's written like a string, nothing changes. So I expect parser to behave like this: grabs whatever whole word is after id:, turns to a string, appends to a ids dictionary <id_string>:Widget_weakref, forgets about id in your .kv or just ignores it if it works with .kv again. Therefore, when id is called directly(not dictionary-like d[key]), it behaves like an empty/None variable. I hope I'm right.


回答第二个和第三个:


To answer the second and the third one:

如果您的意思是通过 MyBox 中的 id 直接访问小部件,例如 SimpleLayout,那么可以.

If you mean accessing widget by id in MyBox directly for example SimpleLayout, then yes.

python 类:

self.ids.simple_layout

kv MyBox 规则:

kv MyBox rule:

MyBox:
    id: screen_manager
    name: 'screen_manager'
    BoxLayout:
        Label:
            id: my_label
            text: 'test'
        Button:
            text: 'button'
            on_release: self.text = root.ids.my_label.text

但是,要像 python 全局变量那样通过 id 访问所有小部件,这是不可能的.您需要先访问类/小部件,然后再访问它的 ids 字典

However, to access all widgets by their ids in way like python globals work, it's not possible. You'd need to access class/widget first and then its ids dictionary

这篇关于Kivy:获取小部件 ID 并通过唯一属性访问小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆