Topic: ListCtrl Sort Items  (Letto 1586 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
ListCtrl Sort Items
« il: Marzo 04, 2017, 18:24 »
Eccomi qua con l'ennesimo problema.
Come riesco ad avere una ListCtrl che quando "l'utente" clicca su una colonna l'intera lista viene ordinata, in ordine crescente o decrescente, in base al capo(colonna) selezionato.
Ho trovato vari esempi e ho provato a modificarli in base a come volevo io ma non mi è andata bene:

import wx
import wx.lib.mixins.listctrl as listmix
 
nominativo = {
0 : ("Rossi", "Mario", "123"),
1 : ("Verdi", "Luca", "124"),
2 : ("Bianchi", "Marco", "122"),
3 : ("Blu", "Mauro", "125"),
4 : ("Gialli", "Roberto", "147"),
5 : ("Rossi", "Luca", "129")}
 

class MyPanel(wx.Panel, listmix.ColumnSorterMixin):
 
   
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
 
        self.list_ctrl = wx.ListCtrl(self, -1, size=(-1,100), style=wx.LC_REPORT|wx.BORDER_SUNKEN|wx.LC_SORT_ASCENDING)
        self.list_ctrl.InsertColumn(0, "Cognome")
        self.list_ctrl.InsertColumn(1, "Nome")
        self.list_ctrl.InsertColumn(2, "Telefono", wx.LIST_FORMAT_RIGHT)
 
        elementi = nominativo.items()
        print(elementi)
        index = 0
        for key, x in elementi:
            self.list_ctrl.InsertItem(index, x[0])
            print(x[0])
            self.list_ctrl.SetItem(index, 1, x[1])
            self.list_ctrl.SetItem(index, 2, x[2])
            self.list_ctrl.SetItemData(index, key)
            print(key)
            index += 1
         
        self.itemDataMap = nominativo
        listmix.ColumnSorterMixin.__init__(self, 3)
        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer)
 
   
    def GetListCtrl(self):
        return self.list_ctrl
 
   
    def OnColClick(self, event):
        print ("click colonna")
        event.Skip()
 
########################################################################
class MyFrame(wx.Frame):
 
   
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Prova List")
 
       
        panel = MyPanel(self)
 


if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    frame.Show()
    app.MainLoop()


Esiste un'altro metodo senza utilizzare import wx.lib.mixins.listctrl as listmix?

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.146
  • Punti reputazione: 9
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #1 il: Marzo 04, 2017, 20:49 »
 > Ho trovato vari esempi e ho provato a modificarli

Ok, ma devi modificarli in modo che abbiano ancora un senso logico però.
ColumnSorterMixin è un mixin che, come è naturale, va "mixato" in un ListCtrl. E' fatto per essere usato con un ListCtrl e solo con un ListCtrl.
Se tu lo "mixi" a un Panel, che cosa speri di ottenere?

Visto che hai già trovato gli esempi, allora segui gli esempi. che hai trovato Sottoclassa ListCtrl mixandoci dentro il mixin, e poi inserisci il tuo ListCtrl sottoclassato nel Panel, come avrai sicuramente visto fare negli esempi.

>Esiste un'altro metodo senza utilizzare import wx.lib.mixins.listctrl as listmix?
E come no. Puoi riscriverti un intero gui framework da zero, se vuoi. Tutto è possibile. Io però prima proverei a fare come è previsto da wxPython.

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #2 il: Marzo 04, 2017, 20:57 »
E non è possibile avere lo stesso risultato senza sottoclassare ListCtrl?

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #3 il: Marzo 04, 2017, 21:41 »
L'esempio che ho trovato è questo:

import wx
import wx.lib.mixins.listctrl as listmix
 
musicdata = {
0 : ("Bad English", "The Price Of Love", "Rock"),
1 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"),
2 : ("George Michael", "Praying For Time", "Rock"),
3 : ("Gloria Estefan", "Here We Are", "Rock"),
4 : ("Linda Ronstadt", "Don't Know Much", "Rock"),
5 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"),
6 : ("Paul Young", "Oh Girl", "Rock"),
}
 
########################################################################
class TestListCtrl(wx.ListCtrl):
 
    #----------------------------------------------------------------------
    def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
 
########################################################################
class TestListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
 
        self.list_ctrl = TestListCtrl(self, size=(-1,100),
                         style=wx.LC_REPORT
                         |wx.BORDER_SUNKEN
                         |wx.LC_SORT_ASCENDING
                         )
        self.list_ctrl.InsertColumn(0, "Artist")
        self.list_ctrl.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
        self.list_ctrl.InsertColumn(2, "Genre")
 
        items = musicdata.items()
        index = 0
        for key, data in items:
            self.list_ctrl.InsertStringItem(index, data[0])
            self.list_ctrl.SetStringItem(index, 1, data[1])
            self.list_ctrl.SetStringItem(index, 2, data[2])
            self.list_ctrl.SetItemData(index, key)
            index += 1
 
        # Now that the list exists we can init the other base class,
        # see wx/lib/mixins/listctrl.py
        self.itemDataMap = musicdata
        listmix.ColumnSorterMixin.__init__(self, 3)
        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer)
 
    #----------------------------------------------------------------------
    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
    def GetListCtrl(self):
        return self.list_ctrl
 
    #----------------------------------------------------------------------
    def OnColClick(self, event):
        print "column clicked"
        event.Skip()
 
########################################################################
class MyForm(wx.Frame):
 
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
 
        # Add a panel so it looks the correct on all platforms
        panel = TestListCtrlPanel(self)
 
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()


Però non ho capito alcune cose(direte voi strano!):
self.itemDataMap = musicdata
listmix.ColumnSorterMixin.__init__(self, 3)

self.itemDataMap diventa uguale a musicdata, ma non viene mai usata.
listmix.ColumnSorterMixin.__init__(self, 3) come si collega alla mia ListCtrl? attraverso wx.lib.mixins.listctrl?

E def GetListCtrl(self) quando viene chiamata?

Grazie!

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #4 il: Marzo 05, 2017, 14:10 »
Ma la lista che gli viene data deve essere in ordine crescente?
Se modifico :

nominativo = {
0 : ("Rossi", "Mario", "123"),
1 : ("Verdi", "Luca", "124"),
2 : ("Bianchi", "Marco", "122"),
3 : ("Blu", "Mauro", "125"),
4 : ("Gialli", "Roberto", "147"),
5 : ("Rossi", "Luca", "129")}


con:

nominativo = {
0 : ("ARossi", "Mario", "123"),
1 : ("BVerdi", "Luca", "124"),
2 : ("CBianchi", "Marco", "122"),
3 : ("DBlu", "Mauro", "125"),
4 : ("EGialli", "Roberto", "147"),
5 : ("FRossi", "Luca", "129")}


La mia lista si visualizza regolarmente.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.146
  • Punti reputazione: 9
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #5 il: Marzo 05, 2017, 16:38 »
Guarda, non so proprio rispondere. Dovrei scrivere un manuale che parte da zero (tipo non so, le funzioni in Python) e arriva fino a dove vuoi tu. E probabilmente tanto non lo leggeresti e continueresti comunque a fare le cose alla cieca.

Leggiti la documentazione di ColumnSortedMixin nella demo (o qui https://wxpython.org/Phoenix/docs/html/wx.lib.mixins.listctrl.ColumnSorterMixin.html#wx.lib.mixins.listctrl.ColumnSorterMixin) per avere risposta ad alcune delle tue domande. Altre domande non hanno senso, tipo:
> Ma la lista che gli viene data deve essere in ordine crescente?
Eh???? Ovviamente no. Lo scopo del mixin è proprio quello di ordinare dinamicamente. Boh.

Purtroppo in tutto questo ti sei ficcato in un pasticcio di parecchi ordini di grandezza superiore alle tue attuali conoscenze, e non c'è niente da fare. Gli esempi della demo sono francamente scritti male: nel senso, non sono dei tutorial, sono delle demo (appunto) rivolte a programmatori abbastanza esperti da farsi largo tra le varie scorciatoie e capire come usare le varie feature in modo sensato. Per esempio non avevo mai fatto caso che effettivamente nella demo il mixin viene mixato in un Panel... è ovviamente una cosa molto maldestra, che funziona in modo un po' precario, ma nella demo è fatta a scopo dimostrativo (e anche perché nello stesso codice si usa anche l'AutoWidthMixin che invece è correttamente mixato a un ListCtrl... quindi suppongo che l'abbiano fatto per variare un po'... non una grande idea comunque). Chiaro che si suppone che uno sia in grado di capire autonomamente e fare poi la cosa più adatta nel suo codice, ma se uno si limita a copiare e spostare pezzi qua e là senza sapere che cosa sono quei pezzi... non si va molto lontano. 

Ora, giusto per riassumere ti faccio vedere lo stesso esempio della demo, ma reso minimale e più corretto. Poi però devi cercare di capire da solo che cosa fanno effettivamente tutte le righe di codice. Una per una. Leggendo la documentazione di ciascun metodo.
Il mio consiglio però è di imparare prima per bene a usare un ListCtrl SENZA il mixin.


MUSICDATA = { etc etc come sopra }

class MyListCtrl(wx.ListCtrl, listmix.ColumnSorterMixin):
    def __init__(self, *a, **k):
        # va comunque chiamato almeno con style=wx.LC_REPORT naturalmente
        wx.ListCtrl.__init__(self, *a, **k)
        self.InsertColumn(0, "Artist")
        self.InsertColumn(1, "Title")
        self.InsertColumn(2, "Genre")
        for id_, (artist, title, genre) in MUSICDATA.items():
            # in Phoenix, usare InsertItem e SetItem, invece
            index = self.InsertStringItem(id_, artist)
            self.SetStringItem(index, 1, title)
            self.SetStringItem(index, 2, genre)
            self.SetItemData(index, id_) # richiesto dal mixin
        self.itemDataMap = MUSICDATA # richiesto dal mixin

        # solo DOPO che la lista e' popolata, inizializzo anche il mixin
        listmix.ColumnSorterMixin.__init__(self, 3)  # 3: numero colonne

    def GetListCtrl(self): return self # richiesto dal mixin


class Test(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k)
        lc = MyListCtrl(self, style=wx.LC_REPORT)

app = wx.App()
Test(None).Show()
app.MainLoop()

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #6 il: Marzo 06, 2017, 12:46 »
Grazie per la risposta! :ok:

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #7 il: Marzo 10, 2017, 09:37 »
Una volta che la lista viene ordinata per una determinata colonna, si generano nuovi indici?
Il mio problema è ottenere i valori della riga selezionata.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.146
  • Punti reputazione: 9
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #8 il: Marzo 10, 2017, 11:17 »
"indici" è un termine generico.

Riprendendo l'ultimo esempio che ho fatto:
- la variabile "index" (riga 12) si riferisce alla posizione della riga nella lista (riga 0, riga 1, riga 2). Ovviamente quando ordini, si "generano nuovi indici", per dirla con le tue parole
- la variabile "id_" (riga 15) si riferisce all'id univoco della riga fornito dal model sottostante, e che il mixin conosce grazie a "SetItemData" (riga 15) e "itemDataMap" (riga 16... avrai notato le note "richiesto dal mixin" che ho aggiunto a quelle righe... ecco, adesso hai capito perché il mixin "richiede" queste cose). Ovviamente questi id univoci non cambiano quando ordini. Ordinare riguarda la view, non il model sottostante.

In generale, se incomincia a lavorare con liste etc etc dovresti cominciare ad abituarti che c'è una differenza tra "view" (come i dati vengono visualizzati) e "model" (quello che i dati sono davvero). E' come nell'altro post di oggi... se non hai almeno una vaga idea di MCV non vai molto più lontanp di così.

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #9 il: Marzo 10, 2017, 12:15 »
Per costruire una Sortable ListCtrl ho usato il tuo metodo. Ora ho provato ad aggiungere la funzione di associazione dei dati di una riga della lista.
Tutto va bene finché non riordino la lista. Riordinandola la mia lista cambia, ma alla riga con index 0 corrisponde il valore iniziale, quello inserito con index 0.
Come faccio a prelevare i dati della riga selezionata?

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #10 il: Marzo 10, 2017, 12:36 »
Con GetItemText ho visto che grosso modo potrei riuscire ad avere ciò che mi interessa, ma non so se il metodo sia giusto o c'è un metodo migliore

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.146
  • Punti reputazione: 9
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #11 il: Marzo 10, 2017, 12:45 »
Per costruire una Sortable ListCtrl ho usato il tuo metodo. Ora ho provato ad aggiungere la funzione di associazione dei dati di una riga della lista.
Tutto va bene finché non riordino la lista. Riordinandola la mia lista cambia, ma alla riga con index 0 corrisponde il valore iniziale, quello inserito con index 0.
Come faccio a prelevare i dati della riga selezionata?
come già detto, se non hai una vaga idea di cos'è mcv non vai da nessuna parte. Il mixin mantiene un model dei dati separato dalla view, e poi agisce sulla view. La "riga" in cui finisce un dato appartiene alla view, non al model.

Offline momo79

  • python erectus
  • ***
  • Post: 100
  • Punti reputazione: 0
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #12 il: Marzo 10, 2017, 13:04 »
Ci sono pagine in italiano dove posso trovare qualcosa sulle MVC ? Altrimenti hai qualche sito da suggerirmi?

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.146
  • Punti reputazione: 9
    • Mostra profilo
Re:ListCtrl Sort Items
« Risposta #13 il: Marzo 10, 2017, 15:46 »
In italiano proprio non saprei.
Del resto, basta anche solo wikipedia e praticamente quello che riesci a googlare magari con "python mcv"... non è una ricetta che puoi copincollare nel tuo codice, è un paradigma di programmazione, un'idea astratta da capire e (bene o male) mettere in pratica.
Tra l'altro, mcv è notoriamente complicato da applicare ai gui framework come wxPython... Ci sono due pagine sul wiki di wxPython dedicate all'argomento: questa https://wiki.wxpython.org/ModelViewController (il cui codice non necessariamente mi convince) e questa https://wiki.wxpython.org/ModelViewPresenter (più complessa ma anche più interessante).
Ma al di là di tutto, l'importante è capire che esiste (o dovrebbe esistere) una differenza tra i dati-come-appaiono e i dati-come-sono. Il tuo mixin separa i due concetti, perché applica un principio di mcv. Impara dalla documentazione come gestire i due aspetti, come passare dal dato visualizzato al dato reale, etc.
Oppure, come ti suggerivo nell'altro thread, guardati i DataViewModel sulla demo ("guardati" nel senso di studiare come funzionano... la documentazione, il codice...). Sono un buon esempio di architettura mcv.