python - KIVY:从不同的类调用时,回收视图不起作用
问题描述
我正在尝试使用recycleview,但我不明白为什么当我单击“填充列表”按钮时它可以正常工作:
from random import sample
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
kv = """
<Row@BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
text: root.value
<Test>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
"""
Builder.load_string(kv)
class Test(BoxLayout):
def populate(self):
self.rv.data = [{'value': ''.join(sample(ascii_lowercase, 6))}
for x in range(50)]
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['value'])
def clear(self):
self.rv.data = []
def insert(self, value):
self.rv.data.insert(0, {'value': value or 'default value'})
def update(self, value):
if self.rv.data:
self.rv.data[0]['value'] = value or 'default new value'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()
但是当我尝试从不同的班级做同样的事情时
像这样,它不起作用:
from random import sample
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
kv = """
<Row@BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
text: root.value
<Test>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
"""
Builder.load_string(kv)
class Caller(BoxLayout):
def do(self):
Test().rv.data = [{'value': ''.join(sample(ascii_lowercase, 6))}
for x in range(50)]
class Test(BoxLayout):
def populate(self):
Caller().do()
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['value'])
def clear(self):
self.rv.data = []
def insert(self, value):
self.rv.data.insert(0, {'value': value or 'default value'})
def update(self, value):
if self.rv.data:
self.rv.data[0]['value'] = value or 'default new value'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()
我在 github 和 kivy 文档以及堆栈溢出上搜索了大量帖子,但我找不到任何相关内容......
解决方案
您的代码的第二个版本存在几个问题:
- 您的
Caller
类不在您的 GUI 中的任何地方使用。 - 您的
populate()
方法创建 的新实例Caller
,但该实例不在您的 GUI 中。 - 的
do()
方法Caller
创建 的新实例Test
,但该实例不在您的 GUI 中。
要使其正常工作,只需使用与第一个版本相同的代码:
def populate(self):
# Caller().do()
self.rv.data = [{'value': ''.join(sample(ascii_lowercase, 6))}
for x in range(50)]
但是,如果您需要popuplate()
从不同的类执行此操作,您只需要访问Test
GUI 中的实例(而不是创建新实例):
class Caller(BoxLayout):
def do(self):
App.get_running_app().root.rv.data = [{'value': ''.join(sample(ascii_lowercase, 6))}
for x in range(50)]
推荐阅读
- javascript - 如何在不刷新网页的情况下刷新测验?
- ios - 如何在 ReplayKit 广播扩展中获取麦克风的状态
- javascript - Vue Cli 的 __non_webpack_require__ 的模拟
- python - 如何在干净的架构中建模 POST 主体
- c# - 如何在运行时在实体框架中添加新表?
- laravel - Laravel Eloquent:仅从模型中检索枢轴值
- javascript - Joi 基于更大的模式验证特定字段
- node.js - 在我的个人项目上安装 Node-Saas 错误
- python - 如何访问对象填充字典中的值?
- python - 重新定位当前使用 Tkinter 网格定位的棋盘游戏