【问题标题】:SpringLayout problem/challengeSpringLayout问题/挑战
【发布时间】:2010-12-22 05:10:54
【问题描述】:

SpringLayout 号称非常强大。我尝试使用 SpringLayout 实现我认为相当简单的布局,但我失败了。

减少到最低限度,我希望在我的 JFrame 上并排放置 4 个 JButton:

*=====================*
| +--+ +--+ +--+ +--+ |
| |b1| |b2| |b3| |b4| |
| +--+ +--+ +--+ +--+ |
*=====================*

我希望所有 4 个都具有相同的大小,而不考虑不同的文本。

我希望最外面的那些(b1 和 b4)与容器的边界保持 5 px 的恒定水平距离,并且按钮的南北边有 5 px 的边界,它们都是相同的高度。

我希望按钮之间的间距也为 5 px。

到目前为止,很容易。我有更多的限制:

  • 当框架变宽(用户/鼠标)时,我希望按钮(b1/b2、b2/b3、b3/b4)之间的间隙变宽,但不是按钮。

  • 如果框架变小,我希望按钮之间的间隙缩小到 1 或 0,然后其他东西必须让位。

  • 我希望框架上的 pack() 能够为我提供一个大小合适的窗口,按钮的默认间距为 5 像素,周围的边框为 5 像素。

我编写了以下相当简单的代码,结果很糟糕。间隙不会缩小,扩展只发生在最右边的按钮 (b4)。

现在我有自定义按钮来统一调整大小,我可以使用 GridBagLayout 相当轻松地满足这些要求,使用 MigLayout 可能更容易。这不是我要找的答案。具体来说,我的问题是:

能否使用 SpringLayout 使此布局正常工作?怎么样?

布局甚至忽略了我的按钮getMaximumSize()。是我做错了什么还是 SpringLayout 出了问题?

非常感谢。

public class SpringLayoutTest extends JFrame {

public SpringLayoutTest() {
  setLocation(100,100);
  setSize(400, 300);
  Container cp = getContentPane();
  SpringLayout layout = new SpringLayout();
  cp.setLayout(layout);

  SiblingButton b1, b2, b3, b4;
  cp.add(b1 = new SiblingButton("..."));
  cp.add(b2 = new SiblingButton("iii"));
  cp.add(b3 = new SiblingButton("xxx"));
  cp.add(b4 = new SiblingButton("WWW"));

  layout.putConstraint(NORTH, b1, 5, NORTH, cp);
  layout.putConstraint(SOUTH, b1, Spring.minus(Spring.constant(5)), SOUTH, cp);
  layout.putConstraint(NORTH, b2, 5, NORTH, cp);
  layout.putConstraint(SOUTH, b2, Spring.minus(Spring.constant(5)), SOUTH, cp);
  layout.putConstraint(NORTH, b3, 5, NORTH, cp);
  layout.putConstraint(SOUTH, b3, Spring.minus(Spring.constant(5)), SOUTH, cp);
  layout.putConstraint(NORTH, b4, 5, NORTH, cp);
  layout.putConstraint(SOUTH, b4, Spring.minus(Spring.constant(5)), SOUTH, cp);

  layout.putConstraint(WEST, b1, 5, WEST, cp);
  layout.putConstraint(WEST, b2, Spring.constant(1, 5, Integer.MAX_VALUE), EAST, b1);
  layout.putConstraint(WEST, b3, Spring.constant(1, 5, Integer.MAX_VALUE), EAST, b2);
  layout.putConstraint(WEST, b4, Spring.constant(1, 5, Integer.MAX_VALUE), EAST, b3);

  layout.putConstraint(EAST, b4, Spring.minus(Spring.constant(5)), EAST, cp);

  layout.putConstraint(WEST, cp, Spring.minus(Spring.constant(5)), WEST, b1);
}

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

SiblingButton 是一个非常简单的实现。请忽略它的设计缺陷,这只是为了演示目的。

class SiblingButton extends JButton {

static ArrayList<SiblingButton> siblings = new ArrayList<SiblingButton>();

public SiblingButton(String text) {
  super(text);
  siblings.add(this);
}

public Dimension getMaximumSize() {
  return getPreferredSize();
}

public Dimension getMinimumSize() {
   return getPreferredSize();
}

public Dimension getPreferredSize() {
  Dimension mx = new Dimension(0, 0);
  for (SiblingButton sb : siblings) {
     mx = new Dimension(Math.max(mx.width, sb.originalPreferredSize().width), 
           Math.max(mx.height, sb.originalPreferredSize().height));
  }
  return mx;
}

Dimension originalPreferredSize() {
  return super.getPreferredSize();
}

}

更新/结论

现在已经 24 小时了,反响非常平淡。唯一的响应(感谢 Camickr!)甚至没有尝试触摸 SpringLayout。我不认为这不是在 SO 社区而是在 SpringLayout 的实用程序上反映不好!

我的印象是 SpringLayout 是布局管理器的红发继子,在某些方面很有用,但很少使用,没有人有使用它的经验,也没有人费心向 Sun 报告错误。

对我来说,事实证明 GroupLayout 可以满足我的所有需求,并且允许我通过合理的编码量来完成我想要的。 GridBagLayout 的一个可喜变化,我从一开始就很清楚实现预期布局所需的步骤,我只需要坐下来编写代码。

对于任何关心的人来说,GroupLayout 的这些特点使它对我如此有用:

  • 布局在水平和垂直方向上或多或少是分开进行的。极大的灵活性和更简单的代码;
  • 可以嵌套网格,而无需引入容器来保存布局;
  • 可以插入具有指定约束的间隙;
  • 可以形成具有共享尺寸规格的任意组件组,即所有组件的尺寸与组中最大的组件相同;和
  • 可以更改组件的大小(例如,maximumSize = preferredSize),而无需对组件进行子类化。

【问题讨论】:

  • 不是答案,但是您检查过 TableLayout 吗? java.sun.com/products/jfc/tsc/articles/tablelayout
  • TableLayout 会比 GBL 甚至 MigL 更简单地满足我声明的要求 - 谢谢!我想使用 SL 的原因是 GUI 实际上还有更多功能,并且其他行中的组件将独立于这些按钮按列布局,我不想推测它们会跨越多少列。当您想要在同一布局中使用不同的列宽时,这会迅速减少您的选择。我最终可能会使用嵌套容器。
  • 哦,我想要 SpringLayout 的另一个原因:它是唯一允许我在不继承我的按钮或直接摆弄它们的尺寸设置的情况下强制所有它们具有相同的 min/pref/ 的布局最大尺寸 - 通过那个时髦的弹簧算法。如果它像宣传的那样工作,那将是相当酷的。我的示例使用子类按钮只是为了简化我的 spring-twiddling 代码。

标签: java swing layout


【解决方案1】:

您可以使用 BoxLayout:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class BoxExample extends JFrame
{
    public BoxExample()
    {
        Box box = Box.createHorizontalBox();
        box.setBorder( new EmptyBorder(5, 5, 5, 5) );
        Dimension size = new Dimension(100, 25);

        box.add( createButton("Button1", size) );
        box.add( createStrut() );
        box.add( createButton("Button2", size) );
        box.add( createStrut() );
        box.add( createButton("Button3", size) );
        box.add( createStrut() );
        box.add( createButton("Button4", size) );

        add( box );
    }

    private JButton createButton(String text, Dimension size)
    {
        JButton button = new JButton(text);
        button.setPreferredSize( size );
        button.setMinimumSize( size );
        button.setMaximumSize( size );
        return button;
    }

    private Component createStrut()
    {
        JComponent component = (JComponent)Box.createHorizontalStrut(5);
        component.setMinimumSize(new Dimension(0, 0));
        component.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
        return component;
    }

    public static void main(String[] args)
    {
        BoxExample frame = new BoxExample();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

【讨论】:

  • 不回答我的问题,但 +1 表示努力和一个不错的选择!
【解决方案2】:

您需要设置容器的约束(框架的内容窗格),更准确地说是它的东边和南边的约束。 阅读这方面的教程:
http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html
SpringDemo3说明一切

【讨论】:

    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 2019-07-17
    • 2015-05-02
    • 2021-11-06
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多