java swing-使用不同布局管理器时的布局异常

java swing-使用不同布局管理器时的布局异常,java,swing,layout,Java,Swing,Layout,有点奇怪,如果我这样做: import javax.swing.*; public class FunkyButtonLayout { public static void main(String[] args) { JFrame frame = new JFrame(""); JPanel j0 = new JPanel(); // j0 gets added to the root pane j0.setLayout(null)

有点奇怪,如果我这样做:

import javax.swing.*;
public class FunkyButtonLayout {
    public static void main(String[] args) {
        JFrame frame = new JFrame("");
        JPanel j0 = new JPanel();     // j0 gets added to the root pane
        j0.setLayout(null);
        JPanel j1 = new JPanel();     // j1 gets added to j0 
        j1.setLayout(null);
        JButton b1 = new JButton(""); // b1 gets added to j1
        j1.add(b1);
        b1.setBounds(0, 0, 40, 32);   // b1 is big
        j0.add(j1);
        j1.setBounds(0, 0, 32, 32);   // j1 is not so big - b1 gets 'trimmed'
        frame.getContentPane().setLayout(null); // <- seems to be needed :-(
        frame.getContentPane().add(j0);             
        j0.setBounds(10, 10, 32, 32); // end result: a 32x32 button with
        frame.setSize(125, 125);      // a trimmed right border
        frame.setVisible(true);       // in the top-left corner
    }
}
排队

        frame.getContentPane().setLayout(new java.awt.FlowLayout());
我将j0绘制为屏幕中间的1x1像素:-

你知道为什么吗?请注意,这不仅仅是一个FlowLayout问题——几乎每个布局管理器都会把它搞砸


我真的很想拥有“在一边修剪边框”按钮的净效果——它允许我做工具栏按钮集群的事情,这种事情试图摆脱原生外观的按钮控件——由于操作系统级别的皮肤,我看不到另一种做这件事的方法。因此,任何想法都值得赞赏:-

如果将布局管理器设置为null,则必须明确设置容器的首选大小,这就是为什么它显示得如此小

如果要在组件上使用收进边界,则会超出父容器布局管理器所做的工作


我将删除对setBounds的所有调用和对setLayoutnull的所有调用,并尝试在仅使用布局管理器后达到您的效果。

如果将布局管理器设置为null,则必须明确设置容器的首选大小,这就是它显示得如此小的原因

如果要在组件上使用收进边界,则会超出父容器布局管理器所做的工作

我将删除对setBounds的所有调用和对setLayoutnull的所有调用,并尝试在仅使用布局管理器后实现您的效果

…知道为什么吗

对。这是因为当你将布局管理器设置为null来删除布局管理器时,你是在对计算机说,我将负责所有的布局工作;在使用任何其他LayoutManager时,将尝试。。。根据要铺设的对象的特性,根据您的需要合理布局组件

因此,我认为最好是尝试创建一个Border实例并将其设置到JButton中,而不是尝试调整它周围的所有对象

我看看能不能快点想出办法

编辑:

哎呀,这不是很快,但这里是我搞砸了一个1px的线,这让我很恼火

正如我前面所说的,将布局设置为null并不是最好的方法。更好的方法是创建自定义边框并将其设置为按钮或设置为空边框

代码如下:

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

/**
 * Sample usage of swing borders.
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
public class ButtonBorderSample  { 

    public static void main( String [] args )  { 

        // Pretty standard swing code
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );


        JPanel panel  = new JPanel( new FlowLayout( 
                                       FlowLayout.CENTER, 0, 5 ) );


        panel.add( createButton( "F I R S T" ) );
        panel.add( createButton( "S E C O N D" ) );
        panel.add( createButton( "T H I R D " ) );

        frame.add( panel , BorderLayout.NORTH );

        frame.pack();
        frame.setVisible( true );

    }
    /**
     * Utility method to create a button.
     * Creates the button, make it square, and add our custom border.
     */
    private static JButton createButton( String s ) { 
        JButton b = new JButton( s );
        b.setPreferredSize( new Dimension( 100, 100   ) );
        b.setBorder( new NoGapBorder() );
        return b;
    }
}

/**
 * This border implementation. It doesn't have insets and draws only a 
 * few parts of the border 
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
class NoGapBorder implements Border  {

    private final Insets insets = new Insets( -1, -1 , -1, -1 );

    /** 
     * Defines in Border interface.
     * @return The default insets instace that specifies no gap at all.
     */
    public Insets getBorderInsets(Component c ) {
        return insets;
    }


    /** 
     * Defines in Border interface.
     * @return false always, it is not relevant.
     */
    public boolean isBorderOpaque() { 
        return false;
    }

    /**
     * Paint the border for the button. 
     * This creates the difference between setting the border to null 
     * and using this class. 
     * It only draws a line in the top, a line in the bottom and a 
     * darker line 
     * in the left, to create the desired effect.
     * A much more complicated strtegy could be used here.
     */
    public void paintBorder(Component c, Graphics g, 
                            int x, int y, int width, int height) { 

       Color oldColor = g.getColor();
       int h = height;
       int w = width;

       g.translate(x, y);

        // Color for top and bottom
        g.setColor( c.getBackground().brighter() );

        // draw top line
        g.drawLine(1, 0, w-2, 0);

        // draw bottom line
       g.drawLine(0, h-1, w-1, h-1); 

       // change the color to make it look as a division
       g.setColor( c.getBackground().darker() );

       // draw the left line
       g.drawLine(0, 0, 0, h-2);        

        // set the graphics back to its original state.
       g.translate(-x, -y);
       g.setColor(oldColor);

    }

}
编辑

戴夫·卡佩内托写道:

**Oscar>***不幸的是,一旦您使用UIManager.setLookAndFeelUIManager.getSystemLookAndFeelClassName;,此选项将停止工作,这也是我的核心需求,我希望让它看起来尽可能的本土化*

嗯,我不是想让你工作,但为了回答你的问题,你认为你的问题与裁员经理有关,我说这不是问题所在

也许我应该到此为止,但我的程序员渴望让我继续使用这个示例

我很高兴你终于解决了你的问题

…知道为什么吗

对。这是因为当你将布局管理器设置为null来删除布局管理器时,你是在对计算机说,我将负责所有的布局工作;在使用任何其他LayoutManager时,将尝试。。。根据要铺设的对象的特性,根据您的需要合理布局组件

因此,我认为最好是尝试创建一个Border实例并将其设置到JButton中,而不是尝试调整它周围的所有对象

我看看能不能快点想出办法

编辑:

哎呀,这不是很快,但这里是我搞砸了一个1px的线,这让我很恼火

正如我前面所说的,将布局设置为null并不是最好的方法。更好的方法是创建自定义边框并将其设置为按钮或设置为空边框

代码如下:

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

/**
 * Sample usage of swing borders.
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
public class ButtonBorderSample  { 

    public static void main( String [] args )  { 

        // Pretty standard swing code
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );


        JPanel panel  = new JPanel( new FlowLayout( 
                                       FlowLayout.CENTER, 0, 5 ) );


        panel.add( createButton( "F I R S T" ) );
        panel.add( createButton( "S E C O N D" ) );
        panel.add( createButton( "T H I R D " ) );

        frame.add( panel , BorderLayout.NORTH );

        frame.pack();
        frame.setVisible( true );

    }
    /**
     * Utility method to create a button.
     * Creates the button, make it square, and add our custom border.
     */
    private static JButton createButton( String s ) { 
        JButton b = new JButton( s );
        b.setPreferredSize( new Dimension( 100, 100   ) );
        b.setBorder( new NoGapBorder() );
        return b;
    }
}

/**
 * This border implementation. It doesn't have insets and draws only a 
 * few parts of the border 
 * @author <a href="http://stackoverflow.com/users/20654">Oscar Reyes</a>
 */
class NoGapBorder implements Border  {

    private final Insets insets = new Insets( -1, -1 , -1, -1 );

    /** 
     * Defines in Border interface.
     * @return The default insets instace that specifies no gap at all.
     */
    public Insets getBorderInsets(Component c ) {
        return insets;
    }


    /** 
     * Defines in Border interface.
     * @return false always, it is not relevant.
     */
    public boolean isBorderOpaque() { 
        return false;
    }

    /**
     * Paint the border for the button. 
     * This creates the difference between setting the border to null 
     * and using this class. 
     * It only draws a line in the top, a line in the bottom and a 
     * darker line 
     * in the left, to create the desired effect.
     * A much more complicated strtegy could be used here.
     */
    public void paintBorder(Component c, Graphics g, 
                            int x, int y, int width, int height) { 

       Color oldColor = g.getColor();
       int h = height;
       int w = width;

       g.translate(x, y);

        // Color for top and bottom
        g.setColor( c.getBackground().brighter() );

        // draw top line
        g.drawLine(1, 0, w-2, 0);

        // draw bottom line
       g.drawLine(0, h-1, w-1, h-1); 

       // change the color to make it look as a division
       g.setColor( c.getBackground().darker() );

       // draw the left line
       g.drawLine(0, 0, 0, h-2);        

        // set the graphics back to its original state.
       g.translate(-x, -y);
       g.setColor(oldColor);

    }

}
编辑

戴夫·卡佩内托写道:

**Oscar>***不幸的是,一旦您使用UIManager.setLookAndFeelUIManager.getSystemLookAndFeelClassName;,此选项将停止工作,这也是我的核心需求,我希望让它看起来尽可能的本土化*

嗯,我不是想让你工作,但为了回答你的问题,你认为你的问题与裁员经理有关,我说这不是问题所在

也许我应该到此为止,但我的程序员渴望让我继续使用这个示例


我很高兴你终于解决了你的问题

要了解布局管理器的工作原理,请查看我在Sun上写的一篇老文章

它很老了,但它很好地讨论了首选大小和布局嵌套

享受,
-Scott

要了解布局管理器的工作原理,请查看我在Sun上写的一篇旧文章

它很老了,但它很好地讨论了首选大小和布局嵌套

享受,
-斯科特

你好-谢谢大家的帮助

Dan>正是你对首选布局的评论让我开始工作——添加j0.setPreferredSizenew java.awt.Dimensi on32,32;这就是让它工作所需要的一切

Oscar>不幸的是,一旦您使用UIManager.setLookAndFeelUIManager.getSystemLookAndFeelClassName;,此选项将停止工作,这也是我的核心需求,我希望让它看起来尽可能的本土化

例如,我的XP上有3个按钮,如下所示:

。。。以下是您的XP外观:

。。。不幸的是,这不是同一件事-很抱歉我的要求不够明确:-

FWIW,这里的代码图像是与按钮大小相同的透明图标,垂直线是图标的一部分:

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

public class FunkyButtonLayout {
  public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel(
          UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {

    }

    JFrame frame = new JFrame("x");
    Container y = frame.getContentPane();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    y.setLayout(new FlowLayout());

    JPanel uberButton = new JPanel();
    uberButton.setLayout(null);
    uberButton.setSize(98, 32);
    uberButton.setPreferredSize(new Dimension(98, 32));

    JButton record = new JButton(new ImageIcon("img/record.png"));
    record.setBounds(0, 0, 40, 32);
    record.setEnabled(true);
    record.setFocusPainted(false);
    JPanel _record = new JPanel();
    _record.setLayout(null);
    _record.setBounds(0, 0, 33, 32);

    JButton pause = new JButton(new ImageIcon("img/pause.png"));
    pause.setBounds(-4, 0, 44, 32);
    pause.setEnabled(true);
    pause.setFocusPainted(false);
    JPanel _pause = new JPanel();
    _pause.setLayout(null);
    _pause.setBounds(33, 0, 33, 32);

    JButton stop = new JButton(new ImageIcon("img/stop.png"));
    stop.setBounds(-4, 0, 36, 32);
    stop.setEnabled(true);
    stop.setFocusPainted(false);
    JPanel _stop = new JPanel();
    _stop.setLayout(null);
    _stop.setBounds(66, 0, 32, 32); 

    _record.add(record);
    _pause.add(pause);
    _stop.add(stop);

    uberButton.add(_record);
    uberButton.add(_pause);
    uberButton.add(_stop);

    y.add(uberButton);

    frame.pack();

    frame.setVisible(true);

  }
}

斯科特>我受过教育:-谢谢大家的帮助

Dan>正是你对首选布局的评论让我开始工作——添加j0.setPreferredSizenew java.awt.Dimension32,32;这就是让它工作所需要的一切

Oscar>不幸的是,一旦您使用UIManager.setLookAndFeelUIManager.getSystemLookAndFeelClassName;,此选项将停止工作,这也是我的核心需求,我希望让它看起来尽可能的本土化

例如,我的XP上有3个按钮,如下所示:

。。。以下是您的XP外观:

。。。不幸的是,这不是同一件事-很抱歉我的要求不够明确:-

FWIW,这里的代码图像是与按钮大小相同的透明图标,垂直线是图标的一部分:

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

public class FunkyButtonLayout {
  public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel(
          UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {

    }

    JFrame frame = new JFrame("x");
    Container y = frame.getContentPane();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    y.setLayout(new FlowLayout());

    JPanel uberButton = new JPanel();
    uberButton.setLayout(null);
    uberButton.setSize(98, 32);
    uberButton.setPreferredSize(new Dimension(98, 32));

    JButton record = new JButton(new ImageIcon("img/record.png"));
    record.setBounds(0, 0, 40, 32);
    record.setEnabled(true);
    record.setFocusPainted(false);
    JPanel _record = new JPanel();
    _record.setLayout(null);
    _record.setBounds(0, 0, 33, 32);

    JButton pause = new JButton(new ImageIcon("img/pause.png"));
    pause.setBounds(-4, 0, 44, 32);
    pause.setEnabled(true);
    pause.setFocusPainted(false);
    JPanel _pause = new JPanel();
    _pause.setLayout(null);
    _pause.setBounds(33, 0, 33, 32);

    JButton stop = new JButton(new ImageIcon("img/stop.png"));
    stop.setBounds(-4, 0, 36, 32);
    stop.setEnabled(true);
    stop.setFocusPainted(false);
    JPanel _stop = new JPanel();
    _stop.setLayout(null);
    _stop.setBounds(66, 0, 32, 32); 

    _record.add(record);
    _pause.add(pause);
    _stop.add(stop);

    uberButton.add(_record);
    uberButton.add(_pause);
    uberButton.add(_stop);

    y.add(uberButton);

    frame.pack();

    frame.setVisible(true);

  }
}

斯科特>我受过教育:-谢谢你,爸爸!嗯,差不多了;-按照预期的方式使用布局管理器并不能让我得到我想要的技能。但是添加j0.setPreferredSizenew java.awt.Dimension32,32;在j0.setBounds行解决问题之后。谢谢你这个男人!嗯,差不多了;-按照预期的方式使用布局管理器并不能让我得到我想要的技能。但是添加j0.setPreferredSizenew java.awt.Dimension32,32;在j0.setBounds行解决问题之后。谢谢也许我应该停在那里,瑞莉,瑞莉很高兴你没有停下来-我从你介绍的代码中学到了很多-谢谢:-也许我应该停在那里,瑞莉,瑞莉很高兴你没有停下来-我从你介绍的代码中学到了很多-谢谢:-