说我在JPanel中有两个组件,A和B.我希望组件A保持左对齐,而组件B尽力保持在面板中间。我嘲笑了下面的演示(抱歉质量,我在油漆中制作):
我现在正在做的是在JPanel上使用GridBagLayout,并保持A左对齐同时保持B居中,但B保持在第2列的中心,所以它在放置A后剩余的空间居中,而不是以整个小组为中心。
我不能使用任何第三方库。有没有办法使用纯Swing来做到这一点?
Firefly的答案是正确的(如标记所示)但我创建了一个SSCCE显示我的原始问题(第一行),Hovercraft Full Of Eels的尝试解决方案(第二行)和Firefly的正确解决方案(第三行)。我认为发布它不会有害:
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.LayoutManager2;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class StackOverflowTest extends JFrame
{
public StackOverflowTest()
{
super("Stack Overflow Test");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel testPanel = new JPanel(new GridLayout(3, 1));
// set up grid bag layout example
JPanel gridBagPanel = new JPanel(new GridBagLayout());
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = GridBagConstraints.LINE_START;
gridBagPanel.add(getA(), gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = GridBagConstraints.CENTER;
gridBagConstraints.weightx = 1.0;
gridBagPanel.add(getB(), gridBagConstraints);
testPanel.add(gridBagPanel);
// set up border layout panel
JPanel borderPanel = new JPanel(new BorderLayout());
borderPanel.add(getA(), BorderLayout.LINE_START);
JPanel flowPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
borderPanel.add(flowPanel, BorderLayout.CENTER);
flowPanel.add(getB());
testPanel.add(borderPanel);
// set up sly493 layout panel
JPanel sly493LayoutPanel = new JPanel(new Sly493LayoutManager());
sly493LayoutPanel.add(getA(), Sly493LayoutManager.LEFT);
sly493LayoutPanel.add(getB(), Sly493LayoutManager.CENTERED);
testPanel.add(sly493LayoutPanel);
// set up panel to act as the midpoint marker
JPanel midpointMarkerPanel = new JPanel()
{
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
int w = getWidth();
int h = getHeight();
int x = w / 2;
g2.drawLine(x, 0, x, h);
g2.drawLine(x, 0, x - (h / 5), (h / 5));
g2.drawLine(x, 0, x + (h / 5), (h / 5));
}
};
midpointMarkerPanel.setPreferredSize(new Dimension(1, 50));
// setup up content pane
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(testPanel, BorderLayout.NORTH);
contentPane.add(midpointMarkerPanel, BorderLayout.CENTER);
this.setContentPane(contentPane);
pack();
}
private JPanel getA()
{
JPanel aPanel = new JPanel(new BorderLayout());
JLabel aLabel = new JLabel("A", JLabel.CENTER);
aLabel.setFont(aLabel.getFont().deriveFont(Font.BOLD, 36));
aPanel.add(aLabel, BorderLayout.CENTER);
aPanel.setBackground(Color.RED);
aPanel.setPreferredSize(new Dimension(50, 50));
return aPanel;
}
private JPanel getB()
{
JPanel bPanel = new JPanel();
JLabel bLabel = new JLabel("B", JLabel.CENTER);
bLabel.setForeground(Color.WHITE);
bLabel.setFont(bLabel.getFont().deriveFont(Font.BOLD, 36));
bPanel.add(bLabel, BorderLayout.CENTER);
bPanel.setBackground(Color.BLUE);
bPanel.setPreferredSize(new Dimension(50, 50));
return bPanel;
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
new StackOverflowTest().setVisible(true);
}
});
}
private static class Sly493LayoutManager implements LayoutManager2
{
public static final Integer LEFT = 0;
public static final Integer CENTERED = 1;
private Component leftComponent;
private Component centeredComponent;
@Override
public void addLayoutComponent(String name, Component comp)
{
}
@Override
public void removeLayoutComponent(Component comp)
{
if (leftComponent == comp)
{
leftComponent = null;
}
else if (centeredComponent == comp)
{
centeredComponent = null;
}
}
@Override
public Dimension preferredLayoutSize(Container parent)
{
Dimension d = new Dimension();
for (Component c : parent.getComponents())
{
//wide enough to stack the left and center components horizontally without overlap
d.width += c.getPreferredSize().width;
//tall enough to fit the tallest component
d.height = Math.max(d.height, c.getPreferredSize().height);
}
return d;
}
@Override
public Dimension minimumLayoutSize(Container parent)
{
return preferredLayoutSize(parent);
}
@Override
public void layoutContainer(Container parent)
{
//in this method we will:
//1) position the left component on the left edge of the parent and center it vertically
//2) position the center component in the center of the parent (as long as it would not overlap
//the left component) and center it vertically
int leftComponentWidth = leftComponent.getPreferredSize().width;
int leftComponentHeight = leftComponent.getPreferredSize().height;
int centeredComponentWidth = centeredComponent.getPreferredSize().width;
int centeredComponentHeight = centeredComponent.getPreferredSize().height;
leftComponent.setBounds(0, (parent.getHeight() - leftComponentHeight) / 2, leftComponentWidth, leftComponentHeight);
int leftComponentRightEdge = leftComponent.getX() + leftComponent.getWidth();
int centerComponentLeftEdge = (parent.getWidth() - centeredComponentWidth) / 2;
int centerComponentTopEdge = (parent.getHeight() - centeredComponentHeight) / 2;
if (leftComponentRightEdge >= centerComponentLeftEdge)
{
//Center component will "do its best" to remain in the center
//but it will not do so if it would cause it to overlap the left component
centerComponentLeftEdge = leftComponentRightEdge;
}
centeredComponent.setBounds(centerComponentLeftEdge,
centerComponentTopEdge,
centeredComponentWidth,
centeredComponentHeight);
}
@Override
public void addLayoutComponent(Component comp, Object constraints)
{
if (LEFT.equals(constraints))
{
if (leftComponent != null)
{
throw new IllegalStateException("A left component has already been assigned to this layout.");
}
leftComponent = comp;
}
else if (CENTERED.equals(constraints))
{
if (centeredComponent != null)
{
throw new IllegalStateException("A centered component has already been assigned to this layout.");
}
centeredComponent = comp;
}
else
{
throw new IllegalStateException("Unexpected constraints '" + constraints + "'.");
}
}
@Override
public Dimension maximumLayoutSize(Container target)
{
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public float getLayoutAlignmentX(Container target)
{
return 0;
}
@Override
public float getLayoutAlignmentY(Container target)
{
return 0;
}
@Override
public void invalidateLayout(Container target)
{
}
}
}
答案 0 :(得分:2)
如果我正确理解您的需求,您希望B相对于父母整体居中,而不是在A定位后居中留下的空间中心。这使得这个问题变得有趣,在测试了其他建议的答案之后,我不相信他们能够满足这个要求。
我很难想出一种方法来组合内置布局管理器,从而实现这一目标。所以,我已经破解了LayoutManager2的自定义实现。
以下可执行示例可能符合您的需求。实现快速而且肮脏,绝不是一个好的通用布局管理器的例子,但它似乎符合您的要求,并且表现得像我认为应该的图纸。我解释了你的要求" B尽力保持在面板中间#34;意味着B应该试图保持相对于整个面板的中心,但不能以牺牲重叠A为代价。
package com.example;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example {
public Example() {
JPanel a = new JPanel();
a.setBackground(Color.RED);
a.setPreferredSize(new Dimension(128, 128));
JPanel b = new JPanel();
b.setBackground(Color.BLUE);
b.setPreferredSize(new Dimension(128, 128));
JPanel panel = new JPanel(new Sly493LayoutManager());
panel.add(a, Sly493LayoutManager.LEFT);
panel.add(b, Sly493LayoutManager.CENTERED);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Example();
}
private static class Sly493LayoutManager implements LayoutManager2 {
public static final Integer LEFT = 0;
public static final Integer CENTERED = 1;
private Component leftComponent;
private Component centeredComponent;
@Override
public void addLayoutComponent(String name, Component comp) { }
@Override
public void removeLayoutComponent(Component comp) {
if (leftComponent == comp) {
leftComponent = null;
} else if (centeredComponent == comp) {
centeredComponent = null;
}
}
@Override
public Dimension preferredLayoutSize(Container parent) {
Dimension d = new Dimension();
for (Component c : parent.getComponents()) {
//wide enough to stack the left and center components horizontally without overlap
d.width += c.getPreferredSize().width;
//tall enough to fit the tallest component
d.height = Math.max(d.height, c.getPreferredSize().height);
}
return d;
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
@Override
public void layoutContainer(Container parent) {
//in this method we will:
//1) position the left component on the left edge of the parent and center it vertically
//2) position the center component in the center of the parent (as long as it would not overlap
//the left component) and center it vertically
int leftComponentWidth = leftComponent.getPreferredSize().width;
int leftComponentHeight = leftComponent.getPreferredSize().height;
int centeredComponentWidth = centeredComponent.getPreferredSize().width;
int centeredComponentHeight = centeredComponent.getPreferredSize().height;
leftComponent.setBounds(0, (parent.getHeight() - leftComponentHeight) / 2, leftComponentWidth, leftComponentHeight);
int leftComponentRightEdge = leftComponent.getX() + leftComponent.getWidth();
int centerComponentLeftEdge = (parent.getWidth() - centeredComponentWidth) / 2;
int centerComponentTopEdge = (parent.getHeight() - centeredComponentHeight) / 2;
if (leftComponentRightEdge >= centerComponentLeftEdge) {
//Center component will "do its best" to remain in the center
//but it will not do so if it would cause it to overlap the left component
centerComponentLeftEdge = leftComponentRightEdge;
}
centeredComponent.setBounds(centerComponentLeftEdge,
centerComponentTopEdge,
centeredComponentWidth,
centeredComponentHeight);
}
@Override
public void addLayoutComponent(Component comp, Object constraints) {
if (LEFT.equals(constraints)) {
if (leftComponent != null) {
throw new IllegalStateException("A left component has already been assigned to this layout.");
}
leftComponent = comp;
} else if (CENTERED.equals(constraints)) {
if (centeredComponent != null) {
throw new IllegalStateException("A centered component has already been assigned to this layout.");
}
centeredComponent = comp;
} else {
throw new IllegalStateException("Unexpected constraints '" + constraints + "'.");
}
}
@Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public float getLayoutAlignmentX(Container target) {
return 0;
}
@Override
public float getLayoutAlignmentY(Container target) {
return 0;
}
@Override
public void invalidateLayout(Container target) {
}
}
}
答案 1 :(得分:2)
这是一种非常快速和肮脏的方式,类似于Firefly的答案 - 只需创建一个带有null布局的JPanel,并将两个子面板放在其paintComponent方法中:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Example extends JPanel {
protected JPanel a;
protected JPanel b;
int size = 200;
public Example() {
setLayout( null );
a = new JPanel();
a.setBackground( Color.red );
a.setPreferredSize( new Dimension( size, size ) );
b = new JPanel();
b.setBackground( Color.blue );
b.setPreferredSize( new Dimension( size, size ) );
add( a );
add( b );
setPreferredSize( new Dimension( 4 * size, size ) );
}
@Override
public void paintComponent( final Graphics g ) {
super.paintComponent( g );
a.setBounds( 0, 0, size, size );
int w = getWidth();
int x = (w - size) / 2;
if ( x < size ) {
x = size;
}
b.setBounds( x, 0, size, size );
}
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
// Create and set up the window.
JFrame jf = new JFrame();
jf.setName( "Example" );
Example item = new Example();
jf.add( item );
// Display the window.
jf.pack();
jf.setVisible( true );
jf.addWindowListener( new WindowAdapter() {
@Override
public void windowClosing( WindowEvent arg0 ) {
System.exit( 0 );
}
} );
}
} );
}
}
答案 2 :(得分:1)
答案 3 :(得分:0)
出于我的实际目的,我不需要精确的居中。我需要正确对齐。我需要两行。右边的文本比中间的文本短得多。所以诀窍是:
真实应用程序中的某些代码({}
块曾经具有不同的功能,但是现在不重要了)
JPanel myPanel = new JPanel(new GridBagLayout());
JLabel centerFirst = new JLabel("first line");
JLabel rightFirst = new JLabel("...");
{
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
myPanel.add(centerFirst, gridBagConstraints);
}
{
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5; // you don't really need 0.5 and 0.5, it may be 0.1 and 0.1, two equal values
myPanel.add(rightFirst, gridBagConstraints);
}
JLabel centerSecond = new JLabel("second line");
JLabel rightSecond = new JLabel("...");
{
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
myPanel.add(centerSecond, gridBagConstraints);
}
{
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
myPanel.add(rightSecond, gridBagConstraints);
}
//...
// the main frame uses GridBagLayout too
JFrame frame = new JFrame();
{
GridBagLayout gbl = new GridBagLayout();
//...
frame.setLayout(gbl);
}
// myPanel: full width of the enclosing GridBagLayout
{
GridBagLayout gbl = (GridBagLayout) frame.getContentPane().getLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0; // it will occupy columns 0 and 1 of the GridBagLayout
gbc.gridy = 4; // and there will be stuff above it
gbc.gridheight = 1; // full width, therefore height=1 is enough
gbc.gridwidth = 2; // the number of columns in this GridBagLayout
gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(myPanel, gbc);
frame.add(myPanel);
}