Simon Andrews
Simon Andrews

Reputation: 427

How can I successfully extend Graphics in Java

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?

Upvotes: 4

Views: 3373

Answers (2)

Simon Andrews
Simon Andrews

Reputation: 427

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.

Upvotes: 1

Pete Kirkham
Pete Kirkham

Reputation: 49321

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.

Upvotes: 1

Related Questions