2014-11-27 3 views
0

В проекте у меня есть JFrame A, начинающийся с JDialog B, который сам запускает JDialog C (все с помощью кнопок). Однако, следуя одной из этих процедур:Странное/различное поведение при обновлении JDialog

  • Я нажимаю на A, чтобы начать B; или
  • я нажимаю на А, чтобы начать B, затем B, чтобы начать C, затем нажмите на кнопку отмены C, в

, что отображается в B не совпадает (вторая процедура дает странные уродливые вещи).

Я не понимаю, почему это возможно, поскольку в обоих случаях вызывается мой метод updateAll.

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

Поскольку я не знаю, откуда это взялось, вот полный код моей (тестовой) программы. Соберитесь.

'A' Рама

public class MyFrame extends JFrame { 
    private static final long serialVersionUID = 7073064926636937881L; 
    public MyFrame() { 
     this.setSize(200, 300); 
     JButton button = new JButton("Click me"); 
     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       new MyDialog1().setVisible(true); 
      } 
     }); 
     this.getContentPane().add(button); 
    } 

    public static void main(String args[]) { 
     new MyFrame().setVisible(true); 
    } 
} 

'B' Dialog

public class MyDialog1 extends JDialog { 
     private static final long serialVersionUID = 9181006217120036637L; 
     private JScrollPane scrollPane; 
     public String text = "aaaaaaaaaaa\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\naaaaaaaa\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\naaaaaaaa"; 

    public MyDialog1() { 
     this.setVisible(false); 
     this.setSize(800, 600); 

     this.initComponent(); 
     this.updateAll(); 
    } 

    private void initComponent() { 
     this.getContentPane().setLayout(new GridBagLayout()); 
     GridBagConstraints c = new GridBagConstraints(); 

     this.scrollPane = new JScrollPane(); 

     c.gridx = 0; 
     c.gridy = 0; 
     this.getContentPane().add(this.scrollPane, c); 

     c.gridx = 0; 
     c.gridy = 1; 
     JButton b = new JButton("Supposedly edit stuff"); 
     final MyDialog1 caller = this; 
     b.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       new MyDialog2(caller).setVisible(true); 
      } 
     }); 
     this.getContentPane().add(b, c); 

     c.gridx = 1; 
     c.gridy = 1; 
     b = new JButton("Leave"); 
     b.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       setVisible(false); 
      } 
     }); 
     this.getContentPane().add(b, c); 
    } 

    public void updateAll() { 
     JPanel mainPanel = new JPanel(); 
     for (int i = 0 ; i < 5 ; i++) { 
      JPanel subPanel = new JPanel(); 
      JTextArea t = new JTextArea(this.text); 
      t.setSize(60, 30); 
      t.setVisible(true);// Useful ? What about setSize ? 
      subPanel.add(t); 
      mainPanel.add(subPanel); 
     } 
     this.scrollPane.setSize(150, 150); // FIXME When in initComponent, doesn't do anything, and when in updateAll, behavior is inconsistent 
     this.scrollPane.setViewportView(mainPanel); // Replacing previous JPanel 

    } 
} 

'C' Dialog

public class MyDialog2 extends JDialog { 
    private static final long serialVersionUID = 5676648412234106581L; 
    private MyDialog1 caller; 

    public MyDialog2(MyDialog1 c) { 
     this.setSize(100, 150); 
     this.caller = c; 
     JButton cancelButton = new JButton("Cancel"); 
     cancelButton.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       setVisible(false); 
       caller.text += "\nbbbbbbbbbbbbb\nbbbbbbbbbbbbbbbbbb\nbbbbbbbbbbb\nbbbbbbbbbbbbbb\ncccccccccccccccccccccccccccccccccccccccccccc\ncccccccccc"; 
       caller.updateAll(); 
      } 
     }); 
     this.getContentPane().add(cancelButton); 
    } 
} 

Спасибо за вашу помощь.

+1

Это вопрос макета (использование 'setSize' в частности), но я не совсем уверен, что вы намерены предложить другим способом. Возможно, опубликуйте рисунок (который может быть относительно грубым, например ... MSPaint), и опишите, как вы хотите корректно вести MyDialog1. – Radiodef

ответ

1

Я предлагаю использовать

c.gridx = 0; 
c.gridy = 0; 
c.fill = GridBagConstraints.BOTH; // make the component fill its display area entirely 
c.ipady = 150; //height 
c.anchor = GridBagConstraints.FIRST_LINE_START; // component start from the left top corner 
this.getContentPane().add(this.scrollPane, c); 

для определения ограничений JScrollPane.

В additition, добавьте Validate() и перекрасить() после того, как модифицирующих элементов

this.scrollPane.setViewportView(mainPanel); // Replacing previous JPanel 
this.validate(); 
this.repaint(); 
+0

Использование только проверки и перерисовки делает обе процедуры одинаковыми. Я проверю остальные поля. – LogicalKip

0

Легкий ответ, который игнорирует хорошую практику:

Заменить это:

this.scrollPane.setSize(150, 150); 

с этим:

this.scrollPane.setMinimumSize(new Dimension(150, 150)); 

Вызов setSize на компоненте, который находится в контейнере с компоновкой, обычно ничего не делает; в лучшем случае он установит размер до следующего проверки контейнера, поскольку размер будет перезаписан менеджером компоновки. Однако установка минимального размера (или preferredSize или maximumSize) устанавливает постоянное свойство, которое соблюдается (большинством) менеджеров макетов.

Почему setMinimumSize внести изменения? Поскольку вы не установили никаких объектов weightx или weighty на любом из ваших GridBagConstraints, то для GridBagLayout недостаточно места для отображения вашего JScrollPane в нужном размере. Когда GridBagLayout определяет, что не хватает места для отображения всего на требуемый размер, макет «стреляет» и заставляет все вернуться к минимальному размеру.

В первый раз, когда вы показываете диалог B, вы видите, что JScrollPane имеет минимальный размер (то есть достаточно большой, чтобы отображать полосы прокрутки и границу видового экрана). После отмены диалога C вступает в силу setSize(150, 150), но вполне вероятно, что любые последующие изменения для любого потомка GridBagLayout приведут к тому, что (150, 150) будут перезаписаны с минимальным размером JScrollPane.

Более сложный ответ, который является хорошей практикой:

Удалить все вызовы SetSize в каждом классе. Обычно вы не должны устанавливать явные размеры вообще, но если вы должны это сделать, используйте setPreferredSize.

компоненты, которые сделаны, чтобы расти и сокращаться, как JScrollPanes, должны быть назначены положительные weightx и weighty значения в их соответствующих GridBagConstraints, наряду с fill быть установлен в GridBagConstraints.BOTH, как pcej предложил.