Вот решение, основанное на моем первоначальном прототипировании.
Я не доволен некоторыми частями, например правилами, для которых «Целые числа» и «Шрифты» для изменения очень «волшебны».Это одно место, которое я хотел бы услышать от других с большим количеством опыта 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;
}
}
часть закрытых вопросов имеет один из дерева четыре золотых флага (s) – mKorbel