2011-04-27 10 views
5

¿Alguien puede explicar por qué lo siguiente no funciona como espero?removeAll no elimina en la próxima validación?

Al presionar el botón 'should' debe aparecer en la pantalla solo el JScrollPane (vacío), es decir, el campo de entrada y el botón desaparecerán. Sin embargo, permanecen hasta que el componente se redimensiona ...

public static void main(String[] args) 
{ 
    JFrame frame = new JFrame("test"); 
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    final JPanel panel = new JPanel(); 

    Container cp = frame.getContentPane(); 
    cp.setLayout(new FlowLayout()); 
    cp.add(new JScrollPane(panel)); 

    Component textField = new JTextField("i am input"); 
    JButton button = new JButton(new AbstractAction("i am pressy") 
    { 
     @Override 
     public void actionPerformed(ActionEvent e) 
     { 
      // this is already on the EDT 
      panel.removeAll(); 
      panel.revalidate(); 
     } 
    }); 

    panel.setLayout(new FlowLayout()); 
    panel.add(textField); 
    panel.add(button); 

    frame.pack(); 
    frame.setVisible(true); 
} 

Gracias por su ayuda. pag.

+2

Pruebe 'panel.repaint()' en su lugar? – Jeremy

+1

Bueno [sscce] (http://sscce.org/). – trashgod

Respuesta

18

Al actualizar una interfaz gráfica de usuario visible el código debería ser:

panel.revalidate(); 
panel.repaint(); // sometimes needed, this appears to be one of them 
2

Puede ejecutar panel.repaint() como se especifica en el comentario de @Jeremy, sin embargo, la interfaz de usuario seguirá cambiando cuando cambie el tamaño de la ventana. La razón es que la eliminación de los elementos de JPanel hará que el panel cambie de tamaño. Una operación de repintado no causará que el panel cambie de tamaño hasta que JFrame vuelva a verificar su diseño (como ocurre en el redimensionamiento de una ventana).

Para asegurarse de que el diseño se distribuye correctamente en un cambio, puede llamar al frame.validate(). Esta operación hará que JFrame se revalide a sí mismo y a todos los componentes secundarios, que es la misma operación que se lleva a cabo durante un evento de cambio de tamaño de la ventana. Para ejecutar este método en su código que tendría que cambiar JFrame frame al final, es decir,

final JFrame frame = new JFrame("test"); 
+0

No creo que la eliminación desencadene el cambio de tamaño; Creo que el redimensionamiento desencadena 'repaint()' a través del 'ComponentListener' de la ventana padre. El cambio de aplicaciones también funciona a través del 'WindowListener' de la ventana. Además, no puedo reproducir el resultado 'frame.validate()' a menos que también cambie el tamaño, la ubicación o el diseño de algún componente. – trashgod

+0

@trashgod si usted ve o no un cambio de tamaño adicional (también conocido como: diseño de Kris correctamente distribuido) depende de si el panel tiene o no un padre que sea validationRoot (debajo del nivel superior). Para estar completamente seguro de que el diseño se vuelve a evaluar en todos los contenedores de nivel superior, la validación de ese contenedor (que también es la raíz de validación más alta) es el camino a seguir – kleopatra

+2

sin necesidad de una referencia (final o de otro tipo) a el marco - SwingUtilities.windowForComponent es tu amigo :-) – kleopatra

9

El método revalidate() marca componentes como la necesidad de ser presentado, pero hasta que algo desencadene repaint() no verá ningún cambio. Cambiar el tamaño de la ventana primaria es uno de esos disparadores; el cambio de aplicaciones es otro. En este version anterior, observe cómo setSize() en el panel obvia la necesidad de repaint(). Del mismo modo, este example cambia el diseño en resetGame().

El artículo Painting in AWT and Swing entra en más detalles.

import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 
import javax.swing.WindowConstants; 

/** @see https://stackoverflow.com/questions/5812002 */ 
public class RevalidateTest { 

    private static JPanel panel = new JPanel(); // default FlowLayout 
    private static JTextField text = new JTextField("Text field"); 
    private static JButton clear = new JButton(new AbstractAction("Clear") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      panel.removeAll(); 
      panel.add(reset); 
      panel.revalidate(); 
      panel.repaint(); 
     } 
    }); 
    private static JButton reset = new JButton(new AbstractAction("Reset") { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      panel.removeAll(); 
      panel.add(text); 
      panel.add(clear); 
      panel.revalidate(); 
      panel.repaint(); 
     } 
    }); 

    static void createAndShowGUI() { 
     JFrame frame = new JFrame("Test"); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     panel.add(text); 
     panel.add(clear); 
     frame.add(panel); // default BorderLayout center 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 
+0

Ver también ['DynamicLayout'] (http://stackoverflow.com/questions/5750068/java-swing-how-to-change-gui-dynamically/5751044#5751044) – trashgod

+0

pero entonces, qué código de aplicación en si alguna vez llamaría a setSize ;-) Es solo otro disparador que pone en cola un componente para volver a pintar, así que mejor adhiérase a la ruta directa que a la desviación. – kleopatra

+0

@kleopatra: Muy bien; solo un ejemplo destinado a iluminar la fontanería. Actualizando ... – trashgod

Cuestiones relacionadas