Kivy, sin atributo 'selección' para una vista de lista
-
20-12-2019 - |
Pregunta
Estoy intentando aprender kivy:cómo manipular la vista de lista y sus elementos enlazados.Aquí hay una parte de mi código donde tengo un problema.
Editar:Cambié el código, o más bien lo agregué todo, en lugar de simplemente publicar una parte.
import re
import sys
import json
import requests
import datetime
from datetime import datetime
from random import randint
import time
#Kivy Imports
import kivy
from kivy.app import App
from kivy.uix import label
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.properties import StringProperty, ObjectProperty
from kivy.adapters.listadapter import ListAdapter
from kivy.uix.listview import ListView, ListItemButton
from kivy.lang import Builder
from kivy.adapters import dictadapter
from kivy.uix.modalview import ModalView
#Kivy version
kivy.require('1.7.0')
#MainLayout Class with the GridView
class MainLayout(GridLayout):
def __init__(self, **kwargs):
super(MainLayout, self).__init__(**kwargs)
self.text_input = ObjectProperty() #reference to the textinput from .kv
self.apps_list = ObjectProperty()
self.logo100 = ObjectProperty()
self.domain = self.ids.text_input.text
self.apps_list = self.ids.apps_list
self.logo100 = self.ids.logo100
self.apps_list.adapter.bind(on_selected_item=self.callback)
def on_enter(self):
apps = {'a', 'b', 'c', 'd', 'e' ,'f', 'g'}
if apps != None :
list_adapter = ListAdapter(data = apps,
selection_mode = 'single',
allow_empty_selection = True,
cls = ListItemButton,
sorted_keys=[])
self.apps_list.adapter = list_adapter
def callback(self, adapter):
if len(self.adapter.selection) == 0:
print "No selected item"
else:
print self.adapter.selection[0].text
class WabApp(App):
def build(self):
return MainLayout()
if __name__ == '__main__':
WabApp().run()
Para el archivo .kv que utilicé:
<MainLayout>:
rows: 2
orientation: 'horizontal'
GridLayout:
cols: 2
orientation: 'vertical'
row_force_default: True
row_default_height: 50
Image:
id: logo100
source: 'logo100.png'
size_hint: [.2, .1]
texture: self.texture
size: self.texture_size
TextInput:
id: text_input
markup: True
text: ''
font_size: 32
size_hint: [1.8, .1]
multiline: False
on_text_validate: root.on_enter()
hint_text: 'test'
ListView:
id: apps_list
allow_empty_selection: True
Cuando hago clic en un elemento de la lista, no sucede nada.
Tampoco sé si debería usar:
self.apps_list.adapter.bind(on_selected_item=self.callback)
o
self.apps_list.adapter.bind(on_selection_change=self.callback)
En realidad, ni el primero ni el segundo muestran una palabra en la consola.Alguna sugerencia ?
Solución
Hay varias cosas que estás haciendo mal, pero tu principal error es el número 2 de la siguiente lista:
Puedes usar
on_selection change
.Hasta donde yo sé no hayon_selected_item
.Estás vinculando el evento antes de crear el objeto..La siguiente instrucción está en el en eso:
self.apps_list.adapter.bind(on_selected_item=self.callback)
pero debería estar en on_enter después de crear el nuevo
ListAdapter
.Podría ser la última línea del método.Vea los códigos a continuación.def on_enter(self): ... self.apps_list.adapter = list_adapter self.apps_list.adapter.bind(on_selection_change=self.callback)
MainLayout
No contiene ningún adaptador.en el metodoon_enter
, Las referenciasself.adapter
debe cambiarse aadapter
(el parámetro del método) oself.apps_list.adapter
.La forma en que estás creando las referencias a
domain
,apps_list
ylogo100
es extraño.No sabía de la existencia delids
atributo en elWidget
pero puedes usarlo directamente.Entonces, en lugar de:self.apps_list.adapter = list_adapter
Puedes usar:
self.ids.apps_list.adapter = list_adapter
No es necesario sobrecargar el _en eso_ método en absoluto.
Si no deseas acceder a apps_lists
a través de ids
atributo, luego puede agregar atributos en el encabezado del idioma kivy:
<MainLayout>:
text_input: text_input
apps_list: apps_list
logo100: logo100
rows: 2
Aquí está el código Python final que incluye todos los cambios mencionados.Omití las importaciones.
# ... your imports
class MainLayout(GridLayout):
def on_enter(self):
apps = {'a', 'b', 'c', 'd', 'e' ,'f', 'g'}
if apps != None :
list_adapter = ListAdapter(data = apps, selection_mode = 'single',
allow_empty_selection = True, cls = ListItemButton, sorted_keys=[])
self.apps_list.adapter = list_adapter
self.apps_list.adapter.bind(on_selection_change=self.callback)
def callback(self, adapter):
if len(adapter.selection) == 0:
print "No selected item"
else:
print adapter.selection[0].text
class WabApp(App):
def build(self):
return MainLayout()
if __name__ == '__main__':
WabApp().run()
Otros consejos
¿Su ejemplo de código está desordenado y muy incompleto?¿Podrías proporcionarnos una aplicación funcional sencilla que muestre tu problema?
Puedo dar un par de sugerencias para solucionar las cosas, una de las cuales causaría el comportamiento que ve:
1) lo haces self.apps_list = ObjectProperty()
en el __init__
método.Esto está mal, no crea una propiedad de objeto con ningún comportamiento útil, simplemente crea un nuevo atributo de instancia de tu clase, ¡que incluso reemplazas en la siguiente línea!En su lugar, deberías crear propiedades a nivel de clase (es decir,el mismo nivel que los métodos de función).
2) Incluye código que se vincula a un adaptador on_selection_change
evento, sino también código en on_enter
que reemplaza el adaptador.Su ejemplo es demasiado incompleto para saber cómo o cuándo se llama a este último, pero si sucede antes de hacer clic en un elemento de la lista, su evento nunca podrá activarse porque el adaptador al que está vinculado ha sido reemplazado.Esto daría el comportamiento que ves.Para solucionarlo, no reemplace el adaptador ni vuelva a vincular la devolución de llamada al nuevo.