Как «правильно» обнаружить DPI дисплея с Java?

У меня есть следующее приложение, которое рисует правило:

public class Rule extends JComponent { public static final long serialVersionUID=26362862L; // public static final int INCH=Toolkit.getDefaultToolkit().getScreenResolution(); public static final int INCH=(int)(Toolkit.getDefaultToolkit().getScreenResolution()*1.15); // Auto adjust this 1.15 ? public static final int HORIZONTAL=0; public static final int VERTICAL=1; public static final int SIZE=35; public int orientation; public boolean isMetric; private int increment; private int units; // private Color rule_color=new Color(0,135,235); private Color rule_color=new Color(120,170,230); static JFrame frame=new JFrame("Rule"); static Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize(); // 1600 x 1200 , 1024 x 768 static JPanel rulerPanel=new JPanel(new BorderLayout()); public Rule(int o,boolean m) { orientation=o; isMetric=m; setIncrementAndUnits(); } public void setIsMetric(boolean isMetric) { this.isMetric=isMetric; setIncrementAndUnits(); repaint(); } private void setIncrementAndUnits() { if (isMetric) { units=(int)((double)INCH/(double)2.54); // dots per centimeter increment=units; } else { units=INCH; increment=units/2; } } public boolean isMetric() { return this.isMetric; } public int getIncrement() { return increment; } public void setPreferredHeight(int ph) { setPreferredSize(new Dimension(SIZE,ph)); } public void setPreferredWidth(int pw) { setPreferredSize(new Dimension(pw,SIZE)); } public void setColor(Color color) { rule_color=color; } public void paintComponent(Graphics g) { Rectangle drawHere=g.getClipBounds(); // Fill clipping area with blue-gray. g.setColor(rule_color); g.fillRect(drawHere.x,drawHere.y,drawHere.width,drawHere.height); // Do the ruler labels in a small font that's black. g.setFont(new Font("SansSerif",Font.PLAIN,10)); g.setColor(Color.black); // Some vars we need. int end=0; int start=0; int tickLength=0; String text=null; // Use clipping bounds to calculate first tick and last tick location. if (orientation==HORIZONTAL) { start=(drawHere.x/increment)*increment; end=(((drawHere.x+drawHere.width)/increment)+1)*increment; } else { start=(drawHere.y/increment)*increment; end=(((drawHere.y+drawHere.height)/increment)+1)*increment; } // Make a special case of 0 to display the number within the rule and draw a units label. if (start==0) { text=Integer.toString(0)+(isMetric?" cm":" in"); tickLength=10; if (orientation==HORIZONTAL) { g.drawLine(0,SIZE-1,0,SIZE-tickLength-1); g.drawString(text,2,21); } else { g.drawLine(SIZE-1,0,SIZE-tickLength-1,0); g.drawString(text,9,10); } text=null; start=increment; } // ticks and labels for (int i=start;i<end;i+=increment) { if (i%units==0) { tickLength=10; text=Integer.toString(i/units); } else { tickLength=5; text=null; } if (tickLength!=0) { if (orientation==HORIZONTAL) { g.drawLine(i,SIZE-1,i,SIZE-tickLength-1); if (text!=null) g.drawString(text,i-3,21); } else { g.drawLine(SIZE-1,i,SIZE-tickLength-1,i); if (text!=null) g.drawString(text,9,i+3); } } } } // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread. static void createAndShowGUI() { rulerPanel.setPreferredSize(new Dimension(570,78)); Rule cmView=new Rule(Rule.HORIZONTAL,true); int H=35; cmView.setPreferredHeight(H); cmView.setColor(new Color(128,200,235)); JScrollPane cmScrollPane=new JScrollPane(); cmScrollPane.setViewportBorder(BorderFactory.createLineBorder(Color.black)); cmScrollPane.setColumnHeaderView(cmView); rulerPanel.add("North",cmScrollPane); Rule inchView=new Rule(Rule.HORIZONTAL,true); inchView.setPreferredHeight(H); inchView.setColor(new Color(168,200,235)); //238,238,238 inchView.setIsMetric(false); JScrollPane inchScrollPane=new JScrollPane(); inchScrollPane.setViewportBorder(BorderFactory.createLineBorder(Color.black)); inchScrollPane.setColumnHeaderView(inchView); rulerPanel.add("South",inchScrollPane); frame.getContentPane().add(rulerPanel); frame.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { } public void windowClosed(WindowEvent e) { } public void windowClosing(WindowEvent e) { System.exit(0); } public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { rulerPanel.repaint(); } public void windowGainedFocus(WindowEvent e) { rulerPanel.repaint(); } public void windowIconified(WindowEvent e) { } public void windowLostFocus(WindowEvent e) { } public void windowOpening(WindowEvent e) { rulerPanel.repaint(); } public void windowOpened(WindowEvent e) { } public void windowResized(WindowEvent e) { rulerPanel.repaint(); } public void windowStateChanged(WindowEvent e) { rulerPanel.repaint(); } }); frame.pack(); frame.setBounds((screenSize.width-rulerPanel.getWidth())/2,(screenSize.height-rulerPanel.getHeight())/2-19,rulerPanel.getWidth()+20,rulerPanel.getHeight()+38); frame.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event-dispatching thread : creating and showing this application's GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } 

Он отлично работал на моих старых 17 “и 20” дисплеях, теперь я заметил на своем новом 27-дюймовом ЖК-дисплее, это неточно, поэтому мне нужно изменить 4-ю строчку, чтобы быть более точным, не Toolkit.getDefaultToolkit (). getScreenResolution () должен получить точный DPI, почему это неправильно, потому что мое приложение работает на других машинах с разными размерами дисплея и DPI, как автоматически настроить 1.15, который я вручную ввел?

PS: Я не только DPI моего приложения Java неточно, но также, когда я смотрел на несколько других приложений в Windows 7, таких как paint.exe или paint.net, их дюймы и см тоже верны. Вы можете попробовать их на своей машине.

Проблема с драйвером.

Реальный DPI известен только драйверу, который сообщает об этом ОС, который сообщает об этом Java и другим приложениям. Поскольку не только Java имеет неправильный масштаб, он должен быть драйвером.

Это проблема давности. Многие графические приложения имеют глобальную настройку «экран DPI», в которой пользователи могут настраивать свой фактический монитор.

Кроме того, поскольку вы пишете на Java, имейте в виду, что некоторые ОС не имеют возможности сообщать Java реальный DPI (потому что они сами не знают). Таким образом, необходимость настройки конфигурации DPI становится еще более очевидной.

Давайте будем гением компьютера.