2016-07-03 16 views
4

Я ищу, чтобы добавить поддержку Hi-DPI некоторым приложениям Swing, но мне не удалось найти решение, достаточное для моих нужд. Мне нужно поддерживать многократный взгляд &, поэтому ситуация кажется более сложной, чем другие найденные мной сообщения (которые, как правило, предлагают «адаптировать размеры пользовательского интерфейса в соответствии с вашим размером шрифта»).Поддержка HiDPI в Java Swing для множественного внешнего вида

Некоторые эксперименты обнаружили, что UIManager содержит множество показателей, которые можно настроить, чтобы вы могли начать с приложения Hi-DPI. (Утилита UIManager-Defaults неоценима для изучения этих!) То, что я нашел, однако, что L & Fs, кажется, работает полностью по-разному друг к другу:

  • Окно L & F дает хорошее (не идеальный) размер шрифта по умолчанию, а встроенные значки (например, флажок & значки окна) имеют размер соответственно, но многие другие показатели все еще не в порядке.

  • In Metal вы можете обновлять шрифты в UIManager отдельно. С небольшим количеством работы вы можете масштабировать встроенный IconUIResource s для соответствия.

  • В Nimbus вы можете просто обновить один шрифт по умолчанию, а другие шрифты встать на свои места ... но это вне меня, как масштабировать встроенные значки и иметь комбинированные поля, переключатели (и т. Д.) успешно!

чувство я получаю от игры вокруг в том, что она должна быть возможность создать список конкретных настроек для каждого L & F конкретных независимо друг от друга. Это будет включать потенциальную настройку значений по умолчанию для Font, Icon, Integer и Dimension s.

Кто-нибудь придумал хорошее решение?

Может ли кто-нибудь поделиться окончательным списком, из которого UIDefaults нужна настройка для стандарта L & Fs?

Я был бы доволен решением, которое просто поддерживает металл и Windows.

Я предполагаю, что такое решение должно быть вполне многоразовым & может решить ту же проблему для ряда приложений Swing. Я удивлен, что такая утилита пока не существует. (Пожалуйста, просветите меня, если нет!) Этот подход не будет решать все, конечно (например, вам все равно придется вручную набирать любые звонки на setPreferredSize и т. Д. Затем снова приложения, которые уже поддерживают mulitple L & Fs, должны избегать вызова этого в любом случае.) Тем не менее, я полагаю, что это может заставить много приложений отключиться.

Я знаю, что JDK-9 обещает полный Hi-DPI support, но я не могу дождаться этого долго - я, возможно, не смогу переключиться на некоторое время даже после выпуска 2017 года.

+0

часть закрытых вопросов имеет один из дерева четыре золотых флага (s) – mKorbel

ответ

1
  • не ответ, только мое понимание в этот вопрос проблематики, и, пожалуйста, не удаляйте этот ответ, он может быть очень информативным для следующего, два года,

  • моих точек, (Я ограничить ленивый пользователь Win, может быть интересен опыт пользователей реальной мощности от LI/(U) Nix или OSX)

    1. , как правило, возвращается обратно использовать NullLayout, несмотря на то, что UIManager (I думаю, что это все еще правда) умеет обрабатывать с getPreferredSize 21k x 48k, bu t выглядит так, как LayoutManager не знает, чтобы правильно разделить эти значения, вы можете это увидеть, эта проблема вы можете увидеть, используя GridBagLayout, есть проблема с масштабированием/масштабированием для 4k sceens, я думаю, что графический интерфейс AWT/Swing коррекция на мониторах 2k,

    2. для экранов 2k/4k вам необходимо переопределить все ключи в UIManager (например, AFAIK для Nimbus L & F можно использовать структуру, сохраненную в XML-файл непосредственно)

      • должны создать свой собственный PaintIcon (в AWT/Swing используются простые формы)
      • переопределение Границы
      • переопределение событий мыши
      • переопределения Фокус события
    3. этих шаги частично необходимы для «гладкого» GUI в сегодняшних мках тоже из старых 4: 3 экранов -> мыслительных ноутбуков с СВЫМ ll_screens с низким разрешением (HD_screens) -> fullhd screen -> fullhs wide sceen, заканчивается 2k экраном, заметьте, что я никогда не пробовал использовать калибровочные варисторы в Nimbus L & F, профессиональное приложение должно содержать тест, проверка на

      • Native OS (есть разница Betweens шрифта, границы, калибровка)
      • получить разрешение экрана в пикселях от основного дисплея с экрана scalling, например, особенно FullHD экран (16: 9) и широкий экран FullHD (21: 9)
      • для кэширования всех дисплеев в случае, если у вас есть несколько мониторов и разрешение в пикселях, различно (проблема в том, что есть два одинаковых монитора, но есть установка с уменьшением - настройки пользователей на GPU или монитор с активной ТВ-картой - настройки могут быть изменены с помощью ТВ-чипа)

      • тогда GUI может быть создан с жестко запрограммированной матрицей для различных размеров, для подгонки все стандарты экрана по умолчанию с успехом переопределения GetPreferredSize для (родительского) контейнера (ов), то LayoutManager примет GetPreferredSize формы жёстко прописанную матрицы в качестве прототипа и сделать собственную работу правильно,

    4. если я помню еще интересные факты , ошибки и т. д. ... и т. д. Я отредактирую этот мой более длинный комментарий, с моими замечаниями

+0

Ваш вопрос только о том, что у пользователей Windows есть именно то, почему я ожидал/надеялся, что какая-то общая утилита должна существовать к настоящему времени, а не все, r собственный. Отдельные разработчики могут тестировать только многие конфигурации платформы + L & F. –

+0

Я немного смущен - если вы переопределяете значения в UIManager (размеры, которые я предполагаю?), То почему вам также необходимо переопределить события мыши и фокуса? Это потому, что вы также масштабируете графический интерфейс при рисовании? –

+0

пункт 2nd. (уже отредактировано всего около 2/4k экранов), необходимо масштабировать тиканье границ и/или вместе с фокусом (hover_over) от события мыши, в конечном счете от ключевого события, значки просты доступны из собственного класса, который реализует paintIcon – mKorbel

1

Вот решение, основанное на моем первоначальном прототипировании.

Я не доволен некоторыми частями, например правилами, для которых «Целые числа» и «Шрифты» для изменения очень «волшебны».Это одно место, которое я хотел бы услышать от других с большим количеством опыта Swing/L & F.

Я создал эту вики сообщества, чтобы, если бы люди предпочли повторять это и добавлять свои знания, а не публиковать свои собственные решения, тогда, пожалуйста, не стесняйтесь.

Я начал с интерфейсом, который может изменить некоторые UI-умолчанию:

public interface Tweaker { 
    void initialTweaks(); 
    Font modifyFont(Object key, Font original); 
    Icon modifyIcon(Object key, Icon original); 
    Integer modifyInteger(Object key, Integer original); 
} 

который может быть вызван следующим образом:

public void scaleUiDefaults() { 
    float dpiScale = Toolkit.getDefaultToolkit().getScreenResolution()/96f; 
    Tweaker delegate = createTweakerForCurrentLook(dpiScale); 
    tweakUiDefaults(delegate, dpiScale); 
} 

private Tweaker createTweakerForCurrentLook(float dpiScaling) { 
    String testString = UIManager.getLookAndFeel().getName().toLowerCase(); 
    if (testString.contains("windows")) return new WindowsTweaker(dpiScaling); 
    if (testString.contains("nimbus")) return new NimbusTweaker(dpiScaling); 
    return new BasicTweaker(dpiScaling); 
} 

private void tweakUiDefaults(Tweaker delegate, float multiplier) { 
    UIDefaults defaults = UIManager.getLookAndFeelDefaults(); 

    delegate.initialTweaks(); 

    for (Object key: Collections.list(defaults.keys())) { 
    Object original = defaults.get(key); 
    Object newValue = getUpdatedValue(delegate, key, original); 
    if (newValue != null && newValue != original) { 
     defaults.put(key, newValue); 
    } 
    } 
} 

private Object getUpdatedValue(Tweaker delegate, Object key, Object original) { 
    if (original instanceof Font) return delegate.modifyFont(key, (Font) original); 
    if (original instanceof Icon) return delegate.modifyIcon(key, (Icon) original); 
    if (original instanceof Integer) return delegate.modifyInteger(key, (Integer) original); 
    return null; 
} 

Я поставил функциональность, которая выглядит для использования большинством L & Fs в базовом классе. Это, кажется, для обработки металла без дальнейшего уточнения:

public class BasicTweaker { 
    protected final float scaleFactor; 
    protected final UIDefaults uiDefaults = UIManager.getLookAndFeelDefaults(); 

    public BasicTweaker(float scaleFactor) { 
    this.scaleFactor = scaleFactor; 
    } 

    public void initialTweaks() {} 

    public Font modifyFont(Object key, Font original) { 

    // Ignores title & accelerator fonts (for example) 
    if (original instanceof FontUIResource && key.toString().endsWith(".font")) { 
     return newScaledFontUIResource(original, scaleFactor); 
    } 
    return original; 
    } 

    protected static FontUIResource newScaledFontUIResource(Font original, float scale) { 
    int newSize = Math.round(original.getSize() * scale); 
    return new FontUIResource(original.getName(), original.getStyle(), newSize); 
    } 

    public Icon modifyIcon(Object key, Icon original) { 
    return new IconUIResource(new ScaledIcon(original, scaleFactor)); 
    } 

    public Integer modifyInteger(Object key, Integer original) { 
    if (!endsWithOneOf(lower(key), LOWER_SUFFIXES_FOR_SCALED_INTEGERS)) { 
     return original; 
    } 
    return (int) (original * scaleFactor); 
    } 

    private boolean endsWithOneOf(String text, String[] suffixes) { 
    return Arrays.stream(suffixes).anyMatch(suffix -> text.endsWith(suffix)); 
    } 

    private String lower(Object key) { 
    return (key instanceof String) ? ((String) key).toLowerCase() : ""; 
    } 

    private static final String[] LOWER_SUFFIXES_FOR_SCALED_INTEGERS = 
    new String[] { "width", "height", "indent", "size", "gap" }; 
} 

класса ScaledIcon используемых выше, вероятно, выходит за рамки - но это по сути просто вызывает ImageIcon(image).paintIcon с измененной шириной & высотой.

Затем переопределить BasicTweaker для других L & Fs ...

Windows:

public class WindowsTweaker extends BasicTweaker { 

    public WindowsTweaker(float scaleFactor) { 

    // Windows already scales fonts, scrollbar sizes (etc) according to the system DPI settings. 
    // This lets us adjust to the REQUESTED scale factor, relative to the CURRENT scale factor 
    super(scaleFactor/getCurrentScaling()); 
    } 

    private static float getCurrentScaling() { 
    int dpi = Toolkit.getDefaultToolkit().getScreenResolution(); 
    return dpi/96f; 
    } 

    public Font modifyFont(Object key, Font original) { 
    return super.modifyFont(key, original); 
    } 

    public Icon modifyIcon(Object key, Icon original) { 
    return original; 
    } 
} 

Nimbus:

public class NimbusTweaker extends BasicTweaker { 

    public NimbusTweaker(float scaleFactor) { 
    super(scaleFactor); 
    } 

    public void initialTweaks() { 
    Font font = uiDefaults.getFont("defaultFont"); 
    if (font != null) { 
     uiDefaults.put("defaultFont", new FontUIResource(
      font.getName(), font.getStyle(), Math.round(font.getSize() * scaleFactor))); 
    } 
    } 

    // Setting "defaultFont" above is sufficient as this will be inherited by all others 
    public Font modifyFont(Object key, Font original) { 
    return original; 
    } 

    // Scaling Radio or CheckBox button icons leads to really weird artifacts in Nimbus? Disable 
    public Icon modifyIcon(Object key, Icon original) { 
    return original; 
    } 
} 
+0

ваше приложение должно быть уверенным в Native OS и разрешении экрана, в большинстве случаев лучше играть с несколькими дисплеями, прежде чем GUI будет создан, настройте, а затем увидите, что с этой информацией я отредактирую свою третью. – mKorbel

+0

Спасибо! Примечание. Я счастлив принять один и тот же DPI на всех мониторах. Тем не менее, я по-прежнему интересуюсь тем, как поддерживать определенный DPI. Какой код я могу использовать для получения DPI отдельных экранов? Я не смог найти эту информацию через API JDK-8. –

 Смежные вопросы

  • Нет связанных вопросов^_^