2017-03-27 1 views
3

JDK 9 내 스윙 앱은 4k highdpi 및 정상 1080p 일반 dpi를 사용하는 Windows에서 잘 작동합니다. 라벨, Comboboxes 등 모두 멋지며 은 4k 화면에서 확대됩니다. 하지만 내 JPanel은 사용자 지정 이미지를 그립니다. 이 JPanel이 직접 드로잉을 처리하도록 배율을 비활성화 할 수 있습니까? 나는 apache-commons bicubic 보간을 사용하여 더 높은 스케일링되지 않은 해상도에 대한 자세한 내용을 그리지 만 상자 밖으로 크기가 조정되므로 그릴 "일반"치수 만 있습니다.jdk 9 특정 패널에 대해 높은 dpi 사용 안 함

종류는 자바 9 스케일링은 다음과 같이 작동하는 것 같다

답변

2

에 관하여 : 당신의 페인트 (구성 요소)() 메소드가 이미 조정됩니다 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 :P 
t.setToScale(1, 1); 
g.setTransform(t); 

정확한 치수, 예를 얻으려면 그리기 전에 한밤중에 전체 배경을 채우는 :이처럼한다면 난 그냥 만들어 8.


final int w = (int) Math.round(getWidth() * scaling); 

, 당신은 자바 9 에 자바를 원하는 결과를 얻어야한다 더 많은 사용자 정의 컴포넌트 설계 및/또는 원시 도면을 위해 노력하는 Java 개발자를위한 클래스입니다. 시스템의 화면 크기를 알아야하며 수동 크기 조정이 필요한 경우가 많습니다. Java 8 및 Java 9의 모든 확장 문제를 해결해야합니다. 여기에 있습니다 :

import javax.swing.*; 
import java.awt.*; 
import java.awt.geom.AffineTransform; 




/** 
* TL;DR: 
* <p> 
* Call GUIScaling.initialize() at application start on the Swing thread. 
* <p> 
* If you set your own Component font sizes or border sizes or window sizes, multiply them by 
* GUIScaling.GUISCALINGFACTOR_COMPONENTSANDFONTS and/or use the helper methods newDimension() and scaleForComponent(). 
* Works on Java 8 and 9. 
* <p> 
* If you do your own custom graphics and want to have control down to the actual pixel, create an instance of 
* GUIScalingCustomGraphics to obtain your Graphics2D at scaling 1 and your component's true physical width and height 
* (Which Java 9 reports differently!), and scale all your graphics using GUIScaling.GUISCALINGFACTOR_CUSTOMGRAPHICS 
* and/or use the helper method scaleForCustom(). The helper method scaleForRealComponentSize() can transform your mouse 
* coordinates to the real physical coordinate, which Java 9 reports differently! 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* <p> 
* GUIScaling class v[1, 2017-10-08 11!00 UTC] by dreamspace-president.com 
* <p> 
* This Swing class detects the system's display scaling setting, which is important to make your GUI and custom 
* graphics scale properly like the user wants it. On a 4K display, for example, you'd probably set 200% in your 
* system. 
* <p> 
* Not tested with Java less than 8! 
* <p> 
* On Java 8 (and with most but not all (e.g. no the default) LooksAndFeels), component sizes (e.g. JButton) and their 
* font sizes will scale automatically, but if you have a certain border width in mind, or decided for a certain min and 
* default window size or a certain font size, you have to upscale those on a non-100%-system. With this class, just 
* multiply the values with GUISCALINGFACTOR_COMPONENTSANDFONTS. Done. newDimension() and scaleForComponent() help with 
* that. 
* <p> 
* On Java 9, component sizes and their font sizes DO NOT SCALE from the perspective of the application, but in reality 
* they are scaled: A window set to 800x600 size will really be 1600x1200, but it will still report half this size when 
* asked. A border of 50 pixels will really be 100 pixels. A Graphics2D object (paint method etc.) will have a scaling 
* of 2! (Not if you just create a BufferedImage object and do createGraphics(), the scale here will be 1.) So, you 
* don't have to bother with GUI scaling here at all. YOU CAN STILL USE GUISCALINGFACTOR_COMPONENTSANDFONTS, because 
* this class will set it to 1 on Java 9. This is detected by indeed checking the scaling of a Graphics2D object. So, 
* your Java 8 and 9 component/font code will be exactly the same in regards to scaling. 
* <p> 
* CUSTOM GRAPHICS: If you do your own painting and want to insist on true physical pixels (in which case obviously 
* you'd have to scale your fonts with GUISCALINGFACTOR_CUSTOMGRAPHICS instead of GUISCALINGFACTOR_COMPONENTSANDFONTS), 
* on Java 9 you have to reset the scaling of the Graphics2D object the paint(Component)() method gives you from 2 to 1, 
* and (also Java 9) you have to adjust the width/height reported by your component. Both is done by making an instance 
* of GUIScalingCustomGraphics. You can do this blindly on Java 8 and 9, your code will stay the same. And then, apply 
* this class' GUISCALINGFACTOR_CUSTOMGRAPHICS to scale everything according to system settings. Or, instead of 
* insisting on true physical pixels, you could trust Java 9 and not mess with the initial scaling - but then you'd have 
* to distinguish whether you're dealing with Java 8 or 9, because on 8, you'd still have to scale your custom graphics. 
* In case you decide for this, use GUISCALINGFACTOR_COMPONENTSANDFONTS for your custom graphics instead of 
* GUISCALINGFACTOR_CUSTOMGRAPHICS because the former will be ***1*** on Java 9 but will be proper (e.g. 2.0 for a 200% 
* system) on Java 8. 
* <p> 
* A weird problem that comes with Java 9: If you use the mouse coordinates as reported by the system (instead of, say, 
* quasi-fix the physical mouse pointer invisibly at the screen center and make your own pointer based on coordinate 
* differences), you will have HALF THE USUAL RESOLUTION. On Java 8, a 3840x2160 screen will give you according mouse 
* coordinates, but on Java 9, you get half these coordinates (if the system is set to scaling 200%). While 
* scaleForRealComponentSize() helps correct this, a custom drawn mouse pointer will now step in 2 pixel distances, it 
* can not reach every individual pixel any longer. I wish they had updated the MouseEvent class accordingly with 
* additional float methods. 
*/ 
final public class GUIScaling { // INITIAL TOUCHING of this class MUST be on Swing thread! 


    /** 
    * Call this at the start of your application ON THE SWING THREAD. This initializes the class and hence its values. 
    */ 
    public static void initialize() { 

     System.err.println(""); // To make sure an obfuscator doesn't remove this method and its calls. 
    } 


    /** 
    * By calling this, you ALSO initialize the class, so you don't HAVE TO use initialize() in that case (but it really 
    * doesn't matter). And you can indeed set a LookAndFeel of your choice, even though initialization of this class 
    * also sets AND TEMPORARILY USES a LookAndFeel. 
    * 
    * @param intendedLAFIs ANYTHING, but ideally a LookAndFeel name or several. The first value that equalsIgnoreCase 
    *      an installed LookAndFeelInfo.getName() will be used. 
    */ 
    public static void setLookAndFeel(final String... intendedLAFIs) { 

     if (intendedLAFIs != null) { 
      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; 
         } 
        } 
       } 
      } 
     } 
    } 


    /** 
    * Convenience method, compatible with Java 8 and 9. 
    */ 
    public static Dimension newDimension(final int w, final int h) { 

     return new Dimension(scaleForComponent(w), scaleForComponent(h)); 
    } 


    /** 
    * @param x E.g. the width of a component, or the size of a border. 
    * @return x scaled by the necessary display scaling factor for components and fonts, compatible with Java 8 and 9. 
    */ 
    public static int scaleForComponent(final double x) { 

     return (int) Math.round(x * GUISCALINGFACTOR_COMPONENTSANDFONTS); 
    } 


    /** 
    * @param x E.g. the width of a rectangle being drawn in a paint() or paintComponent() override. 
    * @return x scaled by the necessary display scaling factor for custom graphics, compatible with Java 8 and 9. 
    */ 
    public static int scaleForCustom(final double x) { 

     return (int) Math.round(x * GUISCALINGFACTOR_CUSTOMGRAPHICS); 
    } 


    /** 
    * @param x E.g. the width as reported by a component. 
    * @return x scaled so that it represents real physical pixels, compatible with Java 8 and 9. 
    */ 
    public static int scaleForRealComponentSize(final double x) { 

     return (int) Math.round(x * GUISCALINGFACTOR_REALCOMPONENTSIZE); 
    } 


    /** 
    * For Java 9, but can blindly be used in Java 8, too. Ensures that the scaling of a paint(Component)()'s Graphics2D 
    * object is 1. Conveniently does the usual casting, too. 
    * <p> 
    * Also calculates the physical pixel width/height of the component, which is reported differently on Java 9 if the 
    * display scaling is not 100%. 
    */ 
    final public static class GUIScalingCustomGraphics { 


     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. 


     /** 
     * @param component NOT NULL. The component (e.g. JPanel or JFrame) whose paint() method you're overriding. 
     * @param graphics NOT NULL. The Graphics argument given to your paint() method. 
     */ 
     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(); 
      t.setToScale(1, 1); 
      g.setTransform(t); 
     } 


    } 




    final private static double JBUTTONFONTSIZE_ON_100PERCENTSCALE_JAVA8_W10_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC = 11.0; 

    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. 

    static { 

     // 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"); 

     final float jButtonFontSize_on_unknownScale_unknownJava_unknownOS_withLookAndFeelWindows = 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! 

       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) { 

      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; 

     } else { 

      final double factorPreliminary = jButtonFontSize_on_unknownScale_unknownJava_unknownOS_withLookAndFeelWindows/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_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); 

    } 

} 
관련 문제