用python读/写kivy小部件属性

Posted

技术标签:

【中文标题】用python读/写kivy小部件属性【英文标题】:Read/write kivy widget attributes with python 【发布时间】:2016-10-12 18:47:33 【问题描述】:

我对 Python 有基本的实用知识,我正在尝试自学 kivy。我希望能够让 Python 读取和写入数据到 kivy 小部件。

假设有一个地址簿应用程序可以将日期和时间插入到 TextInput 中。当应用程序启动时,只需让 Python 获取日期和时间并插入正确吗?

此程序代码将给出一个简单地址簿的示例:

from kivy.app import App

from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput

class AddressApp(App):
    def build(self):
        pass

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

这是它的地址.kv 文件:

GridLayout:
    cols: 2
    Label:
    text: 'Date'
TextInput:
    id: textinputdate
Label:
    text: 'Time'
TextInput:
    id: textinputtime
Label:
    text: 'Name'
TextInput:
    id: textinputname
Label:
    text: 'Address'
TextInput:
    id: textinputaddress
Label:
    text: 'email'
TextInput:
    id: textinputemail
Label:
    text: 'Phone'
TextInput:
    id: textinputphone

之后,如果我想让 Python 读取...我不知道...呃...电话号码 TextInput,该怎么做?

【问题讨论】:

【参考方案1】:

如果您希望某些小部件具有额外功能(例如:在应用启动时加载当前日期),请创建该小部件的自定义版本,以满足要求。在规则中读取小部件的值非常简单。示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
import time

gui = '''
BoxLayout:
    orientation: 'vertical'

    GridLayout:
        cols: 2

        Label:
            text: 'current time'

        DateInput:
            id: date_input

    Button:
        text: 'write date to console'
        on_press: print(date_input.text)
'''


class DateInput(TextInput):

    def __init__(self, **kwargs):
        super(DateInput, self).__init__(**kwargs)
        Clock.schedule_interval(self.update, 1)  # update every second

    def update(self, dt):
        self.text = time.ctime()


class Test(App):

    def build(self):
        return Builder.load_string(gui)


Test().run()

【讨论】:

【参考方案2】:

FreeNode IRC 频道 kivy 上一个名叫 spinD20 的人向我展示了这个。

还有一种比添加自定义小部件更简单的方法。只要您只是想在应用启动时向 TextInput 中插入一个值...

地址.py

from kivy.app import App

from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput

import time

class AddressApp(App):
        def build(self):
            self.root.ids.textinputdate.text = time.strftime("%x")

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

地址.kv

GridLayout:
    cols: 2
    Label:
        text: 'Date'
    TextInput:
        id: textinputdate
    Label:
        text: 'Time'
    TextInput:
        id: textinputtime
    Label:
        text: 'Name'
    TextInput:
        id: textinputname
    Label:
        text: 'Address'
    TextInput:
        id: textinputaddress
    Label:
        text: 'email'
    TextInput:
        id: textinputemail
    Label:
        text: 'Phone'
    TextInput:
        id: textinputphone

【讨论】:

强烈建议不要将任何代码放入build 方法中,这与应用程序的一般行为无关。有时您想在其他应用程序中重复使用小部件,而这种解决方案使得在没有不必要的进一步重写的情况下无法实现。换句话说,这些东西应该嵌入到自定义小部件中,以节省您将来的工作。 视情况而定。在这种情况下,我将默认值放入 TextInput。换句话说,我正在完成应用程序设置。我不需要创建自定义 TextInput 库,如果我这样做了,我最终会创建六个这样的库,这比我在启动时向其中插入值要多。 然后将它们填充到父小部件中,在本例中为网格布局。这只是一个好习惯。 你能举个例子吗?【参考方案3】:

spinningD20 在这里。公平地说,我回答了他的直接问题,但随后还解释了将其封装到自定义小部件中:

from kivy.app import App

from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput

import time


class DateInput(TextInput):
    def __init__(self, **kwargs):
        super(DateInput, self).__init__(**kwargs)
        self.text = time.strftime("%x")


class Container(GridLayout):
    def __init__(self, **kwargs):
        # using super calls the base class's init.  We'll hand it keyword arguments we received, just in case
        super(Container, self).__init__(**kwargs)
        # now we can do stuff here
        self.ids.textinputtime.text = 'from python'


class AddressApp(App):
        def build(self):
            pass

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

在 kv 中:

# anything without the <> symbols is part of the App's kv.  So here's the one thing the App will have in its kv
Container:

# here's the custom widget's kv, just like your previous example
<Container>:
    cols: 2
    Label:
        text: 'Date'
    DateInput:
        id: dateinputdate
    Label:
        text: 'Time'
    TextInput:
        id: textinputtime
    Label:
        text: 'Name'
    TextInput:
        id: textinputname
    Label:
        text: 'Address'
    TextInput:
        id: textinputaddress
    Label:
        text: 'email'
    TextInput:
        id: textinputemail
    Label:
        text: 'Phone'
    TextInput:
        id: textinputphone

我希望这会有所帮助!祝戴夫好运!

【讨论】:

【参考方案4】:

另一个例子,解释如何通过父网格布局用当前日期填充文本输入,避免 App 类保持干净:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.gridlayout import GridLayout
import time

gui = '''
#:import time time
DateGrid
    cols: 1

    Label:
        text: 'Customer data'

    TextInput:
        id: date_input

    TextInput:
        id: name_input

    TextInput:
        id: email_input

    Button:
        text: 'refresh date'
        on_press: date_input.text = time.ctime()
'''


class DateGrid(GridLayout):

    def __init__(self, **kwargs):
        super(DateGrid, self).__init__(**kwargs)
        Clock.schedule_once(self.populate_inputs, 0.5)

    def populate_inputs(self, *x):
        _ = self.ids

        _.date_input.text = time.ctime()
        _.name_input.text = 'Foo Snowman'
        _.email_input.text = 'foo.snowman@gravy.com'


class Test(App):

    def build(self):
        return Builder.load_string(gui)


Test().run()

【讨论】:

以上是关于用python读/写kivy小部件属性的主要内容,如果未能解决你的问题,请参考以下文章

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

在 Kivy 中传递自定义小部件属性

运行代码时更新 kivy 小部件的属性

Python kivy 较低的小部件位置

Python kivy 较低的小部件位置

kivy python 小部件实例或所有小部件