我尝试仅为面板创建一个虚拟边界(在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);
}
}
答案 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 );