2015-09-15 19 views
5

Ho sempre creato rettangoli dai contorni come questo (utilizzando Graphics (2D)):drawRect() non funziona correttamente su alcuni colori

g.setColor(aColor); 
g.fillRect(x, y, width, height); 
g.setColor(anotherColor); 
g.drawRect(x, y, width, height); 

Questo funziona bene, tranne che con alcuni colori come il Color.BLUE. Ci sono linee che non hanno lo stesso spessore:

enter image description here

Può essere difficile da vedere a prima vista, ma se si guarda attentamente si renderanno conto che la linea di sinistra è troppo spessa e la linea giusta è troppo sottile Questo succede anche con altri colori, semplicemente non così ovviamente: (io non sono ancora sicuro se questo accade con ciano, non si può esattamente dire)

enter image description here

non riesco a dare un senso a questo perché la la linea nera viene disegnata sul rettangolo blu interno, il rettangolo interno non dovrebbe avere alcun effetto su di esso. (senza fillRect() le linee hanno anche spessori)

Ho fornito un esempio sotto che probabilmente ti aiuterà a vedere meglio la differenza. La mia domanda: perché sta succedendo questo con determinati colori RGB e come risolverlo?

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 
import java.util.HashMap; 

import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JToggleButton; 
import javax.swing.WindowConstants; 

public class LineExample { 

    Color colors[] = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, 
      Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW }; 
    String colorNames[] = new String[] { "Black", "Blue", "Cyan", "Dark Gray", "Gray", "Green", "Light Gray", "Magenta", 
      "Orange", "Pink", "Red", "White", "Yellow" }; 
    HashMap<String, Color> hashMap = new HashMap<String, Color>(); 
    Color currentColor = colors[2]; 

    public LineExample() { 

     fillHashMap(hashMap); 

     JFrame frame = new JFrame(); 

     JPanel mainPanel = new JPanel(new BorderLayout()); 
     JPanel northPanel = new JPanel(new FlowLayout()); 
     JPanel centerPanel = new JPanel(new GridLayout(1, 2)); 
     CustomPanel customPanel = new CustomPanel(); 
     BluePanel bluePanel = new BluePanel(); 

     JComboBox<String> comboBox = new JComboBox<String>(); 
     addItems(comboBox); 
     comboBox.addItemListener(new ItemListener() { 
      @Override 
      public void itemStateChanged(ItemEvent e) { 
       currentColor = hashMap.get(comboBox.getSelectedItem()); 
       centerPanel.repaint(); 
      } 
     }); 

     JToggleButton toggleButton = new JToggleButton("Switch"); 
     toggleButton.addItemListener(new ItemListener() { 
      @Override 
      public void itemStateChanged(ItemEvent e) { 
       centerPanel.removeAll(); 
       if (e.getStateChange() == ItemEvent.SELECTED) { 
        centerPanel.add(bluePanel); 
        centerPanel.add(customPanel); 
       } else if (e.getStateChange() == ItemEvent.DESELECTED) { 
        centerPanel.add(customPanel); 
        centerPanel.add(bluePanel); 
       } 
       centerPanel.revalidate(); 
       centerPanel.repaint(); 
      } 
     }); 

     northPanel.add(comboBox); 
     northPanel.add(toggleButton); 
     centerPanel.add(customPanel); 
     centerPanel.add(bluePanel); 
     mainPanel.add(northPanel, BorderLayout.NORTH); 
     mainPanel.add(centerPanel, BorderLayout.CENTER); 

     frame.setContentPane(mainPanel); 

     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frame.setSize(250, 250); 
     frame.setVisible(true); 

    } 

    public void addItems(JComboBox<String> comboBox) { 
     for (int i = 0; i < colors.length; i++) { 
      comboBox.addItem(colorNames[i]); 
     } 
     comboBox.setSelectedIndex(2); 
    } 

    public void fillHashMap(HashMap<String, Color> hashmap) { 
     for (int i = 0; i < colors.length; i++) { 
      hashMap.put(colorNames[i], colors[i]); 
     } 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new LineExample(); 
      } 
     }); 
    } 

    public class BluePanel extends JPanel { 
     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      int width = 100; 
      int height = 100; 
      int x = ((this.getWidth() - width)/2); 
      int y = ((this.getHeight() - height)/2); 
      g.setColor(Color.BLUE); 
      g.fillRect(x, y, width, height); 
      g.setColor(Color.BLACK); 
      g.drawRect(x, y, width, height); 
     } 
    } 

    public class CustomPanel extends JPanel { 
     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      int width = 100; 
      int height = 100; 
      int x = ((this.getWidth() - width)/2); 
      int y = ((this.getHeight() - height)/2); 
      g.setColor(currentColor); 
      g.fillRect(x, y, width, height); 
      g.setColor(Color.BLACK); 
      g.drawRect(x, y, width, height); 
     } 
    } 

} 
+0

'la linea di sinistra è troppo spessa e la linea di destra è troppo sottile. - Vedo sempre una linea nera da 1 pixel. Ho fatto una stampa serigrafica e caricato l'immagine in MS Paint e ingrandito. Ho anche caricato l'immagine postata in Paint. Anche la tua immagine è di 1 pixel. Quindi non sono sicuro di cosa stai descrivendo. – camickr

+0

Quando si salva l'immagine e la si osserva in un visualizzatore di immagini e quindi si ingrandisce, si noterà che il bordo sinistro e il bordo destro hanno entrambi esattamente un pixel di larghezza. Quello che vedi lì (non lo vedo davvero, comunque) è quasi certamente l'effetto che viene anche descritto qui: http: //graphicdesign.stackexchange.it/questions/42306/why-do-two-rectangular-adjacent-rectangles-create-black-or-white-lines-in-between – Marco13

risposta

8

Questo è un problema interessante che si pone a causa di accordi di subpixel di schermi LCD. Ho scattato alcune foto del mio monitor con il mio telefono per spiegare questo effetto.

Per prima cosa guardiamo a sinistra. La linea sembra avere uno spessore di circa 2 pixel. Ciò è dovuto al fatto che andare da sinistra a destra sulla linea è una transizione da nero a blu. Dal momento che i pixel rosso e verde non possono essere illuminati per il colore blu, dobbiamo attendere il successivo subpixel blu dopo che la linea dovrebbe terminare.

enter image description here

Poi guardiamo il lato destro. Questa linea ha uno spessore di circa 1 pixel. Questa volta è una transizione da bianco a nero, quindi i pixel rosso e verde possono essere illuminati subito dopo la linea.

enter image description here

Questo problema si pone come la libreria grafica Java non è subpixel a conoscenza (almeno per le forme). Avrai sempre questo problema per alcune combinazioni di colori su ogni monitor. Sarà più evidente per i colori primari rosso verde blu, motivo per cui è difficile dire nel tuo ciano esempio.

+0

Molto impressionante - grazie e 1+ (vorrei poter votare 100+). –

+2

@HovercraftFullOfEels Considera una taglia ;-) – Marco13

+1

Suppongo che la mia vista non sia abbastanza buona da vedere questo problema (o non succede su tutti gli schermi LCD?). Buono a sapersi esiste (1+). – camickr

0

potrebbe essere correlato a antialiasing? Quando affronto questo tipo di problemi faccio di solito qualcosa di simile ...

Graphics2D g2 = (Graphics2D)g; 
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

// draw stuff 

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); 
+0

Ho già provato prima, non ha funzionato. Si prega di notare che è possibile provare da soli con il mio esempio prima. –