草庐IT

python - Kivy:获取小部件 ID 并通过唯一属性访问小部件

coder 2023-08-27 原文

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

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

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

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

我的问题是:

  1. “id”不是像“name”一样的属性吗?
  2. 如何从 Python 端访问每个小部件的 ID?

奖励问题:

  1. 我能否通过其 ID(假设所有 ID 都是唯一的)“全局”访问小部件?通过“全局”我的意思是例如访问(在上面的代码中)来自'MyBox:'小部件的id而不引用父子,而只是通过id(或者可能是每个小部件唯一的任何其他属性)。我正在考虑创建一个包含所有小部件的字典 { id : widget object } 以便于访问,除非有另一种我不知道的方法? 需要强调的是——我试图避免以父子方式进行引用(当您想稍后更改小部件树时,这会相当困惑)并且我想以 .kv 语言生成小部件。 那么最好的方法是什么?

编辑:

所以这是我能想到的通过唯一的“全局”id 引用小部件的最简单方法。

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

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 端轻松访问。

现在我创建 gid 变量并将它们注册到 .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,当小部件被定位时,以后很少,所以......根据我对 kivy api 的了解,这似乎是最不麻烦的方法,订单小部件被初始化使用 .kv 语言等;因此,如果有更好的方法,我将非常感激任何指点)。

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

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

最佳答案

实际上,没有。 name在你的小部件中是一个变量和id只是一个小部件引用,weakref根据文档。也许python docs将帮助您了解它是如何工作的。你所做的是打印 id ,而不是小部件内的变量“id”。

kivy docs据解释,在 kv 之后被解析后,ids 被收集到一个 ObservableDict 中。 id 就像 python 字典键一样工作 id:Widget但前提是通过字典访问( ids )。我想kv解析器只是将所有 id 放入字典中,并且只使用它创建的字典。

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

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


回答第二个和第三个:

如果您的意思是通过 id 访问小部件在MyBox直接举例SimpleLayout , 那么是的。

python 类:

self.ids.simple_layout

kv MyBox 规则:

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词典

关于python - Kivy:获取小部件 ID 并通过唯一属性访问小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35792621/

有关python - Kivy:获取小部件 ID 并通过唯一属性访问小部件的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  4. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  5. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  6. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  7. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  8. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  9. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  10. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

随机推荐