拆除使用复杂布局的容器

时间:2012-05-31 13:27:24

标签: java swing applet gridbaglayout

我正在创建一个(j)applet,用户可以访问从树中选择的几个不同视图。 applet有一个主区域,当前视图显示在滚动窗格内,替换之前的内容。大多数情况下,这种方法很好,但是当要替换的视图具有更复杂的布局时,如大(~100个组件),而不是嵌套,删除需要几秒钟!创建大视图是快速的,只有删除速度很慢。这只在applet中很明显,在JFrame中运行应用程序的速度仍然和我预期的一样快。我使用GridBagLayout作为视图。

经过一些实验,我发现如果我更换

contents.remove(view); //contents is the view of the scrollpane.

view.removeAll();
contents.remove(view);
然后整个过程非常快。

我的猜测是这种行为的原因是Java的一些布局“神奇”,虽然我有一个解决方案但它感觉不对,似乎表明我并不完全理解发生了什么。所以我的问题是这样的:
有人知道实际发生了什么吗?是否有更好(更清晰)的方法来完成同样的事情?

修改:SSCCE:http://pastebin.com/VC1T7zGv

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class SSCCE extends JApplet {
    private boolean state;

    public void init() {
        super.init();
        getContentPane().add(setupSwitchPanel(), BorderLayout.NORTH);
        getContentPane().add(setupSimplePanel(), BorderLayout.CENTER);
    }

    private JPanel setupSwitchPanel() {
        JPanel switchPanel = new JPanel();
        switchPanel.add(new JButton(new AbstractAction("Switch panels (slow)") {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                switchComponents();
            }
        }));

        switchPanel.add(new JButton(new AbstractAction("Switch panels (fast)") {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                ((JPanel)getContentPane().getComponent(1)).removeAll();
                switchComponents();
            }
        }));
        return switchPanel;
    }

    private void switchComponents() {
        getContentPane().remove(1);
        if (state)
            getContentPane().add(setupSimplePanel(), BorderLayout.CENTER);
        else
            getContentPane().add(setupComplexPanel(), BorderLayout.CENTER);
        state = !state;
        getContentPane().validate();
    }

    private JPanel setupComplexPanel() {
        JPanel contents = new JPanel();
        contents.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        for (int x = 0; x<10; x++) {
            c.gridx = x;
            for (int y = 0; y<10; y++) {
                c.gridy = y;
                contents.add(new JLabel(x + ", " + y), c);
            }
        }
        return contents;
    }

    private JPanel setupSimplePanel() {
        JPanel contents = new JPanel();
        contents.add(new JLabel("Simple view"));
        return contents;
    }
}

3 个答案:

答案 0 :(得分:2)

  • add / remove已经看不到JScrollPane的内容,(确定您可以尝试拨打setViewportView(Component),但我不建议这样做)

  • 将父JPanel嵌套另一个JPanelJComponent s

  • 致电父亲JPanel#removeAll()

  • 向父亲JPanel添加新的JComponentJPanel

  • 之后,拨打父亲JPanel#revalidate()JPanel#repaint()

答案 1 :(得分:1)

替代策略:使用CardLayout

  

我宁愿不在记忆中保留所有不同的观点。

为什么呢?典型的存储器可以存储数百个具有数百个组件的卡。

懒洋洋地创建它们,GUI在典型的使用运行中可能只有20-40张卡片。当然,重新使用现有卡进行常见任务,只需更改内容即可。

答案 2 :(得分:0)

通常,调用具有许多子节点的组件的“removeAll”(例如考虑具有多行的GridBagLayout)可能非常慢,因为Swing会触发大量通知事件并调用多次同步部分( java.awt.Component.getTreeLock()的)。

一个非常有用的提示是关闭组件的可见性调用removeAll并再次打开它:

   mypanel.setVisible(false);
   mypanel.removeAll();  //<-- it can be very slow!!!
   mypanel.setVisible(true);

去除不可见的组分非常快。