简体   繁体   English

更新 kivy recycleview self.data from textinput change

[英]Update kivy recycleview self.data from textinput change

I haven't been able to figure out how to do update the data from a change in the text input on the UI.我无法弄清楚如何从 UI 上的文本输入更改中更新数据。 I've been trying to base my code on the following: https://github.com/kivy/kivy/issues/5318我一直在尝试将我的代码基于以下内容: https://github.com/kivy/kivy/issues/5318

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput

import re

string_to_build_recycleview = '''
<rowTest@BoxLayout>:
    #canvas:
        # Rectangle:
            # size: self.size
            # pos: self.pos
    name_text: 'Someone Else'
    stroke_text: 'Butterfly'
    classification_text: '3'
    time_text: '9:99.99'

    BoxLayout:
        orientation: 'horizontal'
        Label:
            id: name
            text: root.name_text

        Label:
            id: stroke
            text: root.stroke_text

        ClassificationTI:
            id: classification
            padding: (8, 1, 2, 1)
            halign: 'center'
            size: (20,20)
            multiline: 'False'
            input_filter: 'int'
            text: root.classification_text
            on_text: root.classification_text = self.text

        TimeTI:
            padding: (8, 1, 2, 1)
            halign: 'center'
            size: (20,20)
            multiline: 'False'
            text: root.time_text
            #on_text: root.time_text = self.text

<RecycleViewTEST@RecycleView>:
    id: myListToTest
    scroll_type: ['bars', 'content']
    #scroll_wheel_distance: dp(114)
    bar_width: dp(10)
    viewclass: 'rowTest'

    RecycleBoxLayout:
        default_size: None, dp(20)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        spacing: dp(2)
 '''

class ClassificationTI(TextInput):
    def insert_text(self,substr,from_undo=False):
        if substr.isnumeric():
            return super(ClassificationTI, self).insert_text(substr,from_undo=from_undo)
        return super(ClassificationTI, self)

class TimeTI(TextInput):
    def insert_text(self,substr,from_undo=False):
        if substr.isnumeric() or substr == ":" or substr == ".":
            return super(TimeTI, self).insert_text(substr,from_undo=from_undo)
        return super(TimeTI, self)

class RecycleViewTEST(RecycleView):
    def __init__(self, **kwargs):
        super(RecycleViewTEST, self).__init__(**kwargs)
        Builder.load_string(string_to_build_recycleview)
        self.initial_populate()

    def on_enter(self, *args):
        self.get_real_data()

    def initial_populate(self):
        data = (('TheFirstOne', 'free', '9', '1:01.60'),('TheSecondOne', 'free', '9', '1:01.60'))
        self.data = [{'name_text':n,'stroke_text':s,'classification_text':c,'time_text':t} for n,s,c,t in data]
        print(self.data)


    def validate_classification(self,classification):
        if classification.isnumeric() and int(classification) > 14 and int(classification) < 1:
            return "Not Valid"
        return classification

    def validate_time(self,time):
        if re.match(r"([0-9]?[0-9]:)?([0-5][0-9])\.([0-9][0-9])", time) is None:
            return "Not Valid"
        return time

    def do_stuff(self):
        for i in range(len(self.data)):
            print(self.data[i])
            self.data[i]['classification_text'] = self.validate_classification(self.data[i]['classification_text'])
            self.data[i]['time_text'] = self.validate_time(self.data[i]['time_text'])
            print(self.data[i])
        self.refresh_from_data()

string_to_build_the_form = '''
<TheForm>:
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            orientation: 'horizontal'
            Label:
                size_hint: (None, None)
                size: (200, 27)
                text: '[u]Name[/u]'
                markup: True
            Label:
                size_hint: (None, None)
                size: (200, 27)
                text: '[u]Stroke[/u]'
                markup: True
            Label:
                size_hint: (None, None)
                size: (190, 27)
                text: '[u]Class[/u]'
                markup: True
            Label:
                size_hint: (None, None)
                size: (200, 27)
                text: '[u]Time (mm:ss.hh)[/u]'
                markup: True

        BoxLayout:
            size_hint: (1,None)
            RecycleViewTEST:
                id: myListToTest

        BoxLayout:
            orientation: 'horizontal'

            Button:
                size_hint: (None,None)
                size: (150,50)
                text: "Validate"
                on_release: root.validate()

            Button:
                id: save_recalc
                size_hint: (None,None)
                size: (150,50)
                text: "Save & Recalculate"
                disabled: True

'''


class TheForm(BoxLayout):
    def __init__(self, **kwargs):
        super(TheForm, self).__init__(**kwargs)
    Builder.load_string(string_to_build_the_form)

    def validate(self, *args):
        self.ids.myListToTest.do_stuff()
        self.ids.save_recalc.disabled = False


class TheTEST(App):
    def build(self):
        sm = TheForm()
        return sm

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

This is after I change the values text input boxes.这是在我更改值文本输入框之后。 The before refers to validating the classification and time then changing the data.之前是指验证分类和时间然后更改数据。 After executing validate(), the textinput text returns to the original numbers:执行 validate() 后,textinput 文本恢复为原来的数字:

BEFORE: {'name_text': 'TheFirstOne', 'stroke_text': 'free', 'classification_text': '9', 'time_text': '1:01.60'}之前:{'name_text':'TheFirstOne','stroke_text':'free','classification_text':'9','time_text':'1:01.60'}

AFTER: {'name_text': 'TheFirstOne', 'stroke_text': 'free', 'classification_text': '9', 'time_text': '1:01.60'}之后:{'name_text':'TheFirstOne','stroke_text':'free','classification_text':'9','time_text':'1:01.60'}

BEFORE: {'name_text': 'TheSecondOne', 'stroke_text': 'free', 'classification_text': '9', 'time_text': '1:01.60'}之前:{'name_text':'TheSecondOne','stroke_text':'free','classification_text':'9','time_text':'1:01.60'}

AFTER: {'name_text': 'TheSecondOne', 'stroke_text': 'free', 'classification_text': '9', 'time_text': '1:01.60'}之后:{'name_text':'TheSecondOne','stroke_text':'free','classification_text':'9','time_text':'1:01.60'}

What am I missing here?我在这里想念什么? Thanks for the help!谢谢您的帮助!

I got an answer from the Kivy forums on discord.我从 discord 上的 Kivy 论坛得到了答案。 The key is to pass a index to the row widget so they can change the data for their row.关键是将索引传递给行小部件,以便他们可以更改行的数据。 I think this should work for any complex widget in a recycleview object.我认为这应该适用于 recycleview object 中的任何复杂小部件。 Hope this helps someone.希望这可以帮助某人。

from kivy.app import App
from kivy.properties import ObjectProperty, NumericProperty, ListProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
from kivy.lang.builder import Builder
KV = """
<RecycleItem>:
    on_text: if root.owner != None: self.owner.data[self.index]['text'] = self.text

RecycleView:
    data: app.data
    viewclass: 'RecycleItem'
    RecycleBoxLayout:
        spacing: 10
        default_size: None, dp(80)
        default_size_hint: 1, None
        orientation: 'vertical'
        size_hint_y: None
        height: self.minimum_height
"""

class RecycleItem(RecycleDataViewBehavior,TextInput):
    owner = ObjectProperty()
    index = NumericProperty(0)

    def refresh_view_attrs(self, rv, index, data):
        self.index = index
        print("INDEXXXXXX: ",self.index)
        return super(RecycleItem, self).refresh_view_attrs(rv, index, data)

class Test(App):
    data = ListProperty()

    def build(self):
        self.data = [{"text": "Label "+str(x), 'owner': self} for x in range(20)]
        return Builder.load_string(KV)

Test().run()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM