(编辑:以大约2年的使用后的格式从我的库中粘贴了新版本。注释可能不是最新的,但是现在值得使用生产代码。)
Java 9中的缩放似乎是这样工作的:您的paint(Component)()方法收到一个 已经缩放 的Graphics2D对象 。
此外,组件的大小(例如myJframe.setSize(),myJPanel.getWidth())会 根据程序隐式 缩放 ,
这意味着当您在200%的桌面上说setSize(800,600)时,组件将为1600x1200,但getWidth /
getHeight将返回800/600。
我可以禁用此JPanel的缩放比例以处理自己的绘制吗?
要将“图形”对象“重置”为缩放比例1,请执行以下操作:
final Graphics2D g = (Graphics2D) graphics;final AffineTransform t = g.getTransform();final double scaling = t.getScaleX(); // Assuming square pixels :Pt.setToScale(1, 1);g.setTransform(t);
为了获得正确的尺寸,例如在绘制之前用黑色填充整个背景:
final int w = (int) Math.round(getWidth() * scaling);
如果这样做,您应该在Java 9 和 Java 8 上获得理想的结果。
我刚刚为Java开发人员创建了一个类,他们致力于实现更自定义的组件设计和/或原始图形,在这些应用程序中,应该知道系统的显示比例,并且经常需要手动比例。它应该解决Java
8和Java 9上的所有扩展问题。在这里:
import javax.swing.*;import java.awt.*;import java.awt.geom.AffineTransform;final public class GUIScaling { // INITIAL TOUCHING of this class MUST be on Swing thread! public static void initialize() { System.err.print(""); } public static void setLookAndFeelDefault() { // The last three (Nimbus etc.) DO NOT automatically scale their font sizes with the system's GUI scaling, // so using the font size in those cases to derive the scaling WILL FAIL. // Btw., the JButton font size at 100% Windows 10 system scaling is 11.0 in all cases but the last three. GUIScaling.setLookAndFeel("Windows", UIManager.getSystemLookAndFeelClassName(), UIManager.getCrossPlatformLookAndFeelClassName(), "Windows Classic", "Nimbus", "metal", "CDE/Motif"); } public static void setLookAndFeel(final String... intendedLAFIs) { if (intendedLAFIs != null && intendedLAFIs.length > 0) { final UIManager.LookAndFeelInfo[] installedLAFIs = UIManager.getInstalledLookAndFeels(); LAFILOOP: for (String intendedLAFI : intendedLAFIs) { for (final UIManager.LookAndFeelInfo lafi : UIManager.getInstalledLookAndFeels()) { if (lafi.getName().equalsIgnoreCase(intendedLAFI)) { try { UIManager.setLookAndFeel(lafi.getClassName()); break LAFILOOP; } catch (Exception e) { continue LAFILOOP; } } } } } else { throw new IllegalArgumentException("intendedLAFIs is null or empty."); } } public static Dimension newDimension(final int w, final int h) { return new Dimension(scaleForComponent(w), scaleForComponent(h)); } public static int scaleForComponent(final double v) { return (int) Math.round(v * GUISCALINGFACTOR_COMPONENTSANDFONTS); } public static int scaleForCustom(final double v) { return (int) Math.round(v * GUISCALINGFACTOR_CUSTOMGRAPHICS); } public static int scaleForRealComponentSize(final double v) { return (int) Math.round(v * GUISCALINGFACTOR_REALCOMPONENTSIZE); } public static Font scaleFontForCustom(final Font font) { if (font != null) { return font.deriveFont(font.getSize2D() * (float) GUISCALINGFACTOR_REALCOMPONENTSIZE); } return null; } final public static class GUIScalingCustomGraphics { final public double guiScalingFactor_manualDrawing = GUISCALINGFACTOR_CUSTOMGRAPHICS; final public double guiScalingFactor_fontsThatLookCorrectInComponents = GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT; final public Component component; // Just for convenience. You can hand the whole instance down your paint call hierarchy. final public int w; // The physical pixel width of the component. final public int h; // dto. height final public Graphics2D g; // Scale will be 1, even on Java 9 with a non-100% display scaling. public GUIScalingCustomGraphics(final Component component, final Graphics graphics) { this.component = component; w = scaleForRealComponentSize(component.getWidth()); h = scaleForRealComponentSize(component.getHeight()); g = (Graphics2D) graphics; final AffineTransform t = g.getTransform(); final double xTrans = t.getTranslateX(); final double yTrans = t.getTranslateY(); t.setToScale(1, 1); t.translate(xTrans, yTrans); g.setTransform(t); } public GUIScalingCustomGraphics(final Graphics graphics) { component = null; w = 0; h = 0; g = (Graphics2D) graphics; final AffineTransform t = g.getTransform(); t.setToScale(1, 1); g.setTransform(t); } public int scale(final double x) { return (int) Math.round(x * guiScalingFactor_manualDrawing); } public Font setFont(final Font font) { final Font ret = font == null ? null : font.deriveFont(font.getSize2D() * (float) guiScalingFactor_fontsThatLookCorrectInComponents); g.setFont(ret); return ret; } @Override public String toString() { return "[GUIScalingCustomGraphics" + " guiScalingFactor_manualDrawing=" + guiScalingFactor_manualDrawing + " w=" + w + " h=" + h + " component=" + component + " g=" + g + ']'; } } final private static double JBUTTONFONTSIZE_ON_100PERCENTSCALE_JAVA8_W10_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC = 11.0; final public static float JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC; final public static double GUISCALINGFACTOR_SYSTEM; // The scaling set in the system. final public static double GUISCALINGFACTOR_COMPONENTSANDFONTS; // The scaling necessary if you set component/font sizes yourself. final public static double GUISCALINGFACTOR_CUSTOMGRAPHICS; // The scaling necessary if you want your custom graphics, too, to be scaled according to System settings. final public static double GUISCALINGFACTOR_REALCOMPONENTSIZE; // The factor by which getWidth() and such return values have to be multiplied, because Java 9 reports them differently. final public static double GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT; // (This is exactly the custom graphics scaling probed by this class.) The factor by which a proper looking font would have to be scaled when used in custom graphics whose scale is 1. (Java 9 pre-scales it to e.g. 2 if Desktop is at 200%, then you reset that with the class above. Then the fonts that look right in the components will be TOO SMALL in the custom graphics. Use this factor / the method above to fix that.) static { if (!SwingUtilities.isEventDispatchThread()) { // This also makes sure an obfuscator doesn't remove this method and its calls. throw new IllegalStateException("Must be initialized on Swing thread!"); } System.err.println("Initializing GUI scaling ..."); GUIScaling.setLookAndFeelDefault(); JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC = new JButton().getFont().getSize2D(); // 21.0 on 200% desktop on Java 8 // 11.0 on 100% desktop on Java 8 final Integer[] paintScalingInPercent = new Integer[1]; final JDialog bruteForceJava9ScalingCheck = new JDialog((frame) null, "", true) { { // setLocation(-1000, -1000); // Outamysight! setLocation(100, 100); // else you might have compatibility problems (see stackoverflow where I posted this class) final Runnable fallbackInCaseOlderJavaVersionDoesNotEndUpClosingThisWindow = () -> { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } SwingUtilities.invokeLater(() -> { paintScalingInPercent[0] = 100; dispose(); }); }; final Thread t = new Thread(fallbackInCaseOlderJavaVersionDoesNotEndUpClosingThisWindow); t.setDaemon(true); t.setName("GUI scaling detector fallback thread"); t.start(); } @Override public void paint(final Graphics graphics) { final Graphics2D g = (Graphics2D) graphics; final AffineTransform originalTransform = g.getTransform(); paintScalingInPercent[0] = (int) Math.round(originalTransform.getScaleX() * 100); dispose(); } }; bruteForceJava9ScalingCheck.setVisible(true); // This call blocks until dispose() is reached. if (paintScalingInPercent[0] == null) { throw new Error("Unexpected behavior: Modal dialog did not block!"); } else if (paintScalingInPercent[0] != 100) { // Must be Java 9 (or newer?). GUISCALINGFACTOR_SYSTEM = paintScalingInPercent[0] * 0.01; GUISCALINGFACTOR_COMPonENTSANDFONTS = 1; // Java 9 does everything. The developer's considerations are made unnecessary/harmless by this "1". GUISCALINGFACTOR_CUSTOMGRAPHICS = GUISCALINGFACTOR_SYSTEM; GUISCALINGFACTOR_FonTINCUSTOMGRAPHICSCONTEXT = GUISCALINGFACTOR_SYSTEM; } else { // Either Java 8 (or older?) or scaling IS just at the normal 1 (100). final double factorPreliminary = JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC / JBUTTONFONTSIZE_ON_100PERCENTSCALE_JAVA8_W10_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC; // If we just divide the two, we get 1.454545... on a 150% desktop, because the font sizes // chosen by Java are integer values, so we experience a rounding error. // The crappy but probably in most cases nicely working solution is: We round the result to .25 steps! GUISCALINGFACTOR_SYSTEM = Math.round(factorPreliminary * 4) / 4d; GUISCALINGFACTOR_COMPonENTSANDFONTS = GUISCALINGFACTOR_SYSTEM; GUISCALINGFACTOR_CUSTOMGRAPHICS = GUISCALINGFACTOR_SYSTEM; GUISCALINGFACTOR_FonTINCUSTOMGRAPHICSCONTEXT = 1; // No font scaling, the fonts used will look correct in custom scaling without extra treatment. } GUISCALINGFACTOR_REALCOMPonENTSIZE = GUISCALINGFACTOR_CUSTOMGRAPHICS / GUISCALINGFACTOR_COMPONENTSANDFONTS; // System.err.println("GUISCALINGFACTOR_SYSTEM = " + GUISCALINGFACTOR_SYSTEM); // System.err.println("GUISCALINGFACTOR_COMPonENTSANDFONTS = " + GUISCALINGFACTOR_COMPONENTSANDFONTS); // System.err.println("GUISCALINGFACTOR_CUSTOMGRAPHICS = " + GUISCALINGFACTOR_CUSTOMGRAPHICS); // System.err.println("GUISCALINGFACTOR_REALCOMPonENTSIZE = " + GUISCALINGFACTOR_REALCOMPONENTSIZE); System.err.println("... done."); }}


