重写JComponent.getBaselineResizeBehavior()但保持Java5兼容性

时间:2009-01-05 00:26:17

标签: java swing baseline

对于我的Swing项目,我需要同时支持 Java 5 Java 6 。 我已经定义了一个自定义JComponent(称之为Picture),并且在将其嵌入JScrollPane之后,我将其放入使用DesignGridLayout管理器的JPanel中。

DesignGridLayout支持基线对齐,这要归功于 swing-layout 开源库(实现对Java 5的基线支持,并提供与新Java 6基线支持的兼容性)。

我的Picture会覆盖 public int getBaseline(int width, int height),以便我可以为其定义正确的基线。请注意,“ override ”并不完全正确:它会覆盖Java6上的方法,但在Java5中定义它。

当我在Java5上运行我的示例应用时,一切都很好:我已正确使用我定义的Picture基线。

但是,当我使用Java6 时,我的Picture#getBaseline()方法无法被调用!当然我的图片的基线对齐很糟糕(居中)。

在检查Java6源代码后,我已经看到,在BasicScrollPaneUI中,getBaseline()在视口组件(我的getBaselineResizeBehavior()实例)上首先调用Picture。 仅当getBaseline()返回getBaselineResizeBehavior()时,它才会调用Component.BaselineResizeBehavior.CONSTANT_ASCENT

现在我的问题是getBaselineResizeBehavior()JComponent的Java6方法,我无法在Java5中实现,因为它返回了Java5中不存在的枚举Component.BaselineResizeBehavior

所以我的问题(最后)是:我如何实现(或模拟?)getBaselineResizeBehavior()以便我的类仍然可以在Java5环境中编译和运行?

4 个答案:

答案 0 :(得分:2)

  

我该如何实现(或模拟?)   getBaselineResizeBehavior()让我的   class仍然可以编译并在a中运行   Java5环境?

您无法使用Java 5库编译此方法声明,因为类型Component.BaselineResizeBehaviour不存在:

public Component.BaselineResizeBehavior getBaselineResizeBehavior()

您必须使用Java 6进行编译。如果您编译为1.5目标,您的类仍然可以在Java 5上运行,但您必须注意它们正常处理缺少的类型/方法。遇到这些情况时,请为这些情况添加测试。确保开发人员在签入之前尝试在Java 5上运行他们的代码。

例如,这个班级......

public class MyPanel extends javax.swing.JPanel {

    public java.awt.Component.BaselineResizeBehavior getBaselineResizeBehavior() {
        return java.awt.Component.BaselineResizeBehavior.OTHER;
    }

    public static void main(String[] args) {
        new MyPanel();
        System.out.println("OK");
    }

}

...可以使用javac JDK编译器编译和运行如下:

X:\fallback>javac -version
javac 1.6.0_05

X:\fallback>javac -target 1.5 MyPanel.java

X:\fallback>"C:\Program Files\Java\jre1.5.0_10\bin\java.exe" -cp . MyPanel
OK

所有流行的IDE都提供了生成旧版本的选项。当您需要对代码路径做出决策时,可以使用反射在运行时测试方法/类型的存在。

未能设置目标将导致如下错误:

Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version n
umber in .class file
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)

答案 1 :(得分:2)

我会创建一个Picture的子类,也许叫做PictureJava6,它实现了getBaselineResizeBehaviour(),在创建Picture的实例时,执行:

public Component pictureFactory() {
    if(javaVersion > "1.6") {
        return new PictureJava6();
    } else {
        return new Picture();
    }
}

答案 2 :(得分:0)

您可以使用反射尝试按名称获取CONSTANT_ASCENT返回值。如果无法反映,则为J5,否则为J6。这侧面显式依赖,允许编译到J5。

FOLL。是对话模态执行此操作的示例:

try {
    Field  fld=Class.forName("java.awt.Dialog$ModalExclusionType").getField("TOOLKIT_EXCLUDE");
    Method mth=getClass().getMethod("setModalExclusionType",new Class[]{fld.getType()});
    mth.invoke(this,new Object[]{fld.get(null)});
    }
catch(Throwable thr) {
    log.errorln("Unable to configure window to be unaffected by modal dialogs - dialogs may need to be closed to operate help.");
    log.errorln("Use Java 6 or later to avoid modal dialogs conflicting with the help system.");
    log.errorln("Exception: "+thr);
    }

更新:我最初发布了J5代码注释掉的代码;我已经改变了,因为我意识到它混淆了这个问题,暗示J5代码在J6中不起作用 - 确实如此。

答案 3 :(得分:0)

我认为在解决虚函数和重载时,返回类型不被视为方法签名的一部分;可能是你可以定义你的“覆盖”方法来返回Object,并反映出我的第一个答案的返回枚举。由于您在J5中编译它不会是编译时冲突,但JVM仍应选择您的方法来覆盖...它可能或它可能会引发运行时异常。不过,值得一试。

例如:

public Object getBaselineResizeBehavior() {
    Object ret;
    // reflect out the return value
    return ret;
    }  

任何错误处理都可以是System.out,纯粹用于调试,因为除非你是J6,否则不会调用它,因此正确编码的反射应该在调用时始终有效。

当然,我会评论这种方法,以便清楚地说明发生了什么。