Kivy, kein Attribut 'Auswahl' für eine Listenansicht
-
20-12-2019 - |
Frage
Ich versuche Kivy zu lernen :wie man listview und seine Elementbindung manipuliert.Hier ist ein Teil meines Codes, in dem ich ein Problem habe.
Bearbeiten:Ich habe den Code geändert oder vielmehr alles hinzugefügt, anstatt nur einen Teil zu posten.
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()
Für die .kv-Datei, die ich verwendet habe :
<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
Wenn ich auf ein Element aus der Liste klicke, passiert nichts.
Ich weiß auch nicht, ob ich es benutzen soll :
self.apps_list.adapter.bind(on_selected_item=self.callback)
oder
self.apps_list.adapter.bind(on_selection_change=self.callback)
Tatsächlich zeigt weder das erste noch das zweite ein Wort auf der Konsole an.Irgendwelche Vorschläge ?
Lösung
Es gibt mehrere Dinge, die Sie falsch machen, aber Ihr Hauptfehler ist die Nummer 2 der folgenden Liste:
Sie können verwenden
on_selection change
.Soweit ich weiß, gibt es keineon_selected_item
.Sie binden das Ereignis, bevor Sie das Objekt erstellen.Die folgende Anweisung befindet sich in der initiieren:
self.apps_list.adapter.bind(on_selected_item=self.callback)
aber es sollte nach dem Erstellen des neuen im on_enter sein
ListAdapter
.Es könnte die letzte Zeile der Methode sein.Siehe die Codes unten.def on_enter(self): ... self.apps_list.adapter = list_adapter self.apps_list.adapter.bind(on_selection_change=self.callback)
MainLayout
enthält keinen Adapter.In der Methodeon_enter
, Referenzself.adapter
sollte geändert werden inadapter
(parameter der Methode) oderself.apps_list.adapter
.Die Art und Weise, wie Sie die Verweise auf erstellen
domain
,apps_list
undlogo100
ist seltsam.Ich wusste nichts von der Existenz desids
attribut imWidget
aber Sie können es direkt verwenden.Also, statt:self.apps_list.adapter = list_adapter
Sie können verwenden:
self.ids.apps_list.adapter = list_adapter
Es besteht keine Notwendigkeit der Überlastung der _initiieren_ methode überhaupt.
Wenn Sie nicht auf die zugreifen möchten apps_lists
durch die ids
attribut, dann können Sie Attribute in die Kopfzeile der Kivy-Sprache einfügen:
<MainLayout>:
text_input: text_input
apps_list: apps_list
logo100: logo100
rows: 2
Hier ist der endgültige funktionierende Python-Code, der alle genannten Änderungen enthält.Ich habe die Importe weggelassen.
# ... 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()
Andere Tipps
Ihr Codebeispiel ist durcheinander und sehr unvollständig?Könnten Sie eine einfache funktionierende App geben, die Ihr Problem zeigt?
Ich kann ein paar Vorschläge machen, um Dinge zu beheben, von denen einer das Verhalten verursachen würde, das Sie sehen:
1) Du tust es self.apps_list = ObjectProperty()
in der __init__
Methode.Das ist falsch, es erstellt keine ObjectProperty mit irgendeinem nützlichen Verhalten, sondern erstellt nur ein neues Attribut des Instanz ihrer Klasse, die Sie sogar in der nächsten Zeile ersetzen!Stattdessen sollten Sie Eigenschaften auf Klassenebene erstellen (z.die gleiche Ebene wie Funktionsmethoden).
2) Sie fügen Code ein, der an einen Adapter gebunden ist on_selection_change
ereignis, aber auch code in on_enter
das ersetzt den Adapter.Ihr Beispiel ist zu unvollständig, um zu wissen, wie oder wann letzteres aufgerufen wird, aber wenn es passiert, bevor Sie auf ein Listenelement klicken, kann Ihr Ereignis niemals ausgelöst werden, da der Adapter, an den es gebunden ist, ersetzt wurde.Dies würde das Verhalten ergeben, das Sie sehen.Um das Problem zu beheben, ersetzen Sie den Adapter nicht und binden Sie den Rückruf nicht erneut an den neuen.