views:

475

answers:

2

I'm trying to create a generic graphics export tool which works by implementing the Graphics interface and intercepts and interprets the calls to its various methods. However although I can do this successfully for a single component my Graphics class is being replaced when I use it on a component which contains other components. Strangely this only happens on Windows and Linux. On OSX it works fine.

Can anyone suggest how I can ensure that it's my original Graphics class which is passed to all subcomponents?

I've got a short script which demonstrates the fundamental problem. When I explicitly call paint using an instance of MyGraphics I don't see MyGraphics in the JPanel - just sun.java2d.SunGraphics2D.

import java.awt.*;
import java.awt.image.*;
import java.text.AttributedCharacterIterator;
import javax.swing.*;

public class GraphicsTest {

public static void main(String[] args) {
 new GraphicsTest();
}

public GraphicsTest () {
 JFrame frame = new JFrame();
 frame.getContentPane().add(new MyPanel());
 frame.setSize(500,500);
 frame.setVisible(true);
 try {
  Thread.sleep(2000);
 } catch (InterruptedException e) {}
 System.out.println("Using my graphics - expect to see 'MyGraphics' next");
 frame.paint(new MyGraphics());

}

class MyPanel extends JPanel {
 public void paint (Graphics g) {
  super.paint(g);
  System.out.println("Graphics is "+g);

  g.fillRect(10, 10, 20, 20);
 }
}

class MyGraphics extends Graphics {

 public String toString () {
  return "MyGraphics";
 }

 public Graphics create() {
  return this;
 }

 // I've left out the huge list of abstract methods from the original script
 // since they're unchanged from the defaults and don't really matter here.
}

On my windows system the output is:

Graphics is sun.java2d.SunGraphics2D[font=javax.swing.plaf.FontUIResource[family=Dialog,name=Dialog,style=plain,size=12],color=sun.swing.PrintColorUIResource[r=51,g=51,b=51]]
Using my graphics - expect to see 'MyGraphics' next
Graphics is sun.java2d.SunGraphics2D[font=javax.swing.plaf.FontUIResource[family=Dialog,name=Dialog,style=plain,size=12],color=sun.swing.PrintColorUIResource[r=51,g=51,b=51]]

whereas under OSX I get what I expected, which is:

Graphics is sun.java2d.SunGraphics2D[font=apple.laf.CUIAquaFonts$DerivedUIResourceFont[family=LucidaGrande,name=LucidaGrande,style=plain,size=13],color=javax.swing.plaf.ColorUIResource[r=0,g=0,b=0]]
Using my graphics - expect to see 'MyGraphics' next 
Graphics is MyGraphics

So what I can I do to ensure that in all cases I get 'MyGraphics' passed to the appropriate subcomponents?

+1  A: 

I don't know for sure, but I suspect that as swing is double-buffered by Java on Windows (rather than by the window manager on OS X), you won't draw to your graphics, but to the Graphics2D provided by the off-screen buffer, then blt to your graphics.

Pete Kirkham
+1  A: 

That's it! If I disable double buffering on the component before calling paint, and reenable it afterwards then everything works the way I need.

RepaintManager.currentManager(frame).setDoubleBufferingEnabled(false);
frame.paint(new MyGraphics());
RepaintManager.currentManager(frame).setDoubleBufferingEnabled(true);

Thanks.

Simon Andrews
Please add this information into your question! Or add a comment to Pete's answer.
furtelwart