2015-04-28 176 views
0

我有一個JScrollPane,它包含一個JTextArea。當窗口最小化然後恢復時,JScrollPane會自行崩潰。請注意,只有在JTextArea中的文本超出JTextArea的給定寬度和/或高度(即出現水平或垂直滾動​​條)時纔會發生擠壓。JScrollPane窗口縮小縮小最小化

這個問題在這裏:JScrollpane loses size after minimize帶來了同樣的問題,但這個問題從來沒有解決過,除了向JScrollPane添加weightx,weighty和fill約束外,我已經開始了。

下面是一個演示問題的簡單示例。在窗口最小化和恢復後,如何讓JScrollPane保持其大小?

import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.util.List; 
import java.util.concurrent.ExecutionException; 
import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import javax.swing.border.EtchedBorder; 

public class GUITest implements ActionListener { 

    JButton button = new JButton("Button"); 
    JTextArea textArea = new JTextArea(); 
    SwingWorker<String, String> mySwingWorker = null; 

    public static void main(String[] args) throws IOException { 
     GUITest tracer = new GUITest(); 
    } 

    public GUITest() throws IOException { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        createAndShowGUI(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public void createAndShowGUI() throws IOException { 
     JFrame frame = new JFrame("GUI Test"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setResizable(false); 
     JPanel mainPanel = new JPanel(); 
     mainPanel.setLayout(new GridBagLayout()); 
     GridBagConstraints mainPanelConstraints = new GridBagConstraints(); 
     mainPanelConstraints.gridx = 0; 
     mainPanelConstraints.gridy = 0; 
     mainPanelConstraints.fill = GridBagConstraints.BOTH; 
     button.addActionListener(this); 
     mainPanel.add(button, mainPanelConstraints); 
     mainPanelConstraints.gridx = 0; 
     mainPanelConstraints.gridy = 1; 
     mainPanelConstraints.fill = GridBagConstraints.BOTH; 
     mainPanel.add(buildTextAreaPanel(), mainPanelConstraints); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private JPanel buildTextAreaPanel() { 
     JPanel textAreaPanel = new JPanel(); 
     textAreaPanel.setLayout(new GridBagLayout()); 
     GridBagConstraints textAreaPanelConstraints = new GridBagConstraints(); 
     textAreaPanel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(EtchedBorder.RAISED), "TextArea")); 
     textArea.setColumns(30); 
     textArea.setRows(15); 
     textArea.setEditable(false); 
     JScrollPane textAreaScrollPane = new JScrollPane(textArea); 
     textAreaScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
     textAreaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 
     textAreaPanelConstraints.gridx = 0; 
     textAreaPanelConstraints.gridy = 0; 
     textAreaPanelConstraints.weightx = 1.0; 
     textAreaPanelConstraints.weighty = 1.0; 
     textAreaPanelConstraints.fill = GridBagConstraints.BOTH; 
     textAreaPanel.add(textAreaScrollPane, textAreaPanelConstraints); 
     return textAreaPanel; 
    } 

    public void actionPerformed(ActionEvent e) { 
     if (e.getSource() == button) { 
      mySwingWorker = new MySwingWorker(); 
      mySwingWorker.execute(); 
     } 
    } 

    private class MySwingWorker extends SwingWorker<String, String> { 
     public String doInBackground() throws Exception { 
      for (int i = 0; i < textArea.getRows(); i++) { 
       publish("text\n"); 
      } 
      publish("more text\n"); 

      return "Done."; 
     } 
     public void process(List<String> chunks) { 
      for (String msg : chunks) { 
       textArea.append(msg); 
      } 
     } 
     public void done() { 
      try { 
       String msg = get(); 
       textArea.append("\n" + msg); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (ExecutionException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

} 

回答

1

您需要在兩種佈局中設置weightx和weighty。在createAndShowGui中,在添加文本區域面板之前,將mainPanelConstraints.weightx和mainPanelConstraints.weighty設置爲1。

+0

我可以看到這會產生所需的行爲,但我不明白爲什麼修改容器的權重值會影響其子組件的大小行爲。你可以解釋嗎? – FalconRunner11

+0

編輯上述評論:由「子組件」我其實是指「孫子組件」。 textAreaScrollPane提供了錯誤的行爲,駐留在textAreaPanel中,然後textAreaPanel駐留在mainPanel中。那麼,如何改變mainPanel的佈局屬性對textAreaScrollPane有直接的影響? – FalconRunner11

+0

weightx和weighty約束決定組件是否展開以填充其父項。如果文本區域面板拉伸以填充mainPanel,則無關緊要,除非mainPanel自身伸展以填充窗口。 – VGR

0

設置父容器(內容窗格)的佈局爲FlowLayout

... 
frame.getContentPane().setLayout(new FlowLayout()); 
frame.getContentPane().add(mainPanel); 
... 
+0

該解決方案似乎正在工作,但我不明白爲什麼在這種情況下更改JFrame內容窗格的佈局會影響組件下方几層的行爲。你能解釋一下這裏發生了什麼嗎? – FalconRunner11

0

我通過刪除所有GridBagLayouts並用BorderLayouts替換它們解決了這個問題的收縮在該特定的代碼示例。我不知道爲什麼JScrollPane會以您在使用GridBagLayout時發現的方式做出反應。

我感覺真的很不舒服從類的構造函數啓動Event Dispatch線程。我將SwingUtilities的invokeLater移入了主要方法。

無論如何,這是代碼。

package com.ggl.testing; 

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.util.List; 
import java.util.concurrent.ExecutionException; 

import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import javax.swing.border.EtchedBorder; 

public class JScrollPaneTest implements ActionListener { 

    JButton button = new JButton("Button"); 
    JTextArea textArea = new JTextArea(); 
    SwingWorker<String, String> mySwingWorker = null; 

    public static void main(String[] args) throws IOException { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        new JScrollPaneTest().createAndShowGUI(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

    } 

    public JScrollPaneTest() throws IOException { 

    } 

    public void createAndShowGUI() throws IOException { 
     JFrame frame = new JFrame("JScrollPane Test"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setResizable(true); 

     JPanel mainPanel = new JPanel(); 
     mainPanel.setLayout(new BorderLayout()); 
     mainPanel.add(button, BorderLayout.NORTH); 
     mainPanel.add(buildTextAreaPanel(), BorderLayout.CENTER); 

     button.addActionListener(this); 

     frame.add(mainPanel, BorderLayout.CENTER); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private JPanel buildTextAreaPanel() { 
     JPanel textAreaPanel = new JPanel(); 
     textAreaPanel.setLayout(new BorderLayout()); 
     textAreaPanel.setBorder(BorderFactory.createTitledBorder(
       new EtchedBorder(EtchedBorder.RAISED), "TextArea")); 

     textArea.setColumns(30); 
     textArea.setRows(15); 
     textArea.setEditable(false); 

     JScrollPane textAreaScrollPane = new JScrollPane(textArea); 

     textAreaPanel.add(textAreaScrollPane, BorderLayout.CENTER); 
     return textAreaPanel; 
    } 

    public void actionPerformed(ActionEvent e) { 
     if (e.getSource() == button) { 
      mySwingWorker = new MySwingWorker(); 
      mySwingWorker.execute(); 
     } 
    } 

    private class MySwingWorker extends SwingWorker<String, String> { 
     public String doInBackground() throws Exception { 
      for (int i = 0; i < textArea.getRows(); i++) { 
       publish("text\n"); 
      } 
      publish("more text\n"); 

      return "Done."; 
     } 

     public void process(List<String> chunks) { 
      for (String msg : chunks) { 
       textArea.append(msg); 
      } 
     } 

     public void done() { 
      try { 
       String msg = get(); 
       textArea.append("\n" + msg); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (ExecutionException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

} 
+0

感謝您提供有關將EDT開始移至主要方法的提示。在解釋了你的版本的例子之後,我發現只需要將mainPanel的佈局從GridBagLayout更改爲BorderLayout。 textAreaPanel(其中包含侵權JScrollPane)可以保持設置爲GridBagLayout,並達到所需的行爲。這引發了我對這個問題的其他兩個工作答案的相同問題:爲什麼更改組件的佈局配置會影響其子組件的行爲,但會影響以下多層的組件? – FalconRunner11

+0

@ FalconRunner11:除了甲骨文維護Swing回答你的問題的人之外,任何人都很難。我發現,通過將我的Swing組件放入主JPanel並將該JPanel放入JFrame中,可以防止出現很多問題。通常,爲了防止出現一組不同的問題,我爲GridBagLayout中的每個Swing組件創建了一個新的GridBagConstraints。 –

+0

我認爲VGR的迴應上面提供了一個足夠好的解釋。 textAreaPanel在添加到mainPanel時應該具有添加的weightx和weighty約束,以便處理其內部可能發生的任何大小調整。 – FalconRunner11