2012-05-31 2 views
1

Я создаю апплет (j), где пользователь имеет доступ к нескольким различным представлениям, выбираемым из дерева. Апплет имеет основную область, в которой текущее представление отображается внутри прокрутки, заменяя все, что было там раньше. В большинстве случаев это отлично работает, но когда вид, который нужно заменить, имеет более сложный макет, так как в больших (~ 100 компонентов), не вложенных, удаление занимает несколько секунд! Создание большого вида - молниеносное, только удаление происходит медленно. Это заметно только в апплетах, запуск приложения в JFrame все еще так же быстро, как я ожидаю. Я использую GridBagLayout для представления.Удаление контейнера, который использует сложный макет

После нескольких экспериментов я обнаружил, что, если я заменю

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

с

view.removeAll(); 
contents.remove(view); 

тогда весь процесс очень быстро.

Я предполагаю, что причиной такого поведения является макет «магии» Java, и хотя у меня есть решение, оно не кажется правильным и, похоже, указывает, что я не совсем понимаю, что происходит. Поэтому мой вопрос (ы) таков:
Кто-нибудь знает, что на самом деле происходит? Есть ли лучший (более ясный) способ сделать то же самое?

Edit: 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

@AndrewThompson A CardLayout может работать, если я поместил представления в отдельные JScrollPanes, но я бы предпочел не хранить все разные виды в памяти. –

+0

Я решил попробовать, и это может сработать - я действительно ожидал получить такое же поведение. CardLayout вполне может быть самым идиоматическим решением. Я, вероятно, поеду с этим, но мне все еще интересно, почему удаление подкомпонентов ускоряет удаление родительского компонента. –

+0

1) Я ввел комментарии в качестве альтернативной стратегии. 2) Nice SSCCE +1 - я вставлял его в вопрос как редактирование. 3) Интригующее наблюдение, но я бы старался использовать лучший макет и перейти к новой проблеме. Надеюсь, вы получите решение. :) –

ответ

1

Альтернативные стратегии: использование a CardLayout.

Я бы предпочел не хранить все разные виды в памяти.

Почему? Типичная память может позволить хранить сотни карт с сотнями компонентов.

Создайте их лениво, и графический интерфейс может иметь только 20-40 карт при типичном использовании. Конечно, повторно использовать существующие карты для общих задач, просто измените контент.

+0

право может быть правильным способом ARAIK – mKorbel

2
  • делать не add/remove что-то к JScrollPane уже видно, (что вы можете попробовать позвонить setViewportView(Component), но я не предлагаю делать это)

  • положить отец JPanel вложен еще JPanel s или JComponent s

  • отец вызов JPanel#removeAll()

  • добавить новый JPanel s или JComponent s к отцу JPanel

  • после этого позвонить отцу JPanel#revalidate() и JPanel#repaint()

+0

Неплохо, я фактически не работаю с JScrollPane, а JPanel, который установлен как Viewport View. Я также отредактирую свой вопрос. –

+1

JViewport видна только прямоугольником от JScrollPana, не помещайте что-то в это, ваш вопрос не отвечает без публикации SSCCE – mKorbel

+0

Проблема, продемонстрированная в 70 строках Java: http://pastebin.com/VC1T7zGv –

0

В общем случае вызывать «removeAll» компонента со многими многими дочерними элементами (например, GridBagLayout со многими строками) может быть очень медленным, потому что Swing запускает множество уведомлений и вызывает несколько раз синхронизированных секций (java .awt.Component.getTreeLock()).

Очень полезный наконечник отключив видимость компонента перед тем вызова RemoveAll и включите его снова:

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

удаления compoents, которые не видны очень быстро.

Смежные вопросы