如何在Java中成功扩展Graphics

时间:2022-08-22 21:22:16

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.

我正在尝试创建一个通用图形导出工具,它通过实现Graphics接口来工作,并拦截和解释对其各种方法的调用。但是,虽然我可以成功地为单个组件执行此操作,但当我在包含其他组件的组件上使用它时,我的Graphics类正在被替换。奇怪的是,这只发生在Windows和Linux上。在OSX上它工作正常。

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

任何人都可以建议我如何确保它是我的原始Graphics类传递给所有子组件?

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.

我有一个简短的脚本,演示了根本问题。当我使用MyGraphics的实例显式调用paint时,我没有在JPanel中看到MyGraphics - 只是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:

在我的Windows系统上,输出是:

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:

而在OSX下,我得到了我的预期,即:

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?

那么我能做些什么来确保在所有情况下我都将“MyGraphics”传递给相应的子组件?

2 个解决方案

#1


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.

我不确定,但我怀疑,由于Windows上的Java(而不是OS X上的窗口管理器)对swing进行双缓冲,因此您不会绘制到图形,而是绘制到图形提供的图形。离屏缓冲区,然后blt到您的图形。

#2


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.

而已!如果我在调用paint之前禁用组件上的双缓冲,然后重新启用它,那么一切都按照我需要的方式工作。

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

Thanks.

#1


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.

我不确定,但我怀疑,由于Windows上的Java(而不是OS X上的窗口管理器)对swing进行双缓冲,因此您不会绘制到图形,而是绘制到图形提供的图形。离屏缓冲区,然后blt到您的图形。

#2


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.

而已!如果我在调用paint之前禁用组件上的双缓冲,然后重新启用它,那么一切都按照我需要的方式工作。

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

Thanks.