我正在创建一个(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;
}
}
答案 0 :(得分:2)
add / remove
已经看不到JScrollPane
的内容,(确定您可以尝试拨打setViewportView(Component),但我不建议这样做)
将父JPanel
嵌套另一个JPanel
或JComponent
s
致电父亲JPanel#removeAll()
向父亲JPanel
添加新的JComponent
或JPanel
之后,拨打父亲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);
去除不可见的组分非常快。