Как мне запретить просмотру recycle очищать текстовые записи?

#python-3.x #kivy #kivy-language

#python-3.x #kivy #kivy-language

Вопрос:

У меня есть просмотр recycle, который состоит только из текстовых полей. Когда вы вводите что-либо в текстовое поле, прокрутите вниз и прокрутите обратно вверх, текст исчезнет.

Я попытался обновить список данных в режиме рециркуляции, но при прокрутке он просто сбрасывает его снова. Я создал отдельную программу только с представлением recycle, чтобы попытаться провести эксперимент.

 from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import ObjectProperty, ListProperty
from kivy.clock import Clock

Builder.load_string('''
<Row>:
    canvas.before:
        Color:
            rgba: 0.5, 0.5, 0.5, 1
        Rectangle:
            size: self.size
            pos: self.pos
    itemText: ''

    TextInput:
        id:CellText
        text:root.itemText

<Row2>
    canvas.before:
        Color:
            rgba: 0.5, 0.5, 0.5, 1
        Rectangle:
            size: self.size
            pos: self.pos
    itemText: ''
    TextInput:
        id:CellText
        text:root.itemText
    TextInput:
        id:CellText
        text:root.itemText2

<RV>:
    id: rv
    viewclass: 'Row'
    pos: 10,-50
    scroll_type: ['bars', 'content']
    scroll_wheel_distance: dp(114)
    bar_width: dp(10)
    RecycleGridLayout:
        cols:6
        default_size: None, dp(30) 
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        spacing: dp(1)
''')


class RV(RecycleView):
    list_items = ListProperty([])
    numRows = 16
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'itemText': "1", 'paren': self, 'index':0},
                     {'itemText': "1", 'paren': self, 'index':0},
                     {'itemText': '0','paren': self, 'index':2},
                     {'itemText': "1", 'paren': self, 'index':0},
                     {'itemText': '0','paren': self, 'index':2},
                     {'itemText': '0','paren': self, 'index':2}]
        for x in range(2,32):
            self.data.extend([{'itemText': str(x), 'paren': self, 'index':6}])
            self.data.extend([{'itemText': "1", 'paren': self, 'index':6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'index': 6}])
            self.data.extend([{'itemText': "1", 'paren': self, 'index':6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'index': 6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'index': 6}])

    def which_edit(self, *args):
        '''This will print the index of the box which is currently edited'''
        #print args[0].parent.index


class Row(BoxLayout):
    paren = ObjectProperty() #the instance of the rv

    def __init__(self, **kwargs):
        super(Row, self).__init__(**kwargs)
        Clock.schedule_once(self.update)

    def update(self, *args):
        self.paren.list_items.append(self)
        self.ids.CellText.bind(text=self.paren.which_edit)


class TestApp(App):

    def build(self):
        return RV()

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

Ответ №1:

Проблема 1

Я попытался обновить список данных в режиме рециркуляции, но при прокрутке он просто сбрасывает его снова.

Основная причина

Все, что вводится в TextInput, не отражается в self.data . Из-за этого всякий раз, когда происходит прокрутка, TextInput обновляется из self.data .

Проблема 2

Перезаписано index например {'itemText': "1", 'paren': self, 'index':0},

Объяснение

index это зарезервированные атрибуты для RecycleView. Он используется для идентификации каждой ячейки в столбцах.

Решение

файл kv

Обновляйте self.data всякий раз, когда в TextInput вносятся какие-либо изменения.

Фрагменты

 TextInput:
    id:CellText
    text:root.itemText
    on_text:
        app.root.data[root.index]['itemText'] = self.text
  

Скрипт на Python

Заменить index на Index

Фрагменты

 def __init__(self, **kwargs):
    super(RV, self).__init__(**kwargs)
    self.data = [{'itemText': "1", 'paren': self, 'Index': 0},
                 {'itemText': "1", 'paren': self, 'Index': 0},
                 {'itemText': '0', 'paren': self, 'Index': 2},
                 {'itemText': "1", 'paren': self, 'Index': 0},
                 {'itemText': '0', 'paren': self, 'Index': 2},
                 {'itemText': '0', 'paren': self, 'Index': 2}]
    for x in range(2, 32):
        self.data.extend([{'itemText': str(x), 'paren': self, 'Index': 6}])
        self.data.extend([{'itemText': "1", 'paren': self, 'Index': 6}])
        self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])
        self.data.extend([{'itemText': "1", 'paren': self, 'Index': 6}])
        self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])
        self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])
  

Пример

main.py

 from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.properties import BooleanProperty

Builder.load_string('''
<Row>:
    canvas.before:
        Color:
            rgba: 0.5, 0.5, 0.5, 1
        Rectangle:
            size: self.size
            pos: self.pos
    itemText: ''

    TextInput:
        id:CellText
        text:root.itemText 
        on_text:
            #root.which_edit(args)
            app.root.data[root.index]['itemText'] = self.text

<RV>:
    id: rv
    viewclass: 'Row'
    pos: 10,-50

    scroll_type: ['bars', 'content']
    scroll_wheel_distance: dp(114)
    bar_width: dp(10)

    RecycleGridLayout:
        cols:6
        default_size: None, dp(30) 
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        spacing: dp(1)
''')


class Row(RecycleDataViewBehavior, BoxLayout):
    pass
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(Row, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(Row, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
        else:
            print("selection removed for {0}".format(rv.data[index]))

    def which_edit(self, *args):
        '''This will print the index of the box which is currently edited'''
        print(f'args={args}')


class RV(RecycleView):
    numRows = 16

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'itemText': "1", 'paren': self, 'Index': 0},
                     {'itemText': "1", 'paren': self, 'Index': 0},
                     {'itemText': '0', 'paren': self, 'Index': 2},
                     {'itemText': "1", 'paren': self, 'Index': 0},
                     {'itemText': '0', 'paren': self, 'Index': 2},
                     {'itemText': '0', 'paren': self, 'Index': 2}]
        for x in range(2, 32):
            self.data.extend([{'itemText': str(x), 'paren': self, 'Index': 6}])
            self.data.extend([{'itemText': "1", 'paren': self, 'Index': 6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])
            self.data.extend([{'itemText': "1", 'paren': self, 'Index': 6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])
            self.data.extend([{'itemText': "0", 'paren': self, 'Index': 6}])


class TestApp(App):

    def build(self):
        return RV()


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