添加组件时ScrollPane扩展

时间:2017-04-15 02:40:05

标签: java swing

我花了一段时间从我的大型程序中创建一个sscce,我希望它足够小!

我的JSplitPane上面有一张桌子,下面是JPanel。

底部面板包含较小的JPanel或条目'。随着条目数量的增加,底部的SplitPane占用顶部窗格的空间。

Dimension dim = getPreferredSize();        
setPreferredSize(dim);

在第一堂课中,取消注释此代码可以解决问题,但我不知道为什么。如果有人可以提供帮助,我想了解如何更好地处理调整大小问题? (我还要处理水平扩展的文本区域,这是一些限制可能看起来有些奇怪的原因之一)

这是下面的面板:

package example;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;

public class BottomPanel extends JPanel{
    private JLabel summary = new JLabel();
    private EntryPanel entryPanel = new EntryPanel(); 

    public BottomPanel() {
        //Dimension dim = getPreferredSize();
        //setPreferredSize(dim);
        setLayout(new GridBagLayout());
        entryPanel.setBorder(BorderFactory.createLineBorder(Color.RED));
        setComponents();
    }

    private void setComponents() {
        Border test = BorderFactory.createLineBorder(Color.BLUE);
        JScrollPane jsp = new JScrollPane(entryPanel);
        JPanel dummy1 = new JPanel();
        JPanel dummy2 = new JPanel();
        JPanel dummy3 = new JPanel();
        dummy1.setBorder(test);
        dummy2.setBorder(test);
        dummy3.setBorder(test);

        int row = 0;
        add(dummy1, new GBC(0,row).setWeight(0,0));
        // new row
        row++;
        add(summary, new GBC(1,row).setAnchor(GBC.LINE_START));   
        // new row
        row++;
        add(jsp, new GBC(1,row).setWeight(50,70).setFill(GBC.BOTH));
        // new row
        row++;
        add(dummy2, new GBC(2,row).setWeight(0,0));
    }

    private class EntryPanel extends JPanel{
        private List<JPanel> entries = new ArrayList<>();
        private int row = 0;

        private EntryPanel(){
            setLayout(new GridBagLayout());
            for(int x = 0; x < 20; x++)
                createEntryItem("TEST", "test text");
        }

        private void createEntryItem(String s, String text){
            Border test = BorderFactory.createLineBorder(Color.GREEN);
            JPanel entryItem = new JPanel();
            entryItem.setBorder(test);
            entryItem.setLayout(new GridBagLayout());
            JLabel title = new JLabel(s);
            JTextArea details = new JTextArea(text);  

            entryItem.add(title, new GBC(0,0).setAnchor(GBC.LINE_START));
            entryItem.add(details, new GBC(0,1).setAnchor(GBC.LINE_START));
            entryItem.add(new JPanel(), new GBC(1,0).setWeight(100,0));
            entries.add(entryItem);
            displayEntry(entryItem);
        }

        private void displayEntry(JPanel entry){
            JPanel dummy = new JPanel();
            add(entry, new                         GBC(0,row).setAnchor(GBC.LINE_START).setFill(GBC.HORIZONTAL));
            add(dummy, new GBC(1,row).setWeight(100, 0));
            row++;
        }
    }
}

和包含框架和面板:

package example;
import java.awt.*;
import javax.swing.*;

public class Example extends JFrame{
    private GraphicsDevice gd =     GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();     
    private int width = (int)((gd.getDisplayMode().getWidth())*0.5);
    private int height = (int)((gd.getDisplayMode().getHeight())*0.75);
    private JPanel mainPanel = new JPanel();
    private JSplitPane sp;
    private JTable table = new JTable();
    private BottomPanel bp = new BottomPanel();

    public Example () {
        setSize(width,height);
        setLayout(new BorderLayout());
        sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,new JScrollPane(table), bp);
        add(sp);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                Example ex = new Example();
            }
        });
    } 
}

和GridBagHelper:

package example;
import java.awt.GridBagConstraints;

public class GBC extends GridBagConstraints{  
   public GBC(int gridx, int gridy){
      this.gridx = gridx;
      this.gridy = gridy;
   }

   public GBC setAnchor(int anchor){
      this.anchor = anchor;
      return this;
   }

   public GBC setFill(int fill){
      this.fill = fill;
      return this;
   }

   public GBC setWeight(double weightx, double weighty){
      this.weightx = weightx;
      this.weighty = weighty;
      return this;
   }
}

任何帮助或建议都会非常感激 - 我自学成才,并且正在苦苦挣扎!

由于

2 个答案:

答案 0 :(得分:2)

我太累了,无法写出正确的答案,但我正在浏览这个,我看到的第一个问题之一是setSize(width,height) Example的构造函数。最好在pack()上调用JFrame,然后让它自动调整大小。

我认为pack JScrollPane可能有点不可预测pack。从记忆中,我已经做了一些奇怪的事情,比如将滚动窗格折叠到最小尺寸。

在代码示例中使用BottomPanel似乎试图围绕public Example () { // setSize(width,height); // setLayout(new BorderLayout()); sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,new JScrollPane(table), bp); sp.setResizeWeight(2.0 / 3.0); sp.setPreferredSize(width, height); setContentPane(sp); // add(sp); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); setVisible(true); } 中面板的总和来调整大小。 (总和会高于我的屏幕分辨率,所以我无法确定具体行为是什么。它会在屏幕高度处限制窗口的高度。)

更优雅的方式来做你想做的事情是这样的:

JScrollPane

我使用setResizeWeight来实现拆分窗格比例,并设置窗格的首选大小而不是窗口。

这与您喜欢的结果非常相似,但它更合适一些。可能是这里经验丰富的Swing用户之一知道更好的方式来使用setPreferredSize,例如不涉及明确的{{1}}。

答案 1 :(得分:1)

  

我想我的问题是为什么获取preferredSize,然后设置preferredSize会有所不同?

如果我们深入挖掘代码,您就会发现......

public void setPreferredSize(Dimension preferredSize) {
    Dimension old;
    // If the preferred size was set, use it as the old value, otherwise
    // use null to indicate we didn't previously have a set preferred
    // size.
    if (prefSizeSet) {
        old = this.prefSize;
    }
    else {
        old = null;
    }
    this.prefSize = preferredSize;
    prefSizeSet = (preferredSize != null);
    firePropertyChange("preferredSize", old, preferredSize);
}

您可以查看getPreferredSize的工作原理......

public boolean isPreferredSizeSet() {
    return prefSizeSet;
}


/**
 * Gets the preferred size of this component.
 * @return a dimension object indicating this component's preferred size
 * @see #getMinimumSize
 * @see LayoutManager
 */
public Dimension getPreferredSize() {
    return preferredSize();
}


/**
 * @deprecated As of JDK version 1.1,
 * replaced by <code>getPreferredSize()</code>.
 */
@Deprecated
public Dimension preferredSize() {
    /* Avoid grabbing the lock if a reasonable cached size value
     * is available.
     */
    Dimension dim = prefSize;
    if (dim == null || !(isPreferredSizeSet() || isValid())) {
        synchronized (getTreeLock()) {
            prefSize = (peer != null) ?
                peer.getPreferredSize() :
                getMinimumSize();
            dim = prefSize;
        }
    }
    return new Dimension(dim);
}

这将返回用户设置preferredSize(如果已设置),而不是计算自己的。

  

我当然要分配一个已经存在的值吗?

但是在将任何组件添加到容器

之前,请调用setPreferredSize

如果您将代码更改为......

Dimension dim = getPreferredSize();
System.out.println(dim);
setPreferredSize(dim);

它会打印出像java.awt.Dimension[width=10,height=10]这样的东西,所以,是的,小......

但是,如果你使用类似的东西......

public BottomPanel() {
    setLayout(new GridBagLayout());
    entryPanel.setBorder(BorderFactory.createLineBorder(Color.RED));
    setComponents();
    Dimension dim = getPreferredSize();
    System.out.println(dim);
    setPreferredSize(dim);
}

打印出java.awt.Dimension[width=105,height=710]

故事的基本道德是,除非你有非常非常好的理由,否则不要打电话给setPreferred/Minimum/MaximumSize,即便如此,也要考虑覆盖getPreferredSize。计算组件的大小并不是其他人的责任,而是组件本身