2015-04-28 277 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