2011-01-16 15 views
13

Mam następujący aplikacja, która rysuje zasadę:Jak "poprawnie" wykryć DPI wyświetlacza z Javą?

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(); } }); 
    } 
} 

to działało dobrze na moim starym 17" i 20" monitorów, teraz zauważyłem na moim nowym 27" LCD, jest niedokładne, więc mam aby zmienić czwartą linię, aby była dokładniejsza, nie jest Toolkit.getDefaultToolkit(). getScreenResolution() ma uzyskać dokładne DPI, dlaczego nie jest poprawne, aby moja aplikacja działała na innych komputerach o różnych rozmiarach i DPI, jak aby automatycznie dopasować 1.15 ręcznie wstawiłem?

PS: Nie tylko mój DPI aplikacji Java jest niedokładny, ale także, gdy spojrzałem na kilka innych aplikacji w systemie Windows 7, takich jak paint.exe lub paint.net, ich cala a cm to als o w poprawności. Możesz wypróbować je na swoim komputerze.

+0

Informacje o DPI zgłaszane przez system operacyjny lub nawet przez sam sterownik ekranu są często niedokładne. Prawdopodobnie masz pecha w naprawdę ogólnej sprawie. –

+0

Nie jestem pewien, ale zamiast 'Toolkit.getDefaultToolkit(). GetScreenSize();', spróbuj użyć tego do uzyskania rozmiaru 'GraphicsEnvironment.getLocalGraphicsEnvironment(). GetDefaultScreenDevice(). GetDisplayMode();'. Ostatnia instrukcja daje tryb wyświetlania, użyj go, aby uzyskać wysokość i szerokość. – Favonius

+0

@Favonius: Dzięki, ale kiedy już je otrzymałem, jak uzyskać dokładną DPI, której potrzebuję? Numery wyglądają tak: Default_device Szerokość: 2560 Wysokość: 1440 Częstotliwość odświeżania: 59 Głębokość bitowa: 32 , prawie tyle samo, co w przypadku getScreenSize(); – Frank

Odpowiedz

8

Problem ze sterownikiem.

Prawdziwy DPI jest znany tylko sterownikowi, który zgłasza go do systemu operacyjnego, który zgłasza go do Javy i innych aplikacji. Ponieważ nie tylko Java ma złą skalę, musi to być sterownik.

To stary problem. Wiele aplikacji graficznych ma ustawienie globalne "DPI ekranu", w którym użytkownicy mogą dostosować się do rzeczywistego monitora.

Poza tym, ponieważ piszesz w Javie, pamiętaj, że niektóre systemy operacyjne nie mają możliwości poinformowania Javy o prawdziwym DPI (ponieważ nie znają siebie). Potrzeba ustawienia konfiguracji DPI jest jeszcze bardziej wyraźna.