2010-06-03 16 views
5

Tengo una aplicación Java que usa SWT como kit de herramientas, y me estoy cansando de todo el horrible código de la placa de la caldera que se necesita para actualizar un elemento GUI.Java SWT: envolviendo syncExec y asyncExec para limpiar el código

Sólo para poner un botón de discapacitados que se habilite tengo que pasar por algo como esto:

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

prefiero mantener mi código fuente tan plano como me sea posible, pero necesito la friolera de 3 niveles de sangría solo para hacer algo simple.

¿Hay alguna forma de que pueda envolverlo? Me gustaría una clase como:

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

y se puede utilizar de esta manera:

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

Algo como esto sería ideal para ocultar esa horrible SWT desorden parece pensar que es necesario hacer nada.

Según tengo entendido, Java no puede hacer punteros a las funciones. Pero Java 7 tendrá algo llamado Closures, que debería ser lo que yo quiero. Pero, mientras tanto, ¿hay algo que pueda hacer para pasar un puntero de función o devolución de llamada a otra función para que se ejecute?

Como acotación al margen, estoy empezando a pensar que sería la pena el esfuerzo para hacer de nuevo esta aplicación en Swing, y yo no tengo que aguantar esto fea basura y no cruzada platformyness de SWT.

+0

espero que sepas, que Swing es un único subproceso también. Por lo tanto, debe hacer lo mismo que en SWT para actualizar un elemento GUI de otro hilo. La única diferencia es que Swing no lanza una excepción cuando llama a los métodos Swting del hilo equivocado. Pero verá los errores de mayn weired en su aplicación cuando lo haga incorrecto. –

Respuesta

4

Tuve un problema similar en mi código SWT.

Escribí una clase base que no tenía más que los métodos asyncExec y syncExec. Tenía un método para cada método de GUI que quería llamar.

Mi clase de subproceso sin GUI extendió la clase base.

Así que en la clase de rosca no GUI, tendría una llamada como setEnabled(shell, true)

En la clase base, me gustaría definir un método public void setEnabled(Shell shell, boolean flag) que incluiría el código en su primer ejemplo.

+0

Esto suena como la única forma en que esto se puede hacer sin punteros de función y/o cierres. – jonescb

2

Lo resolví hace algún tiempo en un proyecto de código cerrado. Mi API trabajó como esto:

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

Esta llamada se correría el método runInUIThread(.) en la instancia this con el parámetro 123. El desorden necesario aquí es el parámetro this.getClass().

tu ejemplo reescrito:

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

Mi aplicación utiliza CGLIB para crear un proxy dinámico para la clase dada. Este proxy fue devuelto por on(.), y la llamada al método y sus parámetros se registraron y pasaron al display.asyncExec(.). Usé Objenesis para la creación de instancias del proxy.

Es posible que se sorprenda de que no haya un impacto perceptible en el rendimiento. Como el proxying se almacenaba en caché y la API de reflexión necesaria para llamar al método real se hizo muy rápido en java 1.6, incluso lo usé para oyentes de eventos.

Obviamente esta es una solución bastante loca;) No puedo publicarla, pero si estás tan enojado como estaba por todas estas clases internas anónimas, es posible que quieras ir por ello. En realidad, no es demasiado código.

2

usted dice que quiere algo como:

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

El hecho de que no se puede tener esto no es una función de SWT, que es una función de Java como lenguaje de programación. La falta de Java de funciones y cierres de orden superior le impide crear un DSL bueno que oculte ese filtro por usted, por lo que las otras respuestas que ha recibido son tan buenas como cualquier otra a menos que cambie de idioma.

Ahora, si estuviera usando un lenguaje como Scala por ejemplo, creo que la respuesta es muy diferente. Probablemente crearías algún tipo de función que imita una estructura de control que aseguraría que tus llamadas SWT se ejecuten en el hilo principal de la pantalla SWT.

Algo así como:

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