gpt4 book ai didi

java - Java Swing 中的 HiDPI 支持提供多种外观和感觉

转载 作者:搜寻专家 更新时间:2023-11-01 03:18:46 25 4
gpt4 key购买 nike

我希望为某些 Swing 应用程序添加 Hi-DPI 支持,但我未能找到足以满足我需求的解决方案。我需要支持多种外观和感觉,因此情况似乎比我发现的其他帖子更复杂(这些帖子倾向于建议“调整您的 UI 大小以匹配您的字体大小”)。

一些实验发现 UIManager 包含许多可以调整的指标,让您在使应用程序 Hi-DPI 友好方面有一个良好的开端。 (UIManager-Defaults 实用程序对于探索这些非常有用!)但我发现 L&F 似乎完全彼此不同地工作:

  • Windows L&F 为您提供了一个不错的(不完美的)默认字体大小,并且内置图标(如复选框和窗口图标)的大小适当 - 但许多其他指标仍然不正常。

  • 在 Metal 中,您可以单独更新 UIManager 中的字体。通过一些工作,您可以缩放内置的 IconUIResource 以匹配。

  • 在 Nimbus 中,你可以只更新一个默认字体,其他字体就位了......但是我不知道如何缩放内置图标并使用组合框、单选按钮(等等)。 ) 渲染成功!

我从玩弄中得到的感觉是,应该可以为每个 L&F 独立创建一个特定调整的列表。这可能包括调整 FontIconIntegerDimension 的默认值。

有没有人想出好的解决办法?

谁能分享一份明确的列表,其中列出了哪些 UIDefaults 需要针对标准 L&F 进行调整?

我会很高兴有一个始终支持 Metal 和 Windows 的解决方案。

我想这样的解决方案应该是完全可重用的,并且可以为一系列 Swing 应用程序解决同样的问题。我很惊讶似乎还没有这样的实用程序。这种方法当然不会解决所有问题(例如,您仍然需要手动缩放对 setPreferredSize 等的任何调用。然后,已经支持多个 L&F 的应用程序应该尽量避免调用它。)不过,我认为它可以让许多应用程序有一个良好的开端。

我知道 JDK-9 promise 满Hi-DPI support ,但我不能等那么久 - 即使在 2017 年发布之后,我也可能有一段时间无法切换。

更新:是的 JDK-9 以后启用 HiDPI 支持,但是内置非整数缩放级别的 L&F 并没有很好地接受它并且看起来很均匀比“用 Java 8 自己破解它”更糟糕。这个问题可以在 L&F 级别得到更好的解决,但是,一些优秀的第 3 方 L&F's like FlatLaFRadiance做得很漂亮。强烈推荐。

最佳答案

这是基于我最初的原型(prototype)设计的解决方案。

我对某些部分不满意,例如修改“整数”和“字体”的规则非常“神奇”。这是我希望从其他人那里听到更多 Swing/L&F 经验的地方。

我已将其设为社区 Wiki,这样如果人们更愿意对此进行迭代并增加他们的知识,而不是发布他们自己的解决方案,那么请随意。

我从一个可以修改某些 ui-defaults 的界面开始:

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&F 使用的功能放在基类中。这似乎无需进一步改进即可处理 Metal:

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" };
}
上面使用的

class ScaledIcon 可能超出范围 - 但它本质上只是调用 ImageIcon(image).paintIcon 并修改了宽度和高度。

然后为其他 L&F 覆盖 BasicTweaker...

window :

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

雨云:

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

关于java - Java Swing 中的 HiDPI 支持提供多种外观和感觉,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38169983/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com