I'm new to programming and is designing a framework for dictionary apps that you can search and select words in the left part of the window, and can read the info of the selected word in the right part of the window. I was trying to use a TextInput and a Recycle on the left and a ScrollView on the right to achieve these objects, it was going well until I began to work on the right part: the right part, which is the ScrollView part, is always blank somehow.
The whole script is here:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
kv_string = '''
<MainLayout>:
orientation: 'horizontal'
BoxLayout:
orientation: 'vertical'
size_hint_x: 0.35
TextInput:
hint_text: 'Search'
size_hint_y: 0.05
multiline: False
padding_y: 10
RV:
size_hint_y: 0.95
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
touch_multiselect: False
<SelectableLabel>:
color: (0, 0, 0, 1)
canvas.before:
Color:
rgba: (.5, .7, .6, .5) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
'''
my_dict = {'A': {'info': 'a'}, 'B': {'info': 'b'}, 'C': {'info': 'c'}, 'D': {'info': 'd'}, 'E': {'info': 'e'}}
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
self.index = index
self.data = data
self.text = data['letter']
return super(SelectableLabel, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
if super(SelectableLabel, 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):
self.selected = is_selected
if is_selected:
MyApp().display_info(self.data)
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
for letter, info in my_dict.items():
data_piece = {'letter': letter, 'info': info}
self.data.append(data_piece)
class MainLayout(BoxLayout):
pass
class MyApp(App):
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
self.info_layout = GridLayout(
size_hint = (1, None),
cols = 1,
height = 500
)
def build(self):
Builder.load_string(kv_string)
root = MainLayout()
info_sv = ScrollView(
size_hint_x = 0.65
)
info_sv.add_widget(self.info_layout)
root.add_widget(info_sv)
return root
def display_info(self, data):
self.info_layout.clear_widgets()
label = Label(
text = data['info']['info'],
color = (0, 0, 1, 1)
)
self.info_layout.add_widget(label)
print(data)
if __name__ == '__main__':
MyApp().run()
As you see I added a 'print(data)' in the displayinfo() method to test if it can receive data and turned out to work perfectly fine. And I tried to add a button in the info_layout and it's also not showing. So I suppose the problem is that info_layout didn't show up or not updated.
The problem is in your code for apply_selection()
. In that code, you have a line:
MyApp().display_info(self.data)
The MyApp()
portion of this creates a new instance of MyApp
, and calls the display_info()
method of that new instance. However, that new instance has nothing to do with what you see on your screen. You actually need to use the instance of MyApp
that is displayed on your screen. Try changing that method to:
def apply_selection(self, rv, index, is_selected):
self.selected = is_selected
if is_selected:
App.get_running_app().display_info(self.data)
# MyApp().display_info(self.data)