如何使用SpringLayout垂直排列组件
How to use SpringLayout to arrange components vertically
对于 SpringLayout,我显然有一些不理解的地方。我正在尝试创建一个 class,它是 JPanel 的扩展,它允许我添加组件并让它们垂直显示,宽度相同。
我的 JPanel 扩展会将其 LayoutManager 设置为使用 SpringLayout,每次添加组件时,它都会放入 SpringLayout 约束以将其附加到第一个组件的面板,然后将每个组件附加到前一个组件一.
首先,这是一个使用 SpringLayout 的 Oracle 编写的示例,我将其更改为垂直而不是水平放置组件:
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import javax.swing.SpringLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import java.awt.Container;
public class SpringDemo3
{
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI()
{
// Create and set up the window.
JFrame frame = new JFrame("SpringDemo3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Container contentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
// Create and add the components.
JLabel label = new JLabel("Label: ");
JTextField textField = new JTextField("Text field", 15);
contentPane.add(label);
contentPane.add(textField);
// Adjust constraints for the label so it's at (5,5).
layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.NORTH, contentPane);
// Adjust constraints for the text field so it's at
// (<label's right edge> + 5, 5).
// layout.putConstraint(SpringLayout.WEST, textField, 5, SpringLayout.EAST, label);
// layout.putConstraint(SpringLayout.EAST, textField, 5, SpringLayout.EAST, contentPane);
layout.putConstraint(SpringLayout.NORTH, textField, 5, SpringLayout.SOUTH, label);
// Adjust constraints for the content pane: Its right
// edge should be 5 pixels beyond the text field's right
// edge, and its bottom edge should be 5 pixels beyond
// the bottom edge of the tallest component (which we'll
// assume is textField).
layout.putConstraint(SpringLayout.EAST, contentPane, 5, SpringLayout.EAST, textField);
layout.putConstraint(SpringLayout.SOUTH, contentPane, 5, SpringLayout.SOUTH, textField);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
根据我理解的SpringLayout的要求,我写了以下内容:
import java.awt.Component;
import java.awt.LayoutManager;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import static javax.swing.SpringLayout.NORTH;
import static javax.swing.SpringLayout.EAST;
import static javax.swing.SpringLayout.SOUTH;
import static javax.swing.SpringLayout.WEST;
public class OneWidthPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private int padding = 5;
SpringLayout springLayout = new SpringLayout();
public OneWidthPanel() { super(); setLayout(springLayout); }
public OneWidthPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); }
public OneWidthPanel(LayoutManager layout) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
public OneWidthPanel(LayoutManager l, boolean isDoubleBuffered) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
private ArrayList<Component> componentList = new ArrayList<>();
@Override
public Component add(Component comp)
{
super.add(comp);
componentList.add(comp);
int listSize = componentList.size();
String topConstraint;
Component northComponent;
if (listSize == 1)
{
topConstraint = NORTH;
northComponent = this;
}
else
{
topConstraint = SOUTH;
northComponent = componentList.get(listSize - 2);
}
springLayout.putConstraint(topConstraint, northComponent, padding, SpringLayout.NORTH, comp);
springLayout.putConstraint(WEST, this, padding, WEST, comp);
springLayout.putConstraint(EAST, this, padding, EAST, comp);
return comp;
}
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
springLayout.putConstraint(EAST, this, padding, EAST, lastComponent);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
}
}
这里有一个小程序来测试它:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import rcutil.layout.OneWidthPanel;
public class OneWidthPanelTester extends JFrame
{
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
OneWidthPanelTester tester = new OneWidthPanelTester();
tester.go();
}
public void go()
{
OneWidthPanel panel = new OneWidthPanel();
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
panel.add(button1);
panel.add(button2);
panel.add(rButton);
panel.finishedAdding();
add(panel, BorderLayout.WEST);
pack();
setVisible(true);
}
}
组件出现在面板顶部的彼此之上。我想设置每个组件的约束,正如我添加的那样,将每个组件的北端连接到前一个组件的南边,将它们按照添加的顺序垂直排列。我有 finishedAdding()
方法,这样我就可以结束最后一个组件与其容器的连接,如 https://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html 的“如何使用 SpringLayout”教程中所述,以及我复制的演示程序中所做的.
我不明白为什么我的组件相互重叠,但(两个)演示组件垂直相邻。我是否能够满足我最初的愿望,即让垂直组件在面板中拉伸为相同大小?
你需要改变
springLayout.putConstraint(topConstraint, comp, padding, SpringLayout.NORTH, northComponent);
至
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent);
这是我最终得出的结论:
import static javax.swing.SpringLayout.EAST;
import static javax.swing.SpringLayout.NORTH;
import static javax.swing.SpringLayout.SOUTH;
import static javax.swing.SpringLayout.WEST;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.util.ArrayList;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
public class OneWidthPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private int padding = 5;
SpringLayout springLayout = new SpringLayout();
BoxLayout boxLayout = new BoxLayout(this, BoxLayout.PAGE_AXIS);
public OneWidthPanel()
{
super();
setLayout(springLayout);
}
public OneWidthPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); }
public OneWidthPanel(LayoutManager layout) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
public OneWidthPanel(LayoutManager l, boolean isDoubleBuffered) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
private ArrayList<Component> componentList = new ArrayList<>();
@Override
public Component add(Component comp)
{
super.add(comp);
componentList.add(comp);
int listSize = componentList.size();
String topConstraint;
Component northComponent;
if (listSize == 1)
{
topConstraint = NORTH;
northComponent = this;
}
else
{
topConstraint = SOUTH;
northComponent = componentList.get(listSize - 2);
}
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent);
springLayout.putConstraint(WEST, comp, padding, WEST, this);
// springLayout.putConstraint(EAST, comp, padding, EAST, this);
return comp;
}
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
// springLayout.putConstraint(EAST, this, padding, EAST, lastComponent);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
springLayout.putConstraint(WEST, this, padding, WEST, lastComponent);
int maxComponentWidth = 0;
int panelHeight = padding;
// calculate overall height and maximum width
for (Component component: componentList)
{
Dimension componentDimension = component.getPreferredSize();
maxComponentWidth = Math.max(maxComponentWidth, componentDimension.width);
panelHeight = panelHeight + componentDimension.height + padding;
}
// for each component, set the component width and preferred height,
// and set maximum width to MAX_VALUE; I was trying to get the components
// to stretch, but that doesn't work.
for (Component component: componentList)
{
Dimension componentDimension = component.getPreferredSize();
Dimension newD = new Dimension(maxComponentWidth, componentDimension.height);
// Dimension maxD = new Dimension(Integer.MAX_VALUE, componentDimension.height);
component.setPreferredSize(newD);
component.setMinimumSize(newD);
component.setMaximumSize(newD);
}
// set panel dimensions
Dimension newD = new Dimension(maxComponentWidth + (padding*2), panelHeight);
this.setPreferredSize(newD);
this.setMinimumSize(newD);
}
}
当前测试人员:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import rcutil.layout.OneWidthPanel;
public class OneWidthPanelTester extends JFrame implements Runnable
{
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
OneWidthPanelTester tester = new OneWidthPanelTester();
SwingUtilities.invokeLater(tester);
}
public void run()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
JLabel label = new JLabel("I'm last");
label.setBorder(BorderFactory.createLineBorder(Color.black));
JTextField textField = new JTextField(25);
OneWidthPanel panel = new OneWidthPanel();
panel.add(button1);
panel.add(button2);
panel.add(rButton);
panel.add(label);
panel.add(textField);
panel.finishedAdding();
add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
}
}
这些组件以添加到面板的最宽组件(按首选尺寸)的宽度显示。按钮不会随面板一起拉伸,但文本字段会拉伸 - 我曾想过设置按钮的最大尺寸并添加 EAST-direction 约束会拉伸它们,但它似乎没有,我也没有我现在做的不需要那个。
正如 Hitesh 指出的那样,您在 add
方法中将参数交换为 SpringLayout.putConstraints。 The documentation 状态:
public void putConstraint(String e1,
Component c1,
int pad,
String e2,
Component c2)
…
Parameters:
e1
- the edge of the dependent
c1
- the component of the dependent
pad
- the fixed distance between dependent and anchor
e2
- the edge of the anchor
c2
- the component of the anchor
前两个参数是“从属”——即您要定位的组件。最后两个参数是“锚点”——即被定位的组件将依赖的其他组件(或容器)。
但这还不是问题的全部。要使所有组件的宽度相同,您需要使用 Spring which is built using Spring.max.
聚合它们的所有高度
A Spring based on a component 是一个“实时”对象:确切的最小值、首选值和最大值会随着相应组件中的更改而更改。因此,所有这些 component-based Spring 对象的最大值将是您要应用于所有对象的宽度。
首先将组件的宽度保留在私有字段中:
private Spring width = Spring.constant(0);
然后,在您的 add
方法中,您只需要调用一次 putConstraints
。暂时不附上组件的横向尺寸:
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent );
width = Spring.max(width, Spring.width(comp));
最后,在 finishedAdding
中,使用那个“智能”Spring 作为容器的宽度和每个组件的宽度。
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
springLayout.putConstraint(EAST, this, width, WEST, this);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
// Make every component's width fill this container.
for (Component comp : componentList) {
springLayout.putConstraint(WEST, comp, 0, WEST, this);
springLayout.putConstraint(EAST, comp, width, WEST, this);
}
}
首先,我们将容器的宽度绑定到所有组件的最大宽度(并将其高度绑定到最后一个组件)。然后,为了确保每个组件都伸展以填充容器的宽度,我们将其东边和西边都附加到容器。
就其价值而言,您实际上并不需要 Spring布局。 Box 可以为所欲为,无需专门的 class:
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
int padding = 5;
Box panel = Box.createVerticalBox();
panel.add(button1);
panel.add(Box.createVerticalStrut(padding));
panel.add(button2);
panel.add(Box.createVerticalStrut(padding));
panel.add(rButton);
for (Component comp : panel.getComponents()) {
Dimension size = comp.getMaximumSize();
size.width = Integer.MAX_VALUE;
comp.setMaximumSize(size);
}
对于 SpringLayout,我显然有一些不理解的地方。我正在尝试创建一个 class,它是 JPanel 的扩展,它允许我添加组件并让它们垂直显示,宽度相同。
我的 JPanel 扩展会将其 LayoutManager 设置为使用 SpringLayout,每次添加组件时,它都会放入 SpringLayout 约束以将其附加到第一个组件的面板,然后将每个组件附加到前一个组件一.
首先,这是一个使用 SpringLayout 的 Oracle 编写的示例,我将其更改为垂直而不是水平放置组件:
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import javax.swing.SpringLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import java.awt.Container;
public class SpringDemo3
{
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI()
{
// Create and set up the window.
JFrame frame = new JFrame("SpringDemo3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Container contentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
// Create and add the components.
JLabel label = new JLabel("Label: ");
JTextField textField = new JTextField("Text field", 15);
contentPane.add(label);
contentPane.add(textField);
// Adjust constraints for the label so it's at (5,5).
layout.putConstraint(SpringLayout.WEST, label, 5, SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label, 5, SpringLayout.NORTH, contentPane);
// Adjust constraints for the text field so it's at
// (<label's right edge> + 5, 5).
// layout.putConstraint(SpringLayout.WEST, textField, 5, SpringLayout.EAST, label);
// layout.putConstraint(SpringLayout.EAST, textField, 5, SpringLayout.EAST, contentPane);
layout.putConstraint(SpringLayout.NORTH, textField, 5, SpringLayout.SOUTH, label);
// Adjust constraints for the content pane: Its right
// edge should be 5 pixels beyond the text field's right
// edge, and its bottom edge should be 5 pixels beyond
// the bottom edge of the tallest component (which we'll
// assume is textField).
layout.putConstraint(SpringLayout.EAST, contentPane, 5, SpringLayout.EAST, textField);
layout.putConstraint(SpringLayout.SOUTH, contentPane, 5, SpringLayout.SOUTH, textField);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
根据我理解的SpringLayout的要求,我写了以下内容:
import java.awt.Component;
import java.awt.LayoutManager;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import static javax.swing.SpringLayout.NORTH;
import static javax.swing.SpringLayout.EAST;
import static javax.swing.SpringLayout.SOUTH;
import static javax.swing.SpringLayout.WEST;
public class OneWidthPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private int padding = 5;
SpringLayout springLayout = new SpringLayout();
public OneWidthPanel() { super(); setLayout(springLayout); }
public OneWidthPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); }
public OneWidthPanel(LayoutManager layout) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
public OneWidthPanel(LayoutManager l, boolean isDoubleBuffered) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
private ArrayList<Component> componentList = new ArrayList<>();
@Override
public Component add(Component comp)
{
super.add(comp);
componentList.add(comp);
int listSize = componentList.size();
String topConstraint;
Component northComponent;
if (listSize == 1)
{
topConstraint = NORTH;
northComponent = this;
}
else
{
topConstraint = SOUTH;
northComponent = componentList.get(listSize - 2);
}
springLayout.putConstraint(topConstraint, northComponent, padding, SpringLayout.NORTH, comp);
springLayout.putConstraint(WEST, this, padding, WEST, comp);
springLayout.putConstraint(EAST, this, padding, EAST, comp);
return comp;
}
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
springLayout.putConstraint(EAST, this, padding, EAST, lastComponent);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
}
}
这里有一个小程序来测试它:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import rcutil.layout.OneWidthPanel;
public class OneWidthPanelTester extends JFrame
{
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
OneWidthPanelTester tester = new OneWidthPanelTester();
tester.go();
}
public void go()
{
OneWidthPanel panel = new OneWidthPanel();
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
panel.add(button1);
panel.add(button2);
panel.add(rButton);
panel.finishedAdding();
add(panel, BorderLayout.WEST);
pack();
setVisible(true);
}
}
组件出现在面板顶部的彼此之上。我想设置每个组件的约束,正如我添加的那样,将每个组件的北端连接到前一个组件的南边,将它们按照添加的顺序垂直排列。我有 finishedAdding()
方法,这样我就可以结束最后一个组件与其容器的连接,如 https://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html 的“如何使用 SpringLayout”教程中所述,以及我复制的演示程序中所做的.
我不明白为什么我的组件相互重叠,但(两个)演示组件垂直相邻。我是否能够满足我最初的愿望,即让垂直组件在面板中拉伸为相同大小?
你需要改变
springLayout.putConstraint(topConstraint, comp, padding, SpringLayout.NORTH, northComponent);
至
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent);
这是我最终得出的结论:
import static javax.swing.SpringLayout.EAST;
import static javax.swing.SpringLayout.NORTH;
import static javax.swing.SpringLayout.SOUTH;
import static javax.swing.SpringLayout.WEST;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.util.ArrayList;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
public class OneWidthPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private int padding = 5;
SpringLayout springLayout = new SpringLayout();
BoxLayout boxLayout = new BoxLayout(this, BoxLayout.PAGE_AXIS);
public OneWidthPanel()
{
super();
setLayout(springLayout);
}
public OneWidthPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); }
public OneWidthPanel(LayoutManager layout) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
public OneWidthPanel(LayoutManager l, boolean isDoubleBuffered) { throw new IllegalArgumentException("Cannot set a layout manager on the OneWidthPanel class"); }
private ArrayList<Component> componentList = new ArrayList<>();
@Override
public Component add(Component comp)
{
super.add(comp);
componentList.add(comp);
int listSize = componentList.size();
String topConstraint;
Component northComponent;
if (listSize == 1)
{
topConstraint = NORTH;
northComponent = this;
}
else
{
topConstraint = SOUTH;
northComponent = componentList.get(listSize - 2);
}
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent);
springLayout.putConstraint(WEST, comp, padding, WEST, this);
// springLayout.putConstraint(EAST, comp, padding, EAST, this);
return comp;
}
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
// springLayout.putConstraint(EAST, this, padding, EAST, lastComponent);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
springLayout.putConstraint(WEST, this, padding, WEST, lastComponent);
int maxComponentWidth = 0;
int panelHeight = padding;
// calculate overall height and maximum width
for (Component component: componentList)
{
Dimension componentDimension = component.getPreferredSize();
maxComponentWidth = Math.max(maxComponentWidth, componentDimension.width);
panelHeight = panelHeight + componentDimension.height + padding;
}
// for each component, set the component width and preferred height,
// and set maximum width to MAX_VALUE; I was trying to get the components
// to stretch, but that doesn't work.
for (Component component: componentList)
{
Dimension componentDimension = component.getPreferredSize();
Dimension newD = new Dimension(maxComponentWidth, componentDimension.height);
// Dimension maxD = new Dimension(Integer.MAX_VALUE, componentDimension.height);
component.setPreferredSize(newD);
component.setMinimumSize(newD);
component.setMaximumSize(newD);
}
// set panel dimensions
Dimension newD = new Dimension(maxComponentWidth + (padding*2), panelHeight);
this.setPreferredSize(newD);
this.setMinimumSize(newD);
}
}
当前测试人员:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import rcutil.layout.OneWidthPanel;
public class OneWidthPanelTester extends JFrame implements Runnable
{
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
OneWidthPanelTester tester = new OneWidthPanelTester();
SwingUtilities.invokeLater(tester);
}
public void run()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
JLabel label = new JLabel("I'm last");
label.setBorder(BorderFactory.createLineBorder(Color.black));
JTextField textField = new JTextField(25);
OneWidthPanel panel = new OneWidthPanel();
panel.add(button1);
panel.add(button2);
panel.add(rButton);
panel.add(label);
panel.add(textField);
panel.finishedAdding();
add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
}
}
这些组件以添加到面板的最宽组件(按首选尺寸)的宽度显示。按钮不会随面板一起拉伸,但文本字段会拉伸 - 我曾想过设置按钮的最大尺寸并添加 EAST-direction 约束会拉伸它们,但它似乎没有,我也没有我现在做的不需要那个。
正如 Hitesh 指出的那样,您在 add
方法中将参数交换为 SpringLayout.putConstraints。 The documentation 状态:
public void putConstraint(String e1, Component c1, int pad, String e2, Component c2)
…
Parameters:
e1
- the edge of the dependent
c1
- the component of the dependent
pad
- the fixed distance between dependent and anchor
e2
- the edge of the anchor
c2
- the component of the anchor
前两个参数是“从属”——即您要定位的组件。最后两个参数是“锚点”——即被定位的组件将依赖的其他组件(或容器)。
但这还不是问题的全部。要使所有组件的宽度相同,您需要使用 Spring which is built using Spring.max.
聚合它们的所有高度A Spring based on a component 是一个“实时”对象:确切的最小值、首选值和最大值会随着相应组件中的更改而更改。因此,所有这些 component-based Spring 对象的最大值将是您要应用于所有对象的宽度。
首先将组件的宽度保留在私有字段中:
private Spring width = Spring.constant(0);
然后,在您的 add
方法中,您只需要调用一次 putConstraints
。暂时不附上组件的横向尺寸:
springLayout.putConstraint(NORTH, comp, padding, topConstraint, northComponent );
width = Spring.max(width, Spring.width(comp));
最后,在 finishedAdding
中,使用那个“智能”Spring 作为容器的宽度和每个组件的宽度。
public void finishedAdding()
{
Component lastComponent = componentList.get(componentList.size()-1);
springLayout.putConstraint(EAST, this, width, WEST, this);
springLayout.putConstraint(SOUTH, this, padding, SOUTH, lastComponent);
// Make every component's width fill this container.
for (Component comp : componentList) {
springLayout.putConstraint(WEST, comp, 0, WEST, this);
springLayout.putConstraint(EAST, comp, width, WEST, this);
}
}
首先,我们将容器的宽度绑定到所有组件的最大宽度(并将其高度绑定到最后一个组件)。然后,为了确保每个组件都伸展以填充容器的宽度,我们将其东边和西边都附加到容器。
就其价值而言,您实际上并不需要 Spring布局。 Box 可以为所欲为,无需专门的 class:
JButton button1 = new JButton("ONE new button");
JButton button2 = new JButton("second b");
JRadioButton rButton = new JRadioButton("choose me");
int padding = 5;
Box panel = Box.createVerticalBox();
panel.add(button1);
panel.add(Box.createVerticalStrut(padding));
panel.add(button2);
panel.add(Box.createVerticalStrut(padding));
panel.add(rButton);
for (Component comp : panel.getComponents()) {
Dimension size = comp.getMaximumSize();
size.width = Integer.MAX_VALUE;
comp.setMaximumSize(size);
}