为什么我的自定义边框适用于所有组件?

时间:2014-07-03 09:35:46

标签: java swing border

我尝试仅为面板创建一个虚拟边界(在Java 7之前),但它也适用于面板中的所有组件。有谁知道为什么?

public class Box extends JPanel {

        public Box() {
            super();
            DashedBorder dashedBorder = new DashedBorder();

            this.setBorder(new TitledBorder(dashedBorder, "title", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION));
            this.setLayout(new GridLayout(5, 1));
            for (int i = 1; i <= 15; i++) {
                this.add(new JCheckBox("" + i));
            }

        }


    class DashedBorder extends AbstractBorder {
        @Override
        public void paintBorder(Component comp, Graphics g, int x, int y, int w, int h) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.black);
            g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0));
            g2d.drawRect(x, y, w - 1, h - 1);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        Box box = new Box();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setContentPane(p);
        p.add(box,BorderLayout.CENTER);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }



}

1 个答案:

答案 0 :(得分:5)

这是因为在绘制边框后没有清理图形设置。

基本上Swing使用与paintBorder方法相同的图形来绘制面板上的任何谎言。因此,如果您设置笔触,复合,字体,颜色等 - 请确保之后返回以前使用的设置,否则您可能会看到这种意外行为。

您无法预测在您之后绘制的组件是否会设置自己的笔触/合成/其他任何内容,因此您必须在完成绘制自己的内容后恢复默认图形设置。

嗯,实际上你可以跳过恢复颜色,因为几乎每个组件在绘制时都使用它自己,所以保持默认值不是很重要。但只有颜色,所有其他设置都应该恢复,除非你的组件没有任何孩子,或者你100%确定子组件重新定义了某些特定的属性(我怀疑你无论如何都可以肯定)。

这是一个简单的修复:

public class Box extends JPanel
{
    public Box ()
    {
        super ();

        DashedBorder dashedBorder = new DashedBorder ();
        this.setBorder ( new TitledBorder ( dashedBorder, "title", TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION ) );
        this.setLayout ( new GridLayout ( 5, 1 ) );
        for ( int i = 1; i <= 15; i++ )
        {
            this.add ( new JCheckBox ( "" + i ) );
        }
    }

    class DashedBorder extends AbstractBorder
    {
        @Override
        public void paintBorder ( Component comp, Graphics g, int x, int y, int w, int h )
        {
            Graphics2D g2d = ( Graphics2D ) g;
            g2d.setColor ( Color.black );
            final Stroke os = g2d.getStroke ();
            g2d.setStroke ( new BasicStroke ( 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{ 5 }, 0 ) );
            g2d.drawRect ( x, y, w - 1, h - 1 );
            g2d.setStroke ( os );
        }
    }

    public static void main ( String[] args )
    {
        JFrame frame = new JFrame ();
        JPanel p = new JPanel ();
        p.setLayout ( new BorderLayout () );
        Box box = new Box ();
        frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        frame.setSize ( 400, 400 );
        frame.setContentPane ( p );
        p.add ( box, BorderLayout.CENTER );
        frame.setLocationRelativeTo ( null );
        frame.setVisible ( true );
    }
}

我怀疑有很多关于此的文章,因为没有很多人在类似容器的组件上玩绘画。如果您的组件是绘画“链”中的最后一个或基本上没有子组件,您将永远不会看到此问题。

在我自己的项目中,我使用一些辅助方法分成一些实用程序类来帮助我进行设置/恢复操作,例如用于描边:

public static Stroke setupStroke ( final Graphics2D g2d, final Stroke stroke )
{
    return setupStroke ( g2d, stroke, true );
}

public static Stroke setupStroke ( final Graphics2D g2d, final Stroke stroke, final boolean shouldSetup )
{
    if ( shouldSetup && stroke != null )
    {
        final Stroke old = g2d.getStroke ();
        g2d.setStroke ( stroke );
        return old;
    }
    else
    {
        return null;
    }
}

public static void restoreStroke ( final Graphics2D g2d, final Stroke stroke )
{
    restoreStroke ( g2d, stroke, true );
}

public static void restoreStroke ( final Graphics2D g2d, final Stroke stroke, final boolean shouldRestore )
{
    if ( shouldRestore && stroke != null )
    {
        g2d.setStroke ( stroke );
    }
}

因此,在绘画时最终只使用两行代码:

final Stroke stroke = GraphicsUtils.setupStroke ( newStroke );

// paint something

GraphicsUtils.restoreStroke ( g2d, stroke );