1

我正在创建一个(j)小程序,用户可以访问从树中选择的几个不同视图。小程序有一个主要区域,当前视图显示在滚动窗格内,替换之前的任何内容。大多数情况下,这可以正常工作,但是当要替换的视图具有更复杂的布局时,例如大型(约 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;
    }
}
4

3 回答 3

2
  • 不要add / removeJScrollPane已经可见的东西,(确保您可以尝试调用setViewportView(Component),但我不建议这样做)

  • 把父亲JPanel嵌套在另一个JPanels 或JComponents

  • 打电话给父亲JPanel#removeAll()

  • 给父亲 添加一个新JPanel的 s 或sJComponentJPanel

  • 之后,给父亲打个电话,JPanel#revalidate()然后JPanel#repaint()

于 2012-05-31T13:33:51.673 回答
1

替代策略:使用CardLayout.

我宁愿不要将所有不同的视图都保存在内存中。

为什么?典型的内存可以允许存储数百张带有数百个组件的卡片。

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

于 2012-06-01T09:24:28.160 回答
0

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

一个非常有用的技巧是在调用 removeAll之前关闭组件的可见性并再次打开它:

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

移除不可见的组件非常快。

于 2014-09-23T09:26:40.590 回答