2010-07-17 12 views
6

Sto tentando di ridefinire la mia applicazione (con più di 1000 linee di codice GUI) su un pattern in stile MVC. Il codice logico è già separato dalla GUI, quindi non è un problema. La mia preoccupazione è la separazione della vista dal controller. Capisco che il principio di base di MVC e this tutorial nel wiki wxpython sia stato molto utile, ma l'esempio di codice è un po 'semplicistico e mi lascia dubbi quando provo ad applicare il principio al mio progetto, che è un po' più complesso.Ri-factoring in pattern MVC: dubbi sulla separazione della vista dal controller

Un frammento di struttura ..

Ho un MainWindow con un numero di widget tra cui una (sezione schede) noteBook, il notebook ha un numero di linguette una delle schede (che chiamo FilterTab) contiene due istanze di una classe (che io chiamo un FilterPanel), che è un pannello con una listbox, tre pulsanti, uno per cancellare, uno a rimuovere e uno per aggiungere elementi alla/dalla lista . A seconda dei flag passati alla creazione di istanze, gli eventi di aggiunta possono creare diversi tipi di finestre di dialogo, ad esempio una finestra di dialogo di testo o directoryPicker ecc.

Questa è solo una parte della GUI che è abbastanza stratificata con i gestori di eventi sepolto nella classe FilterPanel.

Se dovessi convertire quella parte di MVC avrei dovuto legare gli eventi dei pulsanti per ogni istanza del FilterPanel nel mio controller (invece che nella classe filterPanel) -in questo caso ci sono due (istanze filterPanel)

quindi vorrei avere qualcosa di simile per ogni pulsante, (3 tasti per filterPanel * numero di istanze del pannello) più i gestori ..

self.mainWindow.filterTab.dirFilterPnl.Bind(wx.EVT_BUTTON, 
            self.onAdd_dirFilterPnl, 
          self.mainWindow.filterTab.dirFilterPnl.addBtn, 
          self.mainWindow.filterTab.dirFilterPnl.addBtn.GetId() 
            ) 

che aggiunge un sacco di codice extra, (il doppio della quantità di evento gestori se ho solo due istanze filterPanel)

Quindi mi piacerebbe sapere sto prendendo il giusto approccio?

risposta

9

Se dovessi convertire quella parte di MVC avrei dovuto legare gli eventi dei pulsanti per ogni istanza del FilterPanel nel mio controller (invece che nella classe filterPanel)

Non necessariamente! La filosofia e la pratica di MVC non implicano che i "punti di vista" siano widget elementari; il tuo FilterPanel potrebbe essere pensato/implementato come un widget "ricco/composito" che genera i suoi "eventi" di livello superiore (diretti al controller) e si aggiorna in modo appropriato. Quindi, quel widget composito può avere gestori per "eventi" di livello inferiore e sintetizzare da loro eventi di livello superiore, inviandoli al controllore; il controller non deve conoscere o preoccuparsi di ogni pulsante, ecc., solo degli eventi di astrazione superiore che riceve, come "l'utente vuole selezionare una directory per lo scopo X" o "l'utente vuole inserire il testo per lo scopo Y" - e rispondete dicendo loro cosa fare.

Il punto chiave è che la vista non prende decisioni "semantiche" basate sugli eventi che gestisce, né invia mai alcun comando al modello - il controller è l'indispensabile "intermediario" per tutte queste interazioni.

Per un'analogia, si consideri che il livello più basso della GUI ha eventi di livello molto basso come "tasto sinistro del mouse premuto" e "tasto sinistro del mouse su" - un "widget pulsante" reagisce direttamente a loro cambiando il l'aspetto del pulsante (una decisione "visiva", non una "strategica") e alla fine, se e quando appropriato, la sintesi di un evento di astrazione superiore come "il pulsante è stato cliccato" (quando un pulsante del mouse è seguito da un pulsante del mouse senza movimenti intermedi del mouse che invalidano l'ipotesi del "clic", ad esempio). Quest'ultimo viene quindi indirizzato a qualsiasi livello superiore che deve "rispondere" ai clic del pulsante.

Analogamente, rich/widgets compositi possono assumere tali eventi e sintetizzare quelli superiore astrazione per il controller reagire. (Lo stesso evento astratto potrebbe essere generato da un clic sul pulsante, una selezione di menu, determinate sequenze di tasti ... al controller non interessano queste considerazioni "visive" di livello inferiore, cioè il lavoro della vista/widget e la vista/widget non codifica le decisioni "strategiche" e le azioni per tali interazioni dell'utente, questo è il lavoro del controllore).

La separazione delle preoccupazioni aiuta con problemi come la verifica e la flessibilità dell'applicazione; non è inaudito, perché tali vantaggi possono essere acquistati al prezzo di avere un po 'più di codice in un'alternativa dove tutto è hardcoded ... ma se scegli MVC implichi che il prezzo, per te, vale la pena pagare.

wx potrebbero non essere la cornice ideale per implementare questo, ma si può sottoclasse wx.Event - o si potrebbe utilizzare un sistema di evento separato come pydispatcher per gli eventi più alto di astrazione che scorrono tra i sottosistemi separati, al fine di slegare il controller dalla scelta specifica del framework GUI. Di solito uso Qt, il cui modello di segnali/slot, IMNSHO, si estende/scala meglio dei tipici sistemi di eventi dei framework GUI. Ma questa è una scelta diversa e un problema diverso.

+1

Risposta eccellente che ha corretto la mia prospettiva che era fissata in modo malsano sulla rimozione di tutti i collegamenti degli eventi dalla vista, che non è solo impraticabile ma a un livello fondamentale impossibile. Ho sviluppato ricchi widget compositi prima quindi non è un problema (usando wx.NewEventType, wx.PyEventBinder, wx.PyCommandEvent per prendere degli eventi come suggerivi), perché non ci avevo pensato per questo problema era probabilmente ancora dovuto alla fissazione di cui sopra. Grazie ancora per la risposta illuminante – volting

+0

Un ultimo dubbio (se tutto va bene) riguardo alla casella di riepilogo, aggiungendo solo elementi unici, sarebbe considerato una decisione semantica? – volting

+2

@volting, prego!Mostrare ogni elemento solo una volta nella lista, tanto quanto (dire) se mostrare gli articoli nell'ordine in cui sono stati aggiunti o in qualche ordine ordinato, sono cose che classificherei normalmente come decisioni visive - non c'è una decisione difficile e veloce criterio, ma mi sembra essenzialmente una decisione su "come mostrare" le cose all'utente, al contrario di "quali azioni semantiche eseguire". –

1

wxPython include pubsub, che segue la metodologia di pubblicazione/sottoscrizione. È simile al pydispatcher, anche se le loro implementazioni differiscono. Il wiki wxPython ha alcuni esempi su come utilizzare PubSub nel vostro programma e c'è anche questo semplice tutorial sul tema:

http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/

MVC in GUI non è esattamente la stessa che è in Django o TurboGears . Trovo che posso mettere la maggior parte della mia logica nei controller e nella mia "vista", lego semplicemente il controller. Qualcosa di simile a questo:

view.py

btn.Bind (wx.EVT_BUTTON, self.onButton)

def onButton (self, evento): controller.someMethod (* args, ** kwargs)

a seconda di ciò che il calcolo è, posso eseguire un thread dal mio controller e inviare il risultato in seguito utilizzando wx.CallAfter + PubSub.

+0

Sto già usando pubsub nel mio progetto, con un numero di ascoltatori nella mia GUI per i messaggi inviati dalla logica ... "Trovo che posso mettere la maggior parte della mia logica nei controller e nella mia vista" Certo il tuo non è legato a nessun pattern, ho 1K di GUI .. ma è impostato su double -Io vorrei rendere il mio progetto flessibile estendibile con facilità e allo stesso tempo imparare qualcosa di nuovo. Grazie – volting

Problemi correlati