Topic: visualizzare dati intabellati  (Letto 510 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline Giuse

  • python unicellularis
  • *
  • Post: 7
  • Punti reputazione: 0
    • Mostra profilo
visualizzare dati intabellati
« il: Novembre 28, 2019, 15:18 »
Vorrei creare una tabella dove visualizzo dei dati provenienti da un db MySql.
Il collegamento e la lettura dei dati da db è andata a buonfine, ma adesso vorrei intabellarli e visualizzarli dentro una finestra di tkinter.

Quindi sull'asse x i nomi dei campi o le label, mentre sull'asse y campo per campo il contenuto di questo.
Premesso che ho cercato anche in inglese, ma non sono riuscito a trovare nessun articolo o esempio che parlasse di ciò.
Forse non è possibile farlo in tkinter?
Cortesemente mi date una direzione, un link o qualche spunto/consiglio dove potere studiare.

Grazie

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #1 il: Novembre 29, 2019, 13:00 »
Vorrei creare una tabella dove visualizzo dei dati provenienti da un db MySql.
Il collegamento e la lettura dei dati da db è andata a buonfine, ma adesso vorrei intabellarli e visualizzarli dentro una finestra di tkinter...

Ciao @Giuse

La rappresentazione "tabellare" dei dati è un "qualcosa" che ho cercato a mia volta in tkinter : mi sembra proprio che non ci sia.

In ogni caso, non è poi troppo difficile realizzarne una, più o meno complessa, sfruttando il gestore di geometria "grid", giusto per giocarci un po' ieri sera mi son divertito a realizzare un esempio minimale che Ti propongo come spunto

# -*- coding: utf-8 -*-

import tkinter as tk

class TableModel():
    '''
Modello base per contenimento dati, intestazioni e dimensionamento per
un oggetto "Table".
'''
   
    def __init__(self, geometry=None, headers=None, data=None):
        '''
"Costruttore" del modello di tabella.

Parametri :
    geometry - dizionario contenente le chiavi :
                minsizes : lista di interi, dimensioni minime delle colonne
                weights : lista di interi definente il proporzionamento al
                           resize, 0 = colonna fissa
    headers  - lista intestazioni delle colonne
    data     . lista di liste : valori nelle colonne

Note : mi piacerebbe aggiungere un "maxsize" alle colonne ma non mi sembra supportato

'''
        self.geometry = geometry
        self.headers = headers
        self.data = data

       
class Table(tk.Frame):
    '''
Elementare "Tabella" dati, crea una singola riga di etichette di intestazione
ed n righe di entry per i dati.
'''
    def __init__(self, master=None, model=None):
        '''
"Costruttore" della tabella

parametri :
    master : widget/finestra proprietaria
    model  : modello della tabella
'''
        super().__init__(master)
        # verifica il modello di tabella, se incoerente si auto-distrugge
        if not model.geometry or not model.headers:
            self.destroy()
            return
        self.model = model
        self.__populate()

    def __populate(self):
        ''' Popola la tabella con i dati memorizzati nel modello. '''
        # etichette
        self.labels = []
        h_bg = tk.Frame(self)
        h_bg.grid(row=0, column=0, sticky='ew', padx=0, pady=0)
        for i in range(len(self.model.headers)):
            lbl = tk.Label(h_bg)
            lbl.configure(text=self.model.headers[i], relief='raised')
            lbl.grid(row=0, column=i, sticky='ew')
            self.labels.append(lbl)
        # definizione sfondo delle celle dati
        cells_bg = tk.Frame(self)
        cells_bg.grid(row=1, column=0, sticky='nsew', padx=0, pady=0)
        # definizione delle celle dati
        self.cells = []
        for i in range(len(self.model.data)):
            row_cells = []
            for j in range(len(self.model.headers)):
                c = tk.Entry(cells_bg, relief='ridge', bg='white')
                c.grid(row=i, column=j, sticky='ew')
                c.insert(tk.END, self.model.data[i][j])
                c.bind('<FocusIn>', self.__cell_focus)
                row_cells.append(c)
            self.cells.append(row_cells)
        # scroolbar ... poi

        # proporzionamento colonne
        for i in range(len(self.model.geometry['minsizes'])):
            if self.model.geometry['minsizes'][i]:
                h_bg.grid_columnconfigure(i, minsize=self.model.geometry['minsizes'][i])
                cells_bg.grid_columnconfigure(i, minsize=self.model.geometry['minsizes'][i])
            if self.model.geometry['weights'][i]:
                h_bg.grid_columnconfigure(i, weight=self.model.geometry['weights'][i])
                cells_bg.grid_columnconfigure(i, weight=self.model.geometry['weights'][i])
        # definizione del "peso" di riga/colonna
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)
        # definizione riga corrente
        self.__curr_row = 0

    def __cell_focus(self, evt):
        row = evt.widget.grid_info()['row']
        if row != self.__curr_row:
            # "decolora" la vecchia riga selezionata
            for c in self.cells[self.__curr_row]:
                c.configure(bg='white')
            self.__curr_row = row
            # "colora" la nuova riga selezionata
            for c in self.cells[self.__curr_row]:
                c.configure(bg='#ffffc0')
           

# un primo test "al volo"
if __name__ == '__main__':
    # preparo le impostazioni per il "modello"
    g = {'minsizes' : [0, 0, 0],
         'weights'  : [1, 1, 1]
         }
    h = ['Cognome', 'Nome', 'data nascita']
    data = [['De Paperoni', 'Paperon', '1901-01-01'],
            ['Paperino', 'Paolino', '1950-11-01'],
            ['Paperone', 'Gastone', '1950-01-06'],
            ['Mouse', 'Miky', '1900-02-29'],
            ['Mouse', 'Minnie', '1910-01-01'],
            ['Mucca', 'Clarabella', '1923-12-13']
            ]
    model = TableModel(g, h, data)
    app = tk.Tk()
    f = tk.Frame(app)
    f.grid(row=0, column=0, sticky='nsew')
    t = Table(f, model)
    t.grid(row=0, column=0, sticky='nsew')
    b = tk.Button(f, text='Chiudi', command=app.destroy)
    b.grid(row=1, column=0, sticky='ew')
    f.grid_columnconfigure(0, weight=1)
    f.grid_rowconfigure(0, weight=1)
    app.grid_columnconfigure(0, weight=1)
    app.grid_rowconfigure(0, weight=1)
    app.mainloop()

Non è molto curato, ma testato poco fa sembra andare benino, per lo meno non da errori ed "evidenzia" la riga selezionata.

Ho ipotizzato un "modello di tabella" per una ipotesi di sviluppo futuro di caratteristiche del giocattolo. Rendere qualcosa di migliore motrebbe essere un interessante esercizio di studio per apprendisti tipo me e, suppongo, altri in circolazione eventualmente interessati.

Ciao :)

Offline Giuse

  • python unicellularis
  • *
  • Post: 7
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #2 il: Novembre 29, 2019, 13:45 »
Ti ringrazio per il codice, in effetti la mia richiesta è solo per studio, sono interessato a python e a quelle applicazioni che servono a registrare dati, editarli o cancellarli, quelli che ingergo vengono chiamati CRUD.
  • Create (creare i dati)
  • Read o Retrieve (leggere i dati)
  • Update (aggiornare i dati)
  • Delete o Destroy (eliminare i dati)
Per adesso sto procedendo per step, quindi mi sono concentrato sul collegamento ad un database che risiede on line e ci sono riuscito, quindi andando avanti volevo capire se potevo avere una view complessiva dei dati. L'intento è quello di scrivere un applicativo dove inserire i titoli della mia libreria, potendoli poi ricercare per autore genere editore etc.. ma per quest'ultima parte penso di essere ancora molto lontano.


Il mio database di riferimento è MySql che è quello che conosco meglio, mentre la scelta del db on line anzichè in un file sul proprio PC, magari con MySqlLite, era semplicemente per studio...ho visto tante guide su come lavorare con un file db in locale e quasi niente su come lavorare su un db in remoto.

Nei prossimi giorni o meglio nel fine settimana ci giocherò un pò e ti faccio sapere.

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #3 il: Novembre 29, 2019, 15:48 »
Ti ringrazio per il codice, in effetti la mia richiesta è solo per studio, sono interessato a python e a quelle applicazioni che servono a registrare dati, editarli o cancellarli, quelli che ingergo vengono chiamati CRUD. ...

Nei prossimi giorni o meglio nel fine settimana ci giocherò un pò e ti faccio sapere.

Capisco, personalmente preferisco operare in LAN locale e su PostgreSQL, ma anche a me piace adoperare la visualizzazione tabellare, prevalentemente per la consultazzione/selezione tra i records da manipolare.

In merito al mio precedente post, ho riscontrato che viene meglio non mischiare label ed entry, una resa migliore si ottiene con le entry anche per le intestazioni di colonna, ovviamente poste in sola lettura. Considera questa modifica nrò popolare le etichette, imho la resa visiva è migliore.


    def __populate(self):
        ''' Popola la tabella con i dati memorizzati nel modello. '''
        # etichette
        self.labels = []
        h_bg = tk.Frame(self)
        h_bg.grid(row=0, column=0, sticky='ew', padx=0, pady=0)
        for i in range(len(self.model.headers)):
            lbl = tk.Entry(h_bg, justify='center', bg='gray91')
            lbl.configure(relief='raised')
            lbl.insert(tk.END, self.model.headers[i])
            lbl.configure(state='readonly')
            lbl.grid(row=0, column=i, sticky='ew')
            self.labels.append(lbl)


Ciao

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.025
  • Punti reputazione: 9
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #4 il: Novembre 29, 2019, 16:07 »
Purtroppo non è così semplice.
Se stai facendo questo per motivi di studio, ciò che devi studiare è MCV, e non c'è davvero altra soluzione che capire e digerire MCV.

Ora, l'esempio che ti è stato fatto è abbastanza istruttivo, nel senso che è una pessima applicazione di MCV, e quindi si può imparare studiando i suoi problemi.
(E no, giusto per prevenire la solita obiezione: non è che "è solo uno schizzo", è proprio una questione delle fondamenta. Io posso fare "solo uno schizzo" del disegno di un corpo umano, ma se ci metto cinque braccia e sei occhi, non è "solo uno schizzo", è che che non sto seguendo l'anatomia umana).

Non c'è nessuna separazione tra "Model" e "View". In particolare nota che il "Model" contiene anche delle caratteristiche che logicamente appartengono alla "View"... ma curiosamente solo alcune di queste caratteristiche sono nel Model, altre restano di compentenza del codice della View... in base a quale criterio?
Ma una cosa più istruttiva da notare è che il Model si esprime "convenientemente" nello stesso linguaggio della View... se guardi alla riga 85-85, vedrai che la View si limita a ricevere i valori del Model tali e quali. Ma questo vuol dire che Model e View sono interdipendenti ("accoppiati", "coupled" come si dice in gergo OOP). In realtà il Model dovrebbe esprimersi in un modo più astratto, e lasciare alla View il compito di decidere come presentare concretamente le indicazioni che dà il Model. Per esempio, il Model potrebbe avere il compito di segnalare che uno dei campi è "il più importante" (è un po' discutibile... ma insomma poniamo). Potrebbe farlo con un flag, immaginiamo. Poi però la View avrebbe il diritto di decidere *come* presentare questa informazione. Una View potrebbe decidere di fare più larga la colonna corrispondente, un'altra View potrebbe colorare quella colonna di rosso, un'altra ancora potrebbe ignorare del tutto questa informazione. Nell'esempio che vedi, d'altra parte, il Model è concepito solo per "servire" quella particolare View, e nessun altra possibile. Metti, per esempio, che adesso ti viene in mente di cambiare la View: non vuoi più vedere i dati in formato tabulare, ma come "schede" con dei pulsanti di navigazione ("successiva", "precedente"... hai presente, no?). Che te ne fai, a questo punto delle informazioni del Model specifiche sulla geometria delle colonne? Ovviamente le scarteresti, ma capisci che a questo punto il Model contiene "un po' più informazioni" se decidi di usare un certo tipo di View, e "un po' meno informazioni" se decidi di usare un altro tipo di View. La verità è che il Model non dovrebbe contenere istruzioni specifiche per nessun tipo di View. Il Model dovrebbe solo essere una rappresentazione astratta della "situazione" (dei dati, ma non solo e non necessariamente).

Un'altra cosa affascinante da vedere, è come il Model "sorvola con eleganza" (!) il problema dei tipi dei dati, semplicemente falsificando i tipi dei dati in modo (di nuovo) da parlare lo stesso linguaggio della View. Quella specifica View ha bisogno di stringhe? Benissimo, allora già nel Model memorizziamo tutto quanto come stringhe, così poi passiamo stringhe "alla cieca" e va tutto bene. Ma vedi che lì per esempio c'è anche una data... non importa! tutto dev'essere una stringa.
Immagina di creare un altro campo di tipo "Si/No", per esempio "Online in questo momento" (o qualcosa del genere, va a sapere). Ora, avrebbe senso che nel Model questo fosse un tipo Bool, ma se vuoi puoi anche utilizzare qualcos'altro... diciamo che usi una stringa che può essere "Y" o "N" (questo è molto più fragile che usare un vero Bool, ma pazienza). Ora, in quella specifica View tu potresti anche cavartela... il Model ha una stringa, la View ti farà vedere una colonna con "Y" o "N". Ma un'altra View potrebbe decidere di farti vedere una casella con la spunta... Un'altra View potrebbe colorare di rosso o di verde la cella della tabella... E così via.
Se ti poni il problema in modo generale, capirai ben presto che occorre ancora una volta "disaccoppiare" il Model dalla View. Il Model deve avere i dati con il tipo "giusto" (Bool per i vero/falso, datetime.date per le date, quello che vuoi). La View deve rappresentare visivamente questi tipi nel modo che preferisce. In mezzo deve esserci un componente che "traduce" i tipi del Model, e li passa alla View nella forma che lei preferisce. Questo è uno dei compiti possibili per un Controller, nel gergo MCV.

E si potrebbe andare avanti... Ma torniamo alla tua idea. Le applicazioni CRUD sono l'abc di un certo tipo di "informatica pratica"... e sono anche il terreno di applicazione più concreto per studiare MCV. Non puoi fare un CRUD senza MCV, sarebbe una faticaccia tremenda.
Il problema che ti è subito chiaro nel momento in cui devi metterti a fare un CRUD, è che non ti basta semplicemente un meccanismo che "travasa" i dati di un Model dentro una View, come fa (non benissimo, come visto) l'esempio che ti è stato proposto. Quello che ti serve in un CRUD è un meccanismo per cui, quando modifichi un valore nella View, il Model si aggiorna di conseguenza. E viceversa: quando modifichi un valore in un Model, la View si aggiorna di conseguenza. View e Model devono "parlarsi". A questo soprattutto serve MCV: a mantenere separate le competenze tra le parti, in modo che la comunicazione possa avvenire secondo protocolli precisi e nessuno pesti i piedi a nessun altro.

La prima cosa che devi fare, è non lasciarti confondere le idee dagli oggetti concreti con cui lavori. Non importa quale database usi. Puoi anche non usare nessun database, se è per questo. Quello che conta è il principio. Quando hai capito quello, puoi aggiungere tutti i dettagli che vuoi.
La seconda cosa che devi capire, è che devi imparare a non strafare: parti dagli esempi più semplici, e vai avanti per gradi. Una tabella è già un esempio troppo complicato da programmare. Capisco che tu pensi a un database, a qualche esempio concreto, e ti viene l'acquolina in bocca e vorresti subito fare un bel gestionale di magazzino (mannaggia, ma come fanno in Delphi a fare tutte 'ste cose senza starci troppo a pensare? E... infatti... e poi si vede come li fanno certi programmi... Ma vabbè, lasciamo stare la polemica).

Invece ti propongo un esercizio più semplice. Hai due cose: un Model e una View.
Il Model è un semplice valore numerico. Davvero, tutto qui. Un numero e niente di più. Diciamo che è una variabile (chiamiamola "model"... che fantasia) che all'inizio vale "42". Quindi hai:
model = 42 # questo è il model!!!
Dall'altra parte ha la View. Questa è una finestra di testo con esattamente 3 elementi (non importa dove li metti... fa un po' come vuoi):
- una casella di testo
- un pulsante "salva"
- un pulsante "resetta model"

Nella casella di testo ci deve essere visualizzato il contenuto del Model (quindi, all'inizio, "42"... ricordati che è una casella di testo, quindi dovrà contenere una stringa, mentre il Model maneggia dei numeri... ma vabbè, vedi tu come fare).
Azione A: quando cambi il valore nella casella di testo e poi fai clic su "salva", il valore nel Model deve aggiornarsi di conseguenza.
Azione B: quando fai clic su "resetta model", il valore del Model torna a 42. Diciamo che questo simula qualunque intervento che potrebbe succedere sul Model, indipendente dalla tua View... qualcosa che accade. Quando questo succede, la casella di testo deve aggiornarsi di conseguenza.

Attenzione! Non sto dicendo che "Azione B" vuol dire "cambia il model a 42, e cambia il valore della casella di testo a 42". Così sarebbe banale. Invece dico che alla pressione del pulsante il Model deve cambiare, e quando cambia deve notificare alla View che il suo stato è cambiato.
Attenzione! Non sto dicendo che "Azione A" vuol dire "leggi il valore della casella di testo e sbattilo nel Model". Così sarebbe banale. Invece dico che alla pressione del pulsante la View deve notificare al Model che il suo stato è cambiato, e ovviamente il Model deve recepire questo messaggio.

Se provi a fare questo esercizio, ti accorgerai che in realtà è molto complicato...

(PS: in realtà questo esercizio andrebbe fatto prima come puro esercizio di OOP, senza nessuna GUI...)

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #5 il: Novembre 29, 2019, 16:33 »
Ciao @RicPol

Purtroppo non è così semplice. ...

Intervento molto interessante, sei da leggere :)

comunque,  riguardo
(E no, giusto per prevenire la solita obiezione: non è che "è solo uno schizzo", è proprio una questione delle fondamenta ...

Non avevo intenzione di toccare alcuna fondamenta (MCV? Quale arcano esotismo per me!), solo dare un esempio di "assemblaggio" buttato li. Per il resto, nessuna pretesa.

Spero continuamente in interventi di qualità come il Tuo in questo post, a me danno almeno idea su ciò che ignoro, se il discorso continuerà a svilupparsi leggerò con interesse.

Ciao :)

Offline Giuse

  • python unicellularis
  • *
  • Post: 7
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #6 il: Novembre 29, 2019, 16:43 »
@nuzzopippo grazie ancora

@ricpol Capisco e ti ringrazio, procedo per passi, se riesco il gestionale lo finirò sine die, per adesso volevo solo visualizzare i dati intabellati provenienti da un db. Si certo che ho l'acquolina in bocca, ma sono consapevole delle mie limitazioni, che forse con impegno e studio,passo dopo passo, arriverò a capire. Non ho fretta, questa cosa la faccio solo per soddisfazione personale, non ho scadenze e ne impegni. Di quello che hai scritto non ho capito nulla, perdona la franchezza, ma a 53 anni suonati potrebbe essere normale. MVC? certo so cosa è separazione dei dati modello-vista-controllo. Ne sento parlare da anni, mi occupo di grafica per il web, ma non saprei come procedere. Nel voler imparare python, scelto perchè non ho altre esperienze di programmazione, e a quanto si dice è un linguaggio molto più semplice di C C++ e C#.......Quindi sono all'ABC, e per usare il tuo stesso esempio, se per adesso disegno un omino un pò sbilenco mi perdonerai, farò meglio con l'esperienza.

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #7 il: Novembre 29, 2019, 18:22 »
Riletto, e cercato di meditare, sul post di @RicPol ... mi rendo conto di aver fatto un "qualcosa" di quelle che fanno andare il latte alle ginocchia agli esperti, me ne dolgo

Ma una cosa più istruttiva da notare è che il Model si esprime "convenientemente" nello stesso linguaggio della View... se guardi alla riga 85-85, vedrai che la View si limita a ricevere i valori del Model tali e quali. Ma questo vuol dire che Model e View sono interdipendenti ("accoppiati", "coupled" come si dice in gergo OOP). In realtà il Model dovrebbe esprimersi in un modo più astratto, e lasciare alla View il compito ...

In effetti la classe TableModel da me definita è pensata proprio quale ambito di definizione di alcune caratteristiche della visualizzazione di cui deve tenere la "tabella", i dati, nel caso, sono solo un elemento di comodo esemplificativo. La immaginavo destinataria anche di ulteriori caratteristiche, tipo colrazione alternata delle righe, colori di background e foreground, fonts, etc.

Che la sua "denominazione" potesse individuarla quale elemento di un contesto MCV non mi aveva sfiorato neppure vagamente.

Ciò nulla toglie al valore delle critiche ed indicazioni espresse, mi riservo, ammesso riesca a comprendere l'argomento, di tentare una futura implementazione secondo il paradigma MCV.

Grazie delle osservazioni.

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #8 il: Dicembre 13, 2019, 13:53 »
...
Invece ti propongo un esercizio più semplice. Hai due cose: un Model e una View.
....
(PS: in realtà questo esercizio andrebbe fatto prima come puro esercizio di OOP, senza nessuna GUI...)

Dato che @Giuse non ha risposto, letto qualcosa sul "MCV", non sono "certo" di quanto compreso, mi sembra sin troppo "simile" a metodi che uso abitualmente per non ipotizzare un condizionamento, da parte delle "abitudini".
Ho provato a mettere giù un abbozzo dell'esercizio proposto :
# -*- coding: utf-8 -*-

class IntModel:
    ''' Un "Modello" per soli numeri interi'''
    default_value = 42
    def __init__(self):
        self.value = IntModel.default_value

    def remote_value_changed(self, new_value):
        if new_value.isdigit():
            self.value = int(new_value)
            return self.value
        else:
            return None

    def reset(self):
        self.value = IntModel.default_value
        return self.value

    def get_value(self):
        return self.value


if __name__ == '__main__':
    mod = IntModel()
    print('Inizializzato IntModel, valore :', mod.get_value())
    # inizializzo una variabile
    var = str(mod.get_value())
    while not var in 'Aa':
        var = input('Inserisci valore (R per reset, A per uscire) : ')
        # *** È UN "CONTROLLER" VALIDO ? ***
        # la view, ovviamente, sono i 'print'
        if var != mod.get_value():
            if var in 'Rr':
                mod.reset()
                print('Modello resettato, vale :', mod.get_value())
            else:
                outcome = mod.remote_value_changed(var)
                if outcome:
                    print('Nuovo valore acquisito, vale :', mod.get_value())
                else:
                    print('Nuovo valore rifiutato, vale :', mod.get_value())


Inutile dire che mi sarebbe gradito un parere circa quanto fatto risponda o meno al paradigma MCV

Ciao :)

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.025
  • Punti reputazione: 9
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #9 il: Dicembre 13, 2019, 21:51 »
uhm, no non va... cioè intendiamoci, si *potrebbe* fare qualcosa del genere anche con una cli, ma curiosamente il fatto che una cli sia necessariamente "serializzata" ti impedisce di cogliere il nocciolo del problema di cui si stava parlando... in pratica tu non fai altro che accettare input dalla cli, e avere risposte dal model... è un dialogo a senso unico. Se provi a farlo con una gui (anche tkinter... uff che noia tkinter però...) vedi meglio dove sta il problema.


A parte questo, nel tuo model alla riga 9sgg non va bene fare nello stesso pezzo di codice logica di business e validazione dei dati... Questo è un errore comune, ma il model deve accettare e trattare i dati "in purezza"... se hai bisogno di validazione, devi farla a parte. Come in tutti i casi di questo tipo, capisci meglio dove sta il problema se ti immagini la domanda: "che cosa succederebbe se volessi fare *anche* in un altro modo?".
In questo caso, tu adesso ha una interfaccia che fornisce numeri (si spera) sotto forma di stringhe: quindi pensi bene di validarle (per eliminare gli input fasulli), e se è davvero un numero lo casti a integer e procedi. Adesso però immagina che questo sia un software importante, che tu lo hai già mandato in produzione, e adesso il capo arriva e ti dice: guarda, stiamo aprendo un nuovo mercato... abbiamo un contratto miliardario con un gruppo di fanatici dell'antica Roma... quindi adesso ti chiedo di aggiungere una *seconda* cli alternativa, che invece accetta numeri romani.
Vedi bene che a questo punto dovresti riscrivere il tuo model per adattarlo alla nuova interfaccia. E invece questo non bisognerebbe mai farlo... se scrivi una nuova interfaccia con delle regole diverse, il model manco dovrebbe accorgersene... Quindi la validazione e l'adattamento dei dati da passare al model va fatto in un posto separato.

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #10 il: Dicembre 14, 2019, 11:24 »
Grazie della risposta.

Se ho compreso bene, allora, nel paradigma MCV il "Modello" dovrebbe limitarsi alla mera acquisizione "acritica" dei dati,essendo la congruenza degli stessi faccenda di cui si occupa un "controller" specializzato, sia esso processo od oggetto, che provvede a valutare e filtrare l'input per poi fornirli al modello o segnalare alla "view" eventuali incongruenze.

... Si, è un po' diverso dalle mie abitudini (oggetti dati intermedi che si occupano di tutti gli aspetti di gestione, verifica delle congruenze comprese), mi toccherà uno sforzo immaginativo per comprendere le relazioni tra i tre "oggetti", in particolare comprendere come far comunicare modello e view ad un evento "update" andato a buon fine, il "controller" intermedio mi causa difficoltà concettuali.

Certo, sprecarsi su di un "modello  tabella" per tkinter è un po' ingiustificato, ma, forse utile, ammesso mi riesca di fare qualcosa di decente, ad acquisire nuovi modelli di pensiero.

Grazie @RicPol

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #11 il: Dicembre 20, 2019, 08:29 »
Ho trovato, nella ricerca di "capire" l'argomento, un esempio di implementazione del pattern MVC un esempio in python, scritto da Giacomo Debidda che trovo interessante per comprenderne i rudimenti, lo segnalo, è diviso in tre parti :
  • la prima tratta i rudimenti e spiega una implementazione di base utilizzante solo dati in memoria
  • la seconda, utilizza i concetti esposti  per mostrarne la traslazione in uno schema CRUD basato su SQLite
  • la terza tratta l'utilizzo di ORM e dataset

Non che sia "qualcosa" di approfondito ma mi sembra ben fatto e fa comprendere i concetti, secondo me da vedere e rifletterci sopra.

P.S. - i link nelle pagine segnalate non funzionano tanto bene, possibile siano in fase di modifica/dismissione.

Ciao

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.025
  • Punti reputazione: 9
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #12 il: Dicembre 20, 2019, 10:10 »
>  il "Modello" dovrebbe limitarsi alla mera acquisizione "acritica" dei dati
Uhm, beh non proprio... il model dovrebbe preoccuparsi delle operazioni sui dati "in quanto tali" (sui dati che modella, ovvio... sui dati di sua competenza). Se hai un model "Conto in banca", puoi avere un metodo "preleva" che fa parte di quel model. Ma se quando "prelevi" il conto va in rosso, è ancora compito del model verificarlo ed eventualmente applicare una regola che impedisce l'operazione. Questo non fa parte di un "controller" (almeno, in genere). Se poi una GUI desidera visualizzare gli scoperti in rosso, questo è un compito della View.

> Certo, sprecarsi su di un "modello  tabella" per tkinter è un po' ingiustificato,
No no al contrario... in genere visualizzare i dati tabellari in una GUI è un esercizio classico di MCV... e paradossalmente fare una cosa del genere in tkinter potrebbe avere persino più senso che farla con wxpython o con pyqt (fermo restando il mio disprezzo per Tkinter, eh). Infatti i gui framework più evoluti dispongono già di qualche forma di astrazione MCV incorporata che ti aiuta a risolvere questi problemi... ti mettono a disposizione un pattern: anche se non è obbligatorio seguirlo, la cosa migliore e più facile che puoi fare è usare gli strumenti che hai. Invece Tkinter non ha niente di tutto questo (almeno, credo di no) e quindi bisogna implementare da zero, e come esercizio è anche meglio se vuoi....

> un esempio di implementazione del pattern MVC
Carino grazie, appena ho un attimo gli do un'occhiata... Mi interessano sempre queste cose, soprattutto perché prima o poi mi dovrò decidere a scrivere qualche capitolo su mcv nel mio libro su wxpython... e non saranno capitoli facili da calibrare...

Offline nuzzopippo

  • python erectus
  • ***
  • Post: 231
  • Punti reputazione: 0
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #13 il: Dicembre 22, 2019, 09:02 »
.... Infatti i gui framework più evoluti dispongono già di qualche forma di astrazione MCV incorporata che ti aiuta a risolvere questi problemi... ti mettono a disposizione un pattern: anche se non è obbligatorio seguirlo, la cosa migliore e più facile che puoi fare è usare gli strumenti che hai. Invece Tkinter non ha niente di tutto questo ....

Vero, in effetti temo che tale "astrazione incorporata" mi abbia "nascosto" per lungo tempo la "astrazione" MCV implicita, ho sempre utilizzato le tabelle (e non solo quelle) in altro modo.

Continuando a procedere nelle "letture" su MCV (comprendere richiede tempo e pratica) mi rendo conto di aver agito e ragionato, nel mio precedente spunto, solo in ragione della View. Allo stato, volendo definire un generico oggetto "tabella" da riutilizzare e rispettoso di detto paradigma mi sembra di dover prendere in considerazioni le "classi astratte" ed "abstractmethod" nel caso intenda stabilire dei metodi base "obbligati" per Controller e Model.

In particolare, la considerazione che una tabella di per se, di norma, non sarebbe una view "completa", bensì un elemento di una view più estesa mi fa anche pensare ad una "gerarchia" di controller, ossia :
  • controller specifici alla "tabella" che notifichino, p.e., l'avvenuta selezione di un elemento dati o eventuale richiesta di update, oltre che alla tabella stessa una intervenuta variazione dati, per il refresh;
  • controller o "oggetti" di livello superiore che ricevano le notifiche di selezione/update dai controller di tabella ed agiscano di conseguenza a livello di view e dati principali.

... l'ipotesi procedimentale su esposta mi sembra "logica" ma non saprei dire quanto "in linea" con il paradigma MCV, al momento non ho trovato nulla che la escluda ma data la mia scarsa comprensione dell'inglese ...
« Ultima modifica: Dicembre 22, 2019, 09:04 da nuzzopippo »

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 3.025
  • Punti reputazione: 9
    • Mostra profilo
Re:visualizzare dati intabellati
« Risposta #14 il: Dicembre 22, 2019, 13:15 »
assolutamente no, non è il caso di complessificare, non ti serve quella roba per implementare un meccanismo di mcv... piuttosto, in genere ti serve un observer, che di solito viene introdotto subito prima di mcv nei manuali, per quanto ne so.