2011-04-27 46 views
5

有人可以解释为什么以下不能如我所料?removeAll在下次验证时不会删除?

按下'should'按钮会导致仅包含(空)JScrollPane的显示,即输入字段和按钮应该消失。然而,他们留下,直到组件被调整大小...

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); 
} 

感谢您的帮助。页。

+2

试试'panel.repaint()'而不是? – Jeremy 2011-04-27 23:52:16

+1

好[sscce](http://sscce.org/)。 – trashgod 2011-04-28 03:21:51

回答

18

当更新一个可见的GUI代码应该是:

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

您可以执行panel.repaint(),如@Jeremy的评论中所述,但是,当您调整窗口大小时,UI仍会改变。原因是从JPanel中删除元素将导致面板调整大小。重绘操作不会导致面板调整大小,直到JFrame重新检查其布局为止(如调整窗口大小时)。

要确保布局正确地布置在更改上,您可以致电frame.validate()。此操作将导致JFrame重新验证自身和所有子组件,这与在窗口大小调整事件期间发生的操作是相同的。要在您的代码执行这个方法,你需要改变JFrame frame到最后,即

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

我不认为清除会触发调整大小;我认为通过父窗口的ComponentListener调整触发器repaint()。切换应用程序也可以通过窗口的WindowListener工作。另外,除非我也更改某个组件的大小,位置或布局,否则我无法再现您的'frame.validate()'结果。 – trashgod 2011-04-28 02:43:53

+0

@trashgod您是否看到额外的大小调整(又名:Kris的布局是否正确布局)取决于面板是否具有validationRoot(低于顶层)的父级。为了完全确定布局在所有顶级容器中都得到了重新评估,验证该容器(这也是最顶级的验证根目录)是去除 – kleopatra 2011-04-28 08:34:27

+2

的方式(无论是最终还是其他)框架 - SwingUtilities.windowForComponent是你的朋友:-) – kleopatra 2011-04-28 08:36:14

9

revalidate()方法标志着组件为需要布局,但直到触发repaint()你不会看到任何改变。调整父窗口的大小就是这样一个触发器;切换应用程序是另一个。在此之前的version中,请注意面板上的setSize()如何避免需要repaint()。同样,此example更改resetGame()中的布局。

文章Painting in AWT and Swing更详细。

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

参见['DynamicLayout'](http://stackoverflow.com/questions/5750068/java-swing-how-to-change-gui-dynamically/5751044#5751044 )。 – trashgod 2011-04-28 03:24:35

+0

但是,然后,哪个理智的应用程序代码会调用setSize ;-)这只是另一个将组件重新排队的触发器,所以更好地坚持直接路径而不是偏差。 – kleopatra 2011-04-28 07:28:32

+0

@kleopatra:很对;只是一个例子,旨在阐明管道。更新中... – trashgod 2011-04-28 16:44:52