2010-06-03 9 views
5

Ho un'applicazione Java che utilizza SWT come toolkit e mi sto stancando di tutto il brutto codice della piastra della caldaia necessario per aggiornare un elemento della GUI.SWT Java: wrapping syncExec e asyncExec per ripulire il codice

Solo per impostare un pulsante disattivato per essere abilitato devo passare attraverso qualcosa di simile:

shell.getDisplay().asyncExec(new Runnable() { 
    public void run() { 
     buttonOk.setEnabled(true); 
    } 
}); 

ho preferiscono mantenere il mio codice sorgente come piatto come mi sarà possibile, ma ho bisogno di un enorme 3 livelli di rientro solo per fare qualcosa di semplice

C'è un modo per avvolgerlo? Vorrei una classe come:

public class UIUpdater { 
    public static void updateUI(Shell shell, *function_ptr*) { 
     shell.getDisplay().asyncExec(new Runnable() { 
      public void run() { 
       //Execute function_ptr 
      } 
     }); 
    } 
} 

e può essere utilizzato in questo modo:

UIUpdater.updateUI(shell, buttonOk.setEnabled(true)); 

Qualcosa di simile a questo sarebbe grande per nascondere quella orribile pasticcio SWT sembra pensare è necessario fare nulla.

Come ho capito, Java non può fare i puntatori di funzioni. Ma Java 7 avrà qualcosa chiamato Closures che dovrebbe essere quello che voglio. Ma nel frattempo c'è qualcosa che posso fare per passare un puntatore a funzione o un callback ad un'altra funzione da eseguire?

Per inciso, sto iniziando a pensare che valga la pena di rifare questa applicazione in Swing, e non devo sopportare questa orribile merda e non cross-platformy di SWT.

+0

Spero che tu sappia, che Swing è unico thread troppo. Quindi devi fare lo stesso come in SWT per aggiornare un elemento della GUI da un altro thread. L'unica differenza è che Swing non genera un'eccezione quando chiami i metodi Swting dal thread sbagliato. Ma vedrai probabilmente bug insoddisfatti nella tua app quando commetti un errore. –

risposta

4

Ho avuto un problema simile nel mio codice SWT.

Ho scritto una classe base che non aveva nient'altro che i metodi asyncExec e syncExec. Ho avuto un metodo per ogni metodo GUI che volevo chiamare.

La mia classe thread non-GUI ha esteso la classe base.

Così, alla classe thread non-GUI, avrei una chiamata come setEnabled(shell, true)

nella classe base, mi piacerebbe definire un metodo public void setEnabled(Shell shell, boolean flag) che includerebbe il codice nel tuo primo esempio.

+0

Questo sembra l'unico modo in cui questo può essere fatto senza puntatori di funzione e/o chiusure. – jonescb

2

L'ho risolto qualche tempo fa in un progetto a codice chiuso. Il mio API funzionava così:

SWTUtils.asyncExec(display).on(this.getClass(), this).runInUIThread(123); 

Questa chiamata potrebbe eseguire il metodo runInUIThread(.) sull'istanza this con il parametro 123. Il disordine necessario qui è il parametro this.getClass().

tuo esempio riscritta:

SWTUtils.asyncExec(shell.getDisplay()).on(Button.class, buttonOk).setEnabled(true); 

mia implementazione utilizzato CGLIB per creare un proxy dinamica per la classe data. Questo proxy è stato restituito da on(.) e la chiamata al metodo e i relativi parametri sono stati registrati e passati a display.asyncExec(.). Ho usato Objenesis per l'istanziazione del proxy.

Potreste essere sorpresi dal fatto che non ci sia alcun impatto percepibile sulle prestazioni. Dal momento che il proxy è stato memorizzato nella cache e la reflection API necessaria per chiamare il metodo effettivo è diventata molto veloce in java 1.6, l'ho persino usata per gli ascoltatori di eventi.

Ovviamente questa è una soluzione piuttosto folle;) Non riesco a pubblicarlo, ma se sei così incazzato come lo ero da tutte queste classi interne anonime, potresti volerlo fare. In realtà non è troppo codice.

2

Tu dici che vuoi qualcosa di simile:

public class UIUpdater { 
    public static void updateUI(Shell shell, *function_ptr*) { 
     shell.getDisplay().asyncExec(new Runnable() { 
      public void run() { 
       //Execute function_ptr 
      } 
     }); 
    } 
} 

Il fatto che non si può avere questa non è una funzione di SWT, è una funzione di Java come linguaggio di programmazione. La mancanza di Java di funzioni e chiusure di ordine superiore ti impedisce di creare una buona DSL che potrebbe nascondere quel cruft per te, quindi le altre risposte che hai ricevuto valgono quanto qualsiasi a meno che tu non cambi le lingue.

Ora, se si stesse utilizzando un linguaggio come Scala, ad esempio, penso che la risposta sia molto diversa. Probabilmente creerai una sorta di funzione che imita una struttura di controllo che assicurerebbe che le tue chiamate SWT vengano eseguite sul thread di visualizzazione SWT principale.

Qualcosa di simile:

val enabled = model.isEditable 
Swt { 
    text.setEnabled(enabled); 
    composite.refresh(); 
} 
Problemi correlati