virtuelle wx.ListCtrl nach Spalten sortieren ?

Plattformunabhängige GUIs mit wxWidgets.
Antworten
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hallo zusammen ...

Ich wollte mich mal etwas näher mit virtuellen ListCtrl auseinenader zu setzten und hätte da ein kleines Problem ...

Die virtuelle ListCtrl sieht so aus:

Code: Alles auswählen

class VirtualListCtrl(wx.ListCtrl):

    def __init__(self, parent, data_source):
        wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL|wx.LC_VRULES)

        self.data = data_source

        self.update_len()

        for col, text in enumerate(self.data.get_column_headers()):
            self.InsertColumn(col, text)

        self.alt = wx.ListItemAttr()
        self.alt.SetBackgroundColour("light gray")

    def OnGetItemText(self, item, col):
        data = self.data.get_item(item+1)
        value = data[col]
        if value is None:
            value = u""
        return value

    def OnGetItemAttr(self, item):
        return self.alt if item % 2 else None

    def update_len(self):
        self.SetItemCount(self.data.get_count())
Hier die dazu gehörige Datenquelle:

Code: Alles auswählen

class DataSource(object):
    COLUMNS = ["Index", "Song", "Band", "Album", "Url", "Comment"]

    def __init__(self, dbname):
        conn = sqlite.connect(dbname)
        self.cursor = conn.cursor()

    def get_column_headers(self):
        return DataSource.COLUMNS

    def get_count(self):
        self.cursor.execute("select count(*) from info")
        return self.cursor.fetchone()[0]

    def get_item(self, index):
        self.cursor.execute("select * from info where id=?", (index,))
        data = list(self.cursor.fetchone())
        if not data:
            data = [None, u"", u"", u"", u"", u""]
        return data

    def insert(self, data):
        self.cursor.execute("insert into info values (?, ?, ?, ?, ?, ?)", data)
        self.cursor.connection.commit()

    def update(self, data):
        data = data[1:] + [data[0]]
        self.cursor.execute("update info set song=?, band=?, album=?, url=?, comment=? where id=?", data)
        self.cursor.connection.commit()

    def delete(self, index):
        self.cursor.execute("delete from info where id=?", (index,))
        self.cursor.connection.commit()
Läuft ja schon so ... aber:

Wie kann ich nach einzelnen Spalten sortieren (zB nach Album) ?
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

midan23 hat geschrieben:Ich wollte mich mal etwas näher mit virtuellen ListCtrl auseinenader zu setzten und hätte da ein kleines Problem ...
Wie kann ich nach einzelnen Spalten sortieren (zB nach Album)?
Hallo midan23!

Das ist eine klifflige Frage. Du könntest dir eine Liste im Speicher halten, die für jeden Listeneintrag die zugehörige ID bereit hält.

Die Methode *get_item* liest zuerst den Listeneintrag aus und holt sich dann aus der Datenbank den Eintrag mit der gewünschten ID ``sorted_list[index]`` raus.

Beim Sortieren musst du also die *sorted_list* aktualisieren. Wenn ein neuer Eintrag hinzu kommt, dann musst du *sorted_list* aktualisieren. Wenn ein Eintrag gelöscht wird, dann musst du *sorted_list* aktualisieren. Wenn ein *IndexError* geworfen wird, dann musst du die *sorted_list* aktualisieren...

Die Methode *get_count* liefert ``len(sorted_list)`` zurück.

Das Aktualiseren der Liste *sorted_list* ist eine einfache SQL-Abfrage mit der ID des Datensatzes und ``ORDER BY xxx``.

mfg
Gerold
:-)

PS: ``select *`` sollte man vermeiden, wenn man die Spaltenüberschriften kennt. So hat der SQL-Server weniger zu tun und man bekommt weniger Daten zurück geliefert. Denn irgendwann kommt immer ein Feld dazu. Außerdem stimmt die Reihenfolge der Felder immer, wenn man diese explizit angibt. Es ist also weniger fehleranfällig.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Also kein direkter Zugriff, wie ich es jetzt mache, sondern ein indirekter Zugriff ...

Die select * from-Abfrage könnte ich ja dann auch abändern ... ich würde eh eine Liste mit allen Spalten brauchen ...

[nachdenk-modus=an]
  • Benutzer klickt auf Spalte im ListCtrl => erzeugt Ereignis
  • In Ereignis-Methode die GetColumn-Methode aufrufen => bekomme Spalten-Nummer
  • Spalten-Nummer als Index auf Spalten-Liste => bekomme Spalten-Name
  • Index-Liste mit neuem Spalten-Namen aktualisieren
  • Angezeigte Liste mit RefreshItems(von, bis) aktualisieren
[nachdenk-modus=aus]

Zumindest könnte ich es mir so ungefähr vorstellen ...

Aber der Tip mit dem Indirekten Zugriff war Gold wert ... Danke
Antworten