覆盖 JComponent.getBaselineResizeBehavior() 但保持 Java5 兼容性

发布于 2024-07-11 09:09:24 字数 1331 浏览 14 评论 0 原文

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

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() (我的 <代码>图片实例)。 仅当 getBaselineResizeBehavior() 返回 Component.BaselineResizeBehavior.CONSTANT_ASCENT 时,它才会调用 getBaseline()

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

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

For my Swing project, I need to support both Java 5 and Java 6.
I have defined a custom JComponent (call it Picture) and, after embedding it in a JScrollPane, I put it in a JPanel that uses DesignGridLayout manager.

DesignGridLayout supports baseline alignment thanks to swing-layout open source library (implements baseline support for Java 5 and provides compatibility with the new Java 6 baseline support).

My Picture class overrides public int getBaseline(int width, int height) so that I can define a correct baseline for it. Note that "override" is not completely correct: it overrides the method on Java6 but defines it in Java5.

When I run my sample app on Java5, everything is fine: the Picture baseline I have defined is correctly used.

However, when I use Java6, my Picture#getBaseline() method does not get called! And of course the baseline alignment of my picture is terrible (centered).

After checking in Java6 source, I have seen that, in BasicScrollPaneUI, getBaseline() calls first getBaselineResizeBehavior() on the viewport component (my Picture instance).
And it will call getBaseline() only if getBaselineResizeBehavior() returns Component.BaselineResizeBehavior.CONSTANT_ASCENT.

Now my problem is that getBaselineResizeBehavior() is a Java6 method of JComponent that I cannot implement in Java5 because it returns an enum Component.BaselineResizeBehavior which does not exist in Java5.

So my question (finally) is: how can I implement (or simulate?) getBaselineResizeBehavior() so that my class can still compile and run in a Java5 environment?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乜一 2024-07-18 09:09:25

您可以使用反射来尝试按名称获取 CONSTANT_ASCENT 返回值。 如果不能体现出来,你就是J5,否则就是J6。 这回避了显式依赖并允许编译到 J5。

福尔。 是针对对话框模式执行此操作的示例:

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 中不起作用,从而混淆了问题 - 它确实如此。

You can use reflection to try to get the CONSTANT_ASCENT return value by name. If it can't be reflected, you are J5, otherwise J6. This side-steps the explicit dependency and allows compilation to J5.

Foll. is an example of doing this for dialog modality:

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);
    }

UPDATE: I originally posted code with the J5 code commented out; I've changed that because I realized it confuses the issue by implying that the J5 code would not work in J6 - it does.

陪我终i 2024-07-18 09:09:25

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

例如:

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

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

当然,我会评论这个方法,以使其非常清楚发生了什么。

I think that the return type is not treated as part of the a method signature in resolving virtual functions and overloads; it might be that you can define your "overriding" method to return Object, and reflect out the return Enum per my first answer. Since you're compiling in J5 it won't be a compile time conflict, but the JVM should still choose your method to override... It might or it might throw a runtime exception. Still, it's worth a try.

For example:

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

Any error handling can be System.out, purely for debugging, since this will not be invoked unless you are J6, so the reflection, correctly coded, should always work if invoked.

And I would, of course, comment this method to make it very clear what's going on.

空‖城人不在 2024-07-18 09:09:24

我将创建一个 Picture 的子类,可能称为 PictureJava6,它实现 getBaselineResizeBehaviour(),并在创建 Picture 实例时执行以下操作:

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

I would make a subclass of Picture, perhaps called PictureJava6, which implemented the getBaselineResizeBehaviour(), and when creating instances of Picture, do:

public Component pictureFactory() {
    if(javaVersion > "1.6") {
        return new PictureJava6();
    } else {
        return new Picture();
    }
}
西瓜 2024-07-18 09:09:24

我如何实现(或模拟?)
getBaselineResizeBehavior() 这样我的
类仍然可以编译并在
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)

how can I implement (or simulate?)
getBaselineResizeBehavior() so that my
class can still compile and run in a
Java5 environment?

You cannot compile this method declaration with the Java 5 library because the type Component.BaselineResizeBehaviour does not exist:

public Component.BaselineResizeBehavior getBaselineResizeBehavior()

You must compile using Java 6. Your classes can still run on Java 5 if you compile to a 1.5 target, but you must take care that they handle absent types/methods gracefully. Add tests for these cases as you encounter them. Ensure developers attempt to run their code on Java 5 prior to check-in.

For example, this class...

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");
    }

}

...can be compiled and run as follows using the javac JDK compiler:

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

All the popular IDEs offer options for generating older class versions. You can use reflection to test for the existence of methods/types at runtime when you need to make decisions about code paths.

Failure to set the target will result in errors like this:

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文