Kivy:创建自定义窗口小部件并通过kv创建新实例

时间:2019-11-28 00:11:07

标签: python python-3.x kivy

我正在尝试为我的一个小项目学习Kivy api,但是我陷入了这个问题,我实际上不知道自己是否在朝着正确的方向前进。

我创建了一个继承自Widget的自定义类,其中包含一些我知道会重复很多的东西:

#classes.py

from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty

class TextField(Widget):
    field_id = ObjectProperty(None)
    field_text = StringProperty('Label: ')
    field_placeholder = StringProperty('your text here')

    grid = GridLayout(cols=2)
    label = Label(text=field_text)
    tinput = TextInput(id=field_id, text=field_placeholder)
    grid.add_widget(label)
    grid.add_widget(tinput) 

然后我想在kv文件中创建类的实例

#main.kv
<MainLayout>
    cols:3
    TextField:
        field_id:'someid'
        field_text:'My Label: '
        field_placeholder: 'My placeholder'

现在,问题是当我运行它时,我得到:

ValueError: Label.text accept only str

当我打印field_text时,我得到

<StringProperty name=>

所以我猜它不是str,就像错误说的那样。我只是完全误解了财产吗?我想用其他方式做些什么吗?

提前感谢您的时间!


编辑:我能想到的唯一问题就是入口点。

#main.py
import kivy
kivy.require('1.8.0')

from example.exampleapp import ExampleApp

if __name__ == "__main__":
    ExampleApp().run()
#exampleapp.py
from example.classes import *
from kivy.uix.gridlayout import GridLayout

with open('zapador/kv/main.kv', encoding='utf8') as f: 
    Builder.load_string(f.read())

class Mainlayout(GridLayout):
    pass

class ExampleApp(App):

    def build(self):
        return Mainlayout()

1 个答案:

答案 0 :(得分:0)

您的代码的一个问题是TextField中的代码部分,其中似乎是您试图定义自定义类的布局:

grid = GridLayout(cols=2)
label = Label(text=field_text)
tinput = TextInput(id=field_id, text=field_placeholder)
grid.add_widget(label)
grid.add_widget(tinput) 

如果要在python中定义布局,则必须在__init__()方法内部的方法中进行。但是,如果执行此操作,则在text方法中设置的__init__()字段将被设置为StringProperty属性的初始值,并且不会更新StringProperty已更改(除非您添加更多代码来处理该事件并修改关联的text属性)。

一种更好,更简单的方法是在kv中进行布局,并在kv更改时让text处理StringProperty属性的更新。因此,我建议将您的TextField类更改为:

#classes.py

from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty

class TextField(Widget):
    field_id = ObjectProperty(None)
    field_text = StringProperty('Label: ')
    field_placeholder = StringProperty('your text here')

并在main.kv中定义布局:

#main.kv
<MainLayout>
    cols:3
    TextField:
        # field_id:'someid'
        field_text:'My Label: '
        field_placeholder: 'My placeholder'

<TextField>:
    field_id: ti
    GridLayout:
        cols: 2
        Label:
            text: root.field_text
        TextInput:
            id: ti
            text: root.field_placeholder

通过这种安排,对StringProperty的更改将反映在text内部的TextField属性中。请注意,我没有将您的field_id ObjectProperty用作id的{​​{1}}。我认为不可能将TextInput用作ObjectProperty。我已将您的id field_id用作ObjectProperty

中对TextInput的引用