java - propiedades - Cómo deshabilitar un contenedor y sus hijos en Swing
propiedades swing java (6)
JXLayer podría ser lo que estás buscando, según esta publicación :
Envuelva su contenedor con JXLayer y llame a
JXLayer.setLocked(true)
después de eso - todos los componentes en su interior estarán deshabilitados
No puedo encontrar una forma de desactivar un contenedor Y sus hijos en Swing. ¿Realmente Swing no tiene esta función básica?
Si configuro SetEnabled (falso) en un contenedor, sus hijos aún están habilitados.
La estructura de mi GUI es bastante compleja, y hacer una traversa de todos los elementos debajo del contenedor no es una opción. Tampoco hay un GlassPane encima del contenedor (el contenedor no es la ventana completa).
Esto es lo que se me ocurrió.
Component[] comps = myPanel.getComponents();
for (Component comp:comps){
comp.setEnabled(false);
}
Este es el código que uso. Visita recursivamente el árbol de componentes, manteniendo un contador para cada componente. Solo se mantienen referencias débiles en los componentes, lo que evita cualquier pérdida de memoria.
Usted dice que atravesar todos los elementos no es una opción, pero mi experiencia es que este código funciona bien para GUI bastante complejas. Por cierto, si Swing tuviera esta característica de forma nativa, de todos modos no habría otra manera que atravesar el árbol de componentes.
Ejemplo de uso (paréntesis significa deshabilitado):
a
/ /
b c
/ /
d e
setMoreDisabled(c)
a
/ /
b (c)
/ /
(d) (e)
setMoreDisabled(a)
(a)
/ /
b (c)
/ /
(d) (e)
setMoreEnabled(a)
a
/ /
b (c)
/ /
(d) (e)
Ahora el código:
import java.awt.Component;
import java.awt.Container;
import java.util.Map;
import java.util.WeakHashMap;
public class EnableDisable {
private static final Map<Component, Integer> componentAvailability = new WeakHashMap<Component, Integer>();
public static void setMoreEnabled(Component component) {
setEnabledRecursive(component, +1);
}
public static void setMoreDisabled(Component component) {
setEnabledRecursive(component, -1);
}
// val = 1 for enabling, val = -1 for disabling
private static void setEnabledRecursive(Component component, int val) {
if (component != null) {
final Integer oldValObj = componentAvailability.get(component);
final int oldVal = (oldValObj == null)
? 0
: oldValObj;
final int newVal = oldVal + val;
componentAvailability.put(component, newVal);
if (newVal >= 0) {
component.setEnabled(true);
} else if (newVal < 0) {
component.setEnabled(false);
}
if (component instanceof Container) {
Container componentAsContainer = (Container) component;
for (Component c : componentAsContainer.getComponents()) {
setEnabledRecursive(c,val);
}
}
}
}
}
Le sugiero que escriba un método recursivo que encuentre todas las instancias de java.awt.Container en su java.awt.Container y establezca sus componentes habilitados / deshabilitados. Así es como resolví este problema en mi clase extendida de JFrame:
@Override
public void setEnabled(boolean en) {
super.setEnabled(en);
setComponentsEnabled(this, en);
}
private void setComponentsEnabled(java.awt.Container c, boolean en) {
Component[] components = c.getComponents();
for (Component comp: components) {
if (comp instanceof java.awt.Container)
setComponentsEnabled((java.awt.Container) comp, en);
comp.setEnabled(en);
}
}
Como respuesta de VonC, no existe una solución simple. Así que te recomiendo que programes desde el principio con una infraestructura de soporte.
Es probable que una infraestructura simple sea, por ejemplo, utilizar oyentes delegados que realicen una comprobación de "evento habilitado" desde el indicador de un supercontenedor antes de que el evento real responda:
class ControlledActionListener extends ActionListener {
...
public void actionPerformed( ActionEvent e ) {
if( !container.isEnabled() ) return;
doYourBusinessHere();
}
}
O mejor aún, puede usar el APT para inyectar automáticamente el código repetitivo para usted.
Esto funciona bien todo el tiempo. Es la forma limpia de bloquear la interacción del usuario y las llamadas de programación con un solo esfuerzo. A pesar de que le cuesta algunos códigos para respaldar la funcionalidad subyacente, obtiene a cambio simplicidad, facilidad de uso y estabilidad.
PD. Me gustaría ver una mejor solución a este problema.
Para agregar a la respuesta de mmyers , deshabilitar a los niños no es una tarea fácil (ver este hilo )
El problema es casi insoluble en el caso general. Es por eso que no es parte del núcleo Swing.
Técnicamente, el estado disable-and-store-old-state seguido por un enable-and-restore-to-old-state puede parecer atractivo. Incluso podría ser agradable de tener en casos especiales. Pero hay (al menos, probablemente un montón más) dos problemas con eso.
Componentes compuestos
La recursión debe detenerse en un "componente compuesto" (o "entidad única"). Entonces el componente es responsable de mantener el estado de dependiente. No hay una forma general de detectar dicho componente; los ejemplos son JComboBox, JXDatePicker (que como cuestión relacionada)
Para hacer las cosas aún más complicadas, los dependientes no necesitan estar bajo la jerarquía del "componente compuesto", fi JXTable se ocupa del estado habilitado de ColumnControl (y del encabezado).
Intentar abordar ambos requeriría tener
a) una propiedad en el complejo: "no toques a mis hijos" y
b) una propiedad sobre los dependientes no confinados: "no me toques"Enlace a habilitado
enable-and-update-to-old podría romper el estado de la aplicación si el estado habilitado está ligado a una propiedad de modelo (de presentación u otra) y esa propiedad cambió mientras tanto, ahora el estado anterior no es válido.
Intentar abordar eso requeriría tener
c) una propiedad "real" almacenada-vieja-habilitada-debida-a-ver-preocupaciones
d) enlazar la propiedad del modelo de presentación tanto a la habilitada como a la almacenada-antigua habilitadaJXRadioGroup tiene una variante de ese problema: al deshabilitar, el grupo mismo o el controlador general, realiza un seguimiento de los antiguos habilitados de cada botón. El botón habilitado está controlado por la Acción, si hay una Acción. Por lo tanto, el controlador habilitado debe restaurar a habilitado anterior o habilitado para acción. Durante la desactivación del grupo (como grupo), aparece un problema si la Acción habilitada era falsa al almacenar y cambiada a verdadera. Otro si se agregan acciones.
Ahora imagine la complejidad de las transiciones de estado cuando se sobrecarga a) - d)