2016-06-03 14 views
6

Si tratta di Delphi e VCL.C'è un modo semplice per chiamare un metodo in un frame, quando il modulo che lo possiede viene attivato/disattivato?

Ho diversi frame che possono essere utilizzati in più moduli, solitamente creati e aggiunti al modulo in codice. È possibile che un modulo contenga molti di questi frame. Ho bisogno di eseguire del codice in questi frame quando il modulo che lo contiene viene disattivato e invertito quando viene attivato.

TMyFrame.FormActivated; 
TMyFrame.FormDeactivated 

Una soluzione è quella di avere un gestore di eventi FormActivate/FormDeactivate in quelle forme che richiedono un metodo di telai.

procedure TMyForm.OnActivate(_Sender: TObject); 
begin 
    FFrame1.FormActivated; 
    FFrame2.FormActivated; 
end; 

Ecco come ho implementato per ora, ma che ha diversi svantaggi:

  • devo implementare questo in ogni forma che contiene un esempio di questi fotogrammi
  • La forma deve sapere che alcuni frame hanno bisogno di questa chiamata (accoppiamento stretto)
  • I frame devono pubblicare due metodi da chiamare in questi eventi. Preferirei non esporre questi metodi.

Un'altra opzione sarebbe quella di impostare un evento FormActivate/FormDeactivate dall'interno del costruttore del frame. Ma questo significherebbe che nessun altro codice potrebbe essere eseguito in questi eventi e non funzionerà se ci sono molti di questi frame sullo stesso modulo.

Esiste qualche altra opzione che funzioni per qualsiasi modulo che contenga molti di questi frame?

Ho bisogno di questo per Delphi 2007 se questo è importante.

+2

Perché non utilizzare il proprio messaggio personalizzato? Il modulo può utilizzare la lista dei componenti e inviare il messaggio a qualsiasi frame che si trova su di esso, ei frame che devono reagire forniscono un gestore per quel messaggio. Quindi è un metodo semplice sul form ('SendActivationNotification (Activated: Boolean;', forse?) Che esegue il loop e invia il messaggio personalizzato usando wParam per passare l'indicazione booleana dell'attivazione o disattivazione. –

+0

Si può avere il Piggyback su FormActivate/FormDeactivate gli eventi nel costruttore e passate l'evento se impostato da un altro componente –

+3

È possibile scrivere un gestore di eventi OnActiveFormChange per lo schermo, che tiene traccia del modulo attivo (per avere un riferimento al modulo precedentemente attivo) e loop tutti i controlli nella forma attiva e precedentemente attiva per trovare i frame e poi procedere come nel commento di Ken che si occupa dei proiettili rimanenti –

risposta

7

(Presupponendo VCL) Il frame deve in qualche modo intercettare gli eventi di attivazione/disattivazione del modulo genitore. Esistono molti modi per eseguire questa operazione (impostazione degli eventi OnActivate/OnDeactivate del genitore, sottoclasse con SetWindowLong(GWL_WNDPROC) o WindowProc), ma è necessario imporre che se più istanze del frame eseguono questo nella stessa istanza del modulo, l'ordine di rimozione del gancio deve essere il contrario di inserire il gancio. Inoltre, avresti il ​​problema di gestire correttamente i casi quando le maniglie delle finestre vengono ricreate.

Un approccio più semplice potrebbe essere quella di usare qualcosa di simile come un antenato di tutti i moduli nel progetto:

TMyForm = class(TForm) 
    procedure Activate; override; 
    procedure Deactivate; override; 
end; 

procedure TMyForm.Activate; 
begin 
    inherited Activate; 
    NotifyControls(CM_ACTIVATE); 
end; 

procedure TMyForm.Deactivate; 
begin 
    inherited Deactivate; 
    NotifyControls(CM_DEACTIVATE); 
end; 

e qualcosa come questo come un antenato di tutti i fotogrammi del progetto:

TMyFrame = class(TFrame) 
    procedure CMActivate(var Msg: TCMActivate); message CM_ACTIVATE; 
    procedure CMDeactivate(var Msg: TCMDeactivate); message CM_DEACTIVATE; 
end; 

procedure TMyFrame.CMActivate(var Msg: TCMActivate); 
begin 
    // parent form activated 
end; 

procedure TMyFrame.CMDeactivate(var Msg: TCMDeactivate); 
begin 
    // parent form deactivated 
end; 

in questo modo l'accoppiamento è abbastanza sciolto e permette ancora di ignorare il comportamento predefinito TMyFrame l'override del gestore di messaggi CM_ACTIVATE o CM_DEACTIVATE in discendenti che hanno bisogno di un trattamento speciale.

Avvertenze:

  1. Questo non è stato testato - è solo un rapido suggerimento, come punto di partenza. Potresti anche dichiarare e utilizzare i tuoi messaggi personalizzati al posto di CM_ACTIVATE/CM_DEACTIVATE, per evitare qualsiasi interferenza con il resto del VCL.
  2. NotifyControls Notifica tutti controlli - non solo i fotogrammi - ma controlli normali ignorano/non gestiscono CM_ACTIVATE/CM_DEACTIVATE messaggi per impostazione predefinita in modo che non dovrebbe essere un problema. Potresti anche implementare il tuo metodo NotifyFrames.
+1

Nel caso della sottoclasse, se avete bisogno di più sottoclassi sulla stessa finestra allo stesso tempo, potete usare 'SetWindowSubclass()' invece di 'SetWindowLong()' o 'WindowsProc'. Il sistema operativo fa tutta la contabilità per te e l'ordine in cui sono installati e rimossi non è importante. –

+0

Si scopre che questa è la soluzione più semplice poiché nel mio attuale caso d'uso tutti i frame e le forme discendono comunque da un antenato comune (che avevo completamente dimenticato) – dummzeuch

+0

+1, ma si noti che 'NotifyControls' trasmette solo ai controlli figlio immediati . se un frame non è un controllo figlio imidiate del modulo, non riceverà i messaggi. – kobik

6

Non so se questo è possibile qui, ma ho avuto un problema simile alcuni anni fa e l'ho risolto con una sorta di ereditarietà di forma/frame. Esiste una classe frame di base che dichiara questi metodi virtual e una classe form che cattura gli eventi e itera su tutti i frame secondari chiamando il metodo frame appropriato. I frame derivati ​​sovrascrivono tali metodi secondo necessità. Questo riduce l'accoppiamento alle classi base.

In un successivo refactoring questo è stato modificato in interfacce implementate dai frame, eliminando completamente l'accoppiamento tra le classi di form e frame.

+2

Sono interessato a maggiori dettagli sull'approccio interfacciato: come chiama il metodo i metodi? (componente, ISomeInterface, InterfaceVar) per tutti i suoi componenti? – dummzeuch

+0

Questo è l'approccio semplice. La soluzione ottimizzata può memorizzare nella cache le interfacce rilevanti in un elenco che è sincronizzato in un metodo di notifica sovrascritto. Non sono sicuro che il guadagno prestazionale valga la pena. –