java swing - 使用不同布局管理器时的布局奇怪

时间:2009-02-12 00:53:17

标签: 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);
        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
    }
}

除了能够使用布局管理器在根窗格中定位j0之外,我得到了我正在寻找的东西。如果我改变了

        frame.getContentPane().setLayout(null);

行到

        frame.getContentPane().setLayout(new java.awt.FlowLayout());

我在屏幕中间看到j0绘制为1x1像素: - (

任何想法为什么?请注意,这不仅仅是一个FlowLayout事情 - 几乎每个布局管理器都会混淆它。

我真的希望得到'边框修剪一边'按钮的净效果 - 它允许我做工具栏 - 按钮 - 群集的事情(cage fighter试图摆脱的那种事情)具有原生外观的按钮控件 - 由于操作系统级别的皮肤,我无法看到另一种方法。所以任何想法都赞赏: - )

4 个答案:

答案 0 :(得分:4)

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

如果在组件上使用setBounds,则会占用父容器的布局管理器所做的工作。

我将删除对setBounds的所有调用以及对setLayout(null)的所有调用,并尝试实现仅使用布局管理器后的效果。

答案 1 :(得分:1)

  

......任何想法为什么?

是。发生这种情况是因为当您删除布局管理器(通过将其设置为null)时,您对计算机说“我将完成所有铺设工作”;使用任何其他LayoutManager时,将尝试...根据您的需要(根据要放置的对象的属性)布置组件

所以,我认为尝试创建一个Border实例并将其设置为JButton而不是尝试调整它周围的所有对象会更好。

我会看看能否快速提出一些事情。

修改

哎呀,它不是很快,但它就在这里(我弄乱了一条令我讨厌的1px线) alt text http://img22.imageshack.us/img22/8933/capturaby8.png

正如我之前所说,将布局设置为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);

    }

}

编辑

Dave Carpeneto写道:

  

** Oscar&gt; ***不幸的是,一旦你UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); ,这也是我的需求的核心(我希望尽可能让这看起来像本地人一样)。*

好吧,我没有尝试过你的工作,但回答你的问题,你认为你的问题与LayoutManagers有关,我说这不是问题。

也许我应该停在那里,但我的“程序员”痒让我继续这个样本。 :)

我很高兴你最终解决了你的问题;)

答案 2 :(得分:1)

有关布局管理器如何工作的非常好的解释,请查看我在Sun写的一篇旧文章

http://developer.java.sun.com/developer/onlineTraining/GUI/AWTLayoutMgr/

它已经过时了,但谈到preferredSize和布局很好。

享受, - 斯科特

答案 3 :(得分:0)

Hiya - 感谢大家的帮助。

Dan&gt; 这是您对首选布局的评论让我开始工作 - 只需添加j0.setPreferredSize(new java.awt.Dimension(32, 32));就可以实现这一点。

奥斯卡&gt; 不幸的是,一旦你UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());,这就停止了工作,这也是我需要的核心(我希望尽可能让它看起来像本机一样)。

例如,这是我在XP上用3个按钮看起来的样子:

alt text http://img19.imageshack.us/img19/8595/minems5.png

...这就是你看起来像XP外观的样子:

alt text http://img102.imageshack.us/img102/5412/yoursod4.png

......不幸的是,这不是同一件事 - 抱歉我的要求不清楚: - (

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

  }
}

Scott&gt; 我受过教育:-) thanks