如何使用Java“正确”检测显示器的DPI?
我有以下应用程序来绘制规则:
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英寸LCD上,它不准确,所以我必须更改第4行以使其更准确,不是 Toolkit.getDefaultToolkit().getScreenResolution()应该获得准确的DPI,为什么它不正确,因为我的应用程序可以在具有不同显示尺寸和DPI的其他机器上运行, 如何自动调整我手动放入的1.15?
PS :不仅我的Java应用程序的DPI不准确,而且当我在Windows 7上查看其他几个应用程序(例如paint.exe或 paint.net)时,它们的英寸和厘米也是正确的。您可以在计算机上尝试使用它们。