2017-04-15 92 views
1

我花了一段时间从我的大型程序创建sscce,我希望它足够小!ScrollPane扩展组件时添加

我有一个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; 
    } 
} 

任何帮助或建议将非常感激 - 我是自学成才,正在努力争取公平的一点!

感谢

+0

调用'setPreferredSize'将阻止组件计算它自己的首选大小 – MadProgrammer

+0

您的期望是什么? – MadProgrammer

+0

我认为我通过调用getPreferredSize()来检索它的首选大小的组件计算。设置这个值似乎是多余的 - 但毫无疑问,我误解了发生了什么 – NickW

回答

1

我想我的问题是,为什么越来越首选大小,然后设置首选大小有差别?

如果我们通过代码挖下去,你会发现...

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); 
} 

这将返回用户设置首选大小,如果它被设置,在计算自己的。

当然,我正在分配一个已经存在的值?

但你打电话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代替。计算组件的大小是没有其他人的责任,但组件的大小本身,但组件本身

+0

哇的要求,这看起来不错。这里真的很早,所以我会在睡觉之后继续工作 - 我认为我不能做到(或者你的时间)正义,但是这看起来很棒。谢谢 – NickW

2

我太累了,写一个正确的答案,但我一眼通过这个和我看到的第一个问题之一是setSize(width,height)构造为Example内。最好在JFrame上拨打pack(),让它自动调整一切。但是,我认为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); 
} 

我用setResizeWeight实现拆分窗格比例和设定的窗格,而不是窗口的首选大小。

这是非常相似的,你喜欢的结果,但它是一个小更合适的。这可能是更有经验的Swing用户一个知道这里有更好的方式使用JScrollPane其中例如不涉及明确的setPreferredSize

+0

我可以欣赏疲劳,现在是凌晨4:30,所以谢谢! (我可能会在明天早上深入研究它)。 我的第一反应是,我读过pack是做到这一点的方式 - 但我很谨慎,我的程序有额外的面板(和一个垂直分割面,在这个sscce的左边接壤,它包含一个很好对齐的表单),而且我缺乏这种重新设计布局的知识。但我明天会详细研究它。再次感谢 – NickW

+1

'JScrollPane'将使用组件的'preferredSize'(因为它自己),或者如果组件实现'Scrollable'接口,它将使用'Scrollable#getPreferredScrollableViewportSize' – MadProgrammer

+0

我想我的问题是为什么获得preferredSize,那么设置preferredSize会有所作为?当然,我分配的价值已经到位了?我只是偶然发现了解决方案,因为我试图更改preferredSize维度返回的高度变量,以便设置最大高度(这不起作用) – NickW