Переопределите JComponent.getBaselineResizeBehavior (), но сохраните совместимость с Java5 - PullRequest
4 голосов
/ 05 января 2009

Для моего проекта Swing мне необходимо поддерживать Java 5 и Java 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() для компонента области просмотра (мой экземпляр Picture). И он будет вызывать getBaseline(), только если getBaselineResizeBehavior() вернет Component.BaselineResizeBehavior.CONSTANT_ASCENT.

Теперь моя проблема в том, что getBaselineResizeBehavior() - это метод Java6 JComponent, который я не могу реализовать в Java5, потому что он возвращает перечисление Component.BaselineResizeBehavior, которого нет в Java5.

Итак, мой вопрос (наконец-то): как я могу реализовать (или симулировать?) getBaselineResizeBehavior(), чтобы мой класс все еще мог компилироваться и работать в среде Java5?

Ответы [ 4 ]

2 голосов
/ 05 января 2009

Я бы сделал подкласс Picture, возможно, с именем PictureJava6, который реализует getBaselineResizeBehaviour (), и при создании экземпляров Picture, сделайте:

public Component pictureFactory() {
    if(javaVersion > "1.6") {
        return new PictureJava6();
    } else {
        return new Picture();
    }
}
2 голосов
/ 05 января 2009

как я могу реализовать (или симулировать?) getBaselineResizeBehavior () так что мой класс все еще может скомпилировать и запустить в Среда Java5?

Вы не можете скомпилировать это объявление метода с библиотекой Java 5, потому что тип Component.BaselineResizeBehaviour не существует:

public Component.BaselineResizeBehavior getBaselineResizeBehavior()

Вы должны скомпилировать с использованием Java 6. Ваши классы могут все еще работать на Java 5, если вы компилируете с целью 1.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");
    }

}

... можно скомпилировать и запустить следующим образом с помощью компилятора JDK javac :

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)
0 голосов
/ 05 января 2009

Я думаю, что возвращаемый тип не рассматривается как часть сигнатуры метода при разрешении виртуальных функций и перегрузок; возможно, вы можете определить свой «переопределяющий» метод для возврата объекта и отразить возвращаемое значение Enum в моем первом ответе. Поскольку вы компилируете в J5, это не будет конфликтом времени компиляции, но JVM все равно должна выбрать ваш метод для переопределения ... Это может или может вызвать исключение времени выполнения. Тем не менее, стоит попробовать.

Например:

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

Любой обработчик ошибок может быть System.out исключительно для отладки, поскольку он не будет вызываться, если вы не J6, поэтому при правильном кодировании отражение всегда должно работать, * если оно вызывается.

И я бы, конечно, прокомментировал этот метод, чтобы было очень ясно, что происходит.

0 голосов
/ 05 января 2009

Вы можете использовать отражение, чтобы попытаться получить возвращаемое значение 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 - он работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...