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

查看:84
本文介绍了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("\nids:")
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.id))
    def print_names(self, *args):
        print("\nnames:")
        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. 不是像'name'一样'id'一个属性吗?
  2. 如何从python端访问每个小部件的ID?

奖金问题:

  1. 我可以通过其ID来全局"访问一个小部件(假设所有ID都是唯一的)吗? 全局"是指,例如,从"MyBox:"小部件访问(在上面的代码中)ID,而不引用父子级,而仅通过ID(或可能是每个小部件唯一的其他任何属性)访问.我正在考虑创建所有小部件的字典{id:小部件对象},以便于访问,除非有我不知道的另一种方法? 要强调的是-我正尝试避免通过子代父方式进行引用(当您以后要更改窗口小部件树时,这很混乱),我想以.kv语言生成窗口小部件. 那么最好的方法是什么?
  1. Can I access a widget "globally" by it's id (assuming all id's are unique)? By "globally" I mean for example accessing (in code above) ids from 'MyBox:' widget without referencing parent-child, but just by ids (or maybe any other property that would be unique to every widget). I was thinking of creating a dictionary { id : widget object } of all widgets for easy access, unless there is another way I'm not aware of? To emphasize - I'm trying to avoid referencing by children-parent way (which is rather messy when you want to change your widget tree later) and I'd like to generate widgets in .kv language. So what would be the best way to do that?

因此,这是我想到的通过唯一的全局" 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中的dict:

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,当小部件定位后又很少见,所以...据我了解的k​​ivy 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文档中,解释了在解析kv之后,ID为收集到一个ObservableDict中.该id就像python dict键id:Widget一样工作,但仅在通过dictionary(ids)访问时才有效.我认为kv解析器只是将所有ID放入字典中,并且只能与它创建的字典一起使用.

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])时,它的行为就像一个empty/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中通过MyBox中的id访问小部件,则可以.

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访问所有小部件,这是不可能的.您需要先访问class/widget,然后再访问其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天全站免登陆