2009-01-23 14 views
8

La forma ingenua de la escritura de la construcción de un menú en una aplicación Java Swing es hacer algo como:forma correcta de utilizar acciones para crear menús, barras de herramientas y otros componentes en Java

JMenu fileMenu = new JMenu("File"); 
JMenuItem openItem = new JMenuItem("Open..."); 
openItem.addActionListener(new ActionListener() { /* action listener stuff */ }) 
fileMenu.addMenuItem(openItem); 

Un desarrollador más experimentado reconoce que se puede acceder a las acciones a través de una variedad de mecanismos: menús, botones de la barra de herramientas, tal vez incluso otros flujos de trabajo en el sistema. Esa persona es más probable que escribir:

Action openAction = new AbstractAction(); 
openAction.setName("Open..."); 
openAction.addActionListener(new ActionListener() { /* action listener stuff */ }) 
... 
JMenuItem openItem = new JMenuItem(openAction); 

Mi pregunta es, cuál es la mejor manera de manejar estos objetos Acción para que puedan ser utilizados a través de menús, barras de herramientas, etc?

  • ¿Crear una clase de fábrica que devuelva acciones específicas?
  • ¿Declara todas las acciones como private static final Action en alguna clase de utilidad?
  • Aproveche un marco de aplicación Java?
  • ¿Algo más?
+0

Duplicado de http://stackoverflow.com/questions/448179/organizing-actions-in-a-swing-application#448195, como lo señaló Dave Ray. –

Respuesta

4

Las aplicaciones que he desarrollado y que necesitan usar las mismas acciones en los menús, barras de herramientas y otros botones se han hecho usando Swing Application Framework.

Swing Application Framework

Este marco permitirá tener un archivo de recursos donde se pueden definir todos los textos de menú, información sobre herramientas e iconos. Creo que los iconos son la clave, no tienes que cargarlos tú mismo. Además, si tiene alguna acción que necesite habilitar/deshabilitar, puede anular el método para controlar su estado.

Vale la pena leer el sitio web.

0

Action es una mala abstracción - ActionListener un soldado a un hombre pobre de Map.

Ciertamente no los asigne a un static ya que son mutables y también necesitan algún contexto para operar de manera útil.

Mi consejo general para la programación de la GUI es notar que en realidad es muy similar a cualquier otra área de programación. Sigue las buenas prácticas habituales. Cabe destacar que la estratificación, la separación de preocupaciones, el uso (implementación) de la herencia rara vez y no escribir una gran bola de barro.

1

Puede agrupar todas sus abstractAction utilizando el mapa dedicado javax.swing.actionmap. Ver http://java.sun.com/javase/6/docs/api/javax/swing/ActionMap.html

Además, cada JComponent tiene una actionMap (getActionMap()).

class MyComponent 
extends JPanel 
{ 
public static final String ACTION_NAME1="my.action.1"; 

public MyComponent() 
{ 
AbstractAction action= new AbstractAction() { ... } 
getActionMap().put(ACTION_NAME1,action); 
... 

menu.add(getActionMap().get(ACTION_NAME1)); 
} 

} 

creo que sirve

0

Véase también this question, que es más o menos lo mismo que lo que está pidiendo.

0

Editar: Tengo la sensación de que la gente no creía que esto fuera posible o fácil, así que lo hice - tardé aproximadamente una hora desde cero - me hubiera llevado 40 minutos si hubiera usado un solo método como un objetivo en lugar de reflejarlo para separar los métodos para cada elemento del menú.

Aquí está el Tested source code. Funciona, pero es un gran método y feo: refactorícelo si lo usa. Puedo arreglarlo un poco en los próximos días, siempre he querido tener una copia de esto para reutilizar.

--- post original

En primer lugar, recuerde que debe separar el código de datos. Eso significa que usted NUNCA debe escribir:

new Menu("File..."); 

La cadena "Archivo ..." es datos. Si comienzas a pensar de esta manera, encontrarás que tu pregunta se responde a sí misma.

Primero necesita crear algunos datos. Debe obtener "Archivo ..." y "Guardar" en los menús. Yo por lo general comenzar, con una matriz de cadenas (que se puede mover fácilmente a un archivo)

new String[]{"File...","+Save","Load"...} 

Este es uno de los patrones más simples que he comenzó con. Luego puede analizar el signo + y usarlo para indicar "Desplegar un nivel en el menú cuando agrega este"

Esto es sólo una convención tonta, invente la suya propia si no le gusta.

El siguiente paso es vincularlo al código para ejecutar. Puede hacer que todos llamen al mismo método, pero qué dolor en el culo (declaración de cambio gigante). Una posibilidad es utilizar la reflexión para vincular un nombre de método mientras está leyendo en los datos. He aquí una solución (de nuevo, no podría adaptarse a sus gustos)

new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...} 

A continuación, analizar fuera de la cosa entre corchetes, reflexivamente conectarlo a un método en su clase actual y ya está.

Existe la tentación que SIEMPRE tengo en este momento, y he aprendido a luchar porque NUNCA funciona. La tentación es usar el primer conjunto de datos ("Archivo ...") y manipularlo para que se ajuste a algún patrón y se una de forma automática a su código (en este caso, elimine todos los caracteres no alfa, haga que la primera letra minúscula y añada "Menú" para obtener el nombre correcto del método). No dude en probar esto, es muy atractivo y parece ingenioso, pero prepárese para abandonarlo cuando no cumpla con alguna necesidad (como dos elementos del menú con el mismo nombre en diferentes submenús).

Otra forma sería si su idioma es compatible con los cierres, a continuación, en realidad se podría crear el nombre de archivo y cierre en el mismo lugar ..

De todos modos, una vez que comience la codificación de esta manera, usted encontrará que todos sus la construcción del menú está en un solo método de 10 líneas y puede modificarlo para adaptarlo a sus necesidades. Tuve un caso en el que tuve que cambiar un conjunto de menús a una jerarquía de botones y lo hice en 2 minutos.

Al final, puede usar este patrón para configurar los objetos de acción fácilmente y cambiar cómo se usan fácilmente (en una sola ubicación, una sola línea de código), para que pueda experimentar con ellos. Hay muchas maneras de usarlos, pero si no hace lo que estoy recomendando aquí, terminará teniendo que implementar de nuevo en cada elemento del menú para cada cambio, lo que es realmente molesto: después de un solo cambio, habrá perdido más tiempo que si acabara de implementar una solución basada en datos en primer lugar.

Esto realmente no es codificar, debe tomar como una hora o dos, entonces nunca tiene que escribir nuevo menú (" ... otra vez. Confía en mí, este tipo de herramientas es casi siempre vale la pena.

edición:

que casi siempre código de datos impulsada por estos días lo general voy a prototipos de algunas cosas de la forma habitual, reconocen el patrón y refactor - y si se reestructuran correctamente, los datos casi siempre. factores y lo que queda es hermoso, apretado y fácil de mantener.

Podría hacer lo que sugerí anteriormente en menos de 1/2 h nuestra (tal vez una hora para hacer la versión reflectante). Esto casi siempre es tan largo como lo sería usar la versión no modificada, y desde ese momento, sus ahorros se multiplican por cada cambio.

Esto es muy similar a lo que a la gente le gusta de ruby, excepto que con ruby ​​parece insertar aún más datos en su código (lo que hace terriblemente difícil extraer completamente los datos del código, que es un buen objetivo para internacionalización).

Hmm, ¿mencioné que si eres bueno para extraer tus datos de esta manera, i18n es prácticamente gratis?

Te sugiero que solo lo intentes alguna vez y veas lo que piensas. Incrustar el control en las cuerdas no es necesario si te hace sentir incómodo. Tiendo a usar matrices de cadenas/objetos simplemente porque son realmente fáciles de ingresar, están todavía en el archivo mientras codifica y son triviales para externalizar más tarde, pero si le gustan los archivos YML o XML o de propiedades, use lo que sea cómodo con - ¡solo abstrae tus datos de tu código!

+0

¿Realmente codifica sus GUI de esta manera? : | –

+0

¿Cómo puede su GUI ser factorizada completamente sin ser manejado por datos? Hay tanta repetitividad. –

+0

Por cierto, String.split (que solía ser StringTokenizer) puede ayudar mucho con el análisis de estos elementos. Una cadena como "File ... | * | fileMethod" se puede analizar en un segundo (el * significa "nivel superior" en este caso; puede crear su "idioma" sobre la marcha) muy parecido a un DSL de Ruby. pero más fácil) –

0
  1. Cree una acción de base para su aplicación; esto le ayudará enormemente más adelante
  2. No crear acciones que usted tiene en su código, en lugar de favorecer subclases de su acción de base

Para organizarlos, que dependerá de lo que está haciendo con ellos, y usted puede tener algunas acciones organizadas de una manera y otras creadas de otra manera. Todo dependerá.

Lo que quiere es tener una manera consistente de ubicar/crear una acción en su código.

Dependiendo de su UI, puede necesitar diferenciar entre acciones "estáticas" (es decir, cosas que siempre están disponibles en su aplicación, como el sistema de menús) y acciones dinámicas que se crean solo en ciertas pantallas o en determinadas ubicaciones.

En cualquier caso, usar subclases concretas de su acción base especializada lo ayudará a mantener estas cosas organizadas. Lo que no desea quiere es especificar cosas como etiquetas, símbolos mnemotécnicos e íconos en su código.

Cuestiones relacionadas