从RecycleView类外部更改数据时,RecycleView不会更新其表。作为总结,我正在尝试创建一个简单的股票投资组合经理。
我有一个自定义的RecycleView类,我将其称为RecycleViewPortfolio,该类继承自RecycleView。在我的.kv文件中,我有三个按钮连接到RecycleViewPortfolio类中的函数populate_1,populate_2和populate_3。每当我按下一个按钮并调用任何填充函数时,RecycleView的行为就会像预期的那样。
但是,每当我从RecycleViewPortfolio类外部更改RecycleView数据时,表都不会更新。例如,我设置了一个全局变量,该变量已导入到我的.py文件和.kv文件中。每当此全局变量中的数据更改时,我都希望能够更新表。
我尝试查看Kivy的文档,其中提到了应该解决此问题的不同功能。但是我想我对如何应用这些方法一无所知。
import StackOverflow.globalvariables as GlobalVariables
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty
class AddPopup(Popup):
"""Popup for adding asset"""
asset_name = ObjectProperty
asset_price = ObjectProperty
asset_amount = ObjectProperty
currency = ObjectProperty
asset_class = ObjectProperty
wrapped_button = ObjectProperty()
def __init__(self, *args, **kwargs):
super(AddPopup, self).__init__(*args, **kwargs)
def open(self, correct=True):
super(AddPopup, self).open(correct)
def save_asset(self):
# Make sure no input is empty
if self.asset_name.text.strip() and self.asset_price.text.strip()\
and self.asset_amount.text.strip() and self.currency.text.strip()\
and self.asset_class.text.strip():
GlobalVariables.rv_data_global = [{'text': self.asset_name.text.strip()},
{'text': self.asset_amount.text.strip()},
{'text': self.asset_price.text.strip()}]
self.dismiss()
class RecycleViewPortfolio(RecycleView):
def __init__(self, **kwargs):
super(RecycleViewPortfolio, self).__init__(**kwargs)
self.populate_2()
def populate_1(self):
root = App.get_running_app().root
root.add_popup.open(True)
self.data = GlobalVariables.rv_data_global
def populate_2(self):
self.data = [{'text': str(x)} for x in range(0, 6)]
def populate_3(self):
self.data = [{'text': str(x)} for x in range(6, 12)]
class PortfolioRoot(GridLayout):
"""root to all screens"""
add_popup = ObjectProperty(None)
list = ListProperty([])
def __init__(self, **kwargs):
super(PortfolioRoot, self).__init__(**kwargs)
self.add_popup = AddPopup()
def test_set_data(self):
GlobalVariables.rv_data_global = [{'text': str(x)} for x in range(12, 18)]
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, # View Behavior
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button): # Data Behavior
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(True)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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
class PortfolioApp(App):
"""App object"""
def __init__(self, **kwargs):
super(PortfolioApp, self).__init__(**kwargs)
def build(self):
return PortfolioRoot()
PortfolioApp().run()
.kv文件
#:kivy 1.10.0
#:import GlobalVariables StackOverflow.globalvariables
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (0, 0.517, 0.705, 1) if self.selected else (0, 0.517, 0.705, 1)
Rectangle:
pos: self.pos
size: self.size
background_color: [1, 0, 0, 1] if self.selected else [1, 1, 1, 1] # dark red else dark grey
on_release:
print("Pressed")
<WrappedLabel@Label>:
size_hint_y: None
height: self.texture_size[1] + (self.texture_size[1]/2)
markup: True
<RecycleViewPortfolio@RecycleView>:
viewclass: 'SelectableButton'
target_id: None
# id: rv_data_list
data: GlobalVariables.rv_data_global
SelectableRecycleGridLayout:
cols: 3
key_selection: 'selectable'
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
<PortfolioRoot>:
BoxLayout:
list: rv_data_list
size: root.size
orientation: 'vertical'
WrappedLabel:
text: "[b] Portfolio Manager [/b]"
font_size: min(root.height, root.width) / 10
GridLayout:
size_hint_y: None
height: root.height * 0.1
cols: 4
rows: 1
# Settings
padding: root.width * 0.001, root.height * 0.001
spacing: min(root.width, root.height) * 0.001
Button:
text: "Add"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_1()
print("Add")
Button:
text: "Change"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_2()
print("Change")
Button:
text: "Remove"
background_color: [1, 1, 1, 1]
on_release:
rv_data_list.populate_3()
print("Remove")
Button:
text: "Test"
background_color: [1, 1, 1, 1]
on_release:
root.test_set_data()
print("Test set data")
RecycleViewPortfolio:
id: rv_data_list
<AddPopup>:
size_hint: 0.8, 0.8
title: "Add Asset"
title_size: root.height * 0.05
auto_dismiss: False
asset_name: asset_name
asset_price: asset_price
asset_amount: asset_amount
currency: currency
asset_class:asset_class
wrapped_button: wrapped_button
BoxLayout:
orientation: 'vertical'
GridLayout:
rows: 5
cols: 2
padding: root.width * 0.02, root.height * 0.02
spacing: min(root.width, root.height) * 0.02
Label:
id: asset_name_label
text: "Asset name"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_name
text: "Asset name"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_price_label
text: "Asset price"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_price
text: "asset"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_amount_label
text: "Asset amount"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_amount
text: "Asset amount"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: currency_label
text: "Asset currency"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: currency
text: "currency"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Label:
id: asset_class_label
text: "Asset class"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
TextInput:
id: asset_class
text: "Asset class"
halign: "center"
font_size: root.height/25
text_size: self.width, None
center_y: .5
Button:
id: wrapped_button
text: "Save"
size_hint: 1, None
height: root.height / 8
on_release: root.save_asset()
Button:
id: wrapped_button
text: "close"
size_hint: 1, None
height: root.height / 8
on_release: root.dismiss()
globalvariables.py
# global variables
rv_data_global = []
我希望能够创建一个弹出窗口,在其中添加存储在全局变量中的信息,并在进行更改后要求更新RecycleView。
编辑:添加了一个有效的示例
此示例显示了我如何能够使用按钮“更改”和“删除”来按预期填充RecycleView。但是,当按下添加按钮并出现弹出窗口并按下保存按钮时,RecycleView不会更新。如果再次按下添加按钮并直接关闭,则RecyleView会更新并显示正确的信息。
“测试”按钮也是如此,在此我调用一个更改全局变量的函数。从那里我不知道如何更新视图,因为Im不再在RecycleView类下工作。
TLDR; 更改数据后手动更新RecycleView的方法。
答案 0 :(得分:0)
我找到了我的一个问题的答案。通过添加:
mode = "Return"
对于test_set_data函数,我现在能够根据需要刷新数据。因此,魔术就是refresh_from_data()方法。
通过App.get_running_app(),我可以从弹出窗口类中访问refresh_from_data()命令。
@avr
我似乎已经在这里解决了自己的问题。但是,如果有人有更好或更干净的解决方案,请告诉我。