Il metodo Java Paint non dipinge?
Domanda
Sto lavorando a un semplice componente di altalena e mi sto strappando i capelli cercando di capire perché il mio metodo di pittura non funziona.
L'idea alla base di questo componente è che è un piccolo JPanel con un'etichetta. Lo sfondo (dietro l'etichetta) dovrebbe essere bianco, con un rettangolo colorato sul lato sinistro che indica il rapporto tra due misure: & Quot; <<>> attuale; e " previsto " ;.
Se avessi un gruppo di questi componenti allineati verticalmente, formerebbero un grafico a barre, composto da barre orizzontali.
Questo genere di cose dovrebbe essere super semplice.
Comunque, ecco il codice:
package com.mycompany.view;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BarGraphPanel extends JPanel {
private static final Color BACKGROUND = Color.WHITE;
private static final Color FOREGROUND = Color.BLACK;
private static final Color BORDER_COLOR = new Color(229, 172, 0);
private static final Color BAR_GRAPH_COLOR = new Color(255, 255, 165);
private int actual = 0;
private int expected = 1;
private JLabel label;
public BarGraphPanel() {
super();
label = new JLabel();
label.setOpaque(false);
label.setForeground(FOREGROUND);
super.add(label);
super.setOpaque(true);
}
public void setActualAndExpected(int actual, int expected) {
this.actual = actual;
this.expected = expected;
}
@Override
public void paint(Graphics g) {
double proportion = (expected == 0) ? 0 : ((double) actual) / expected;
Rectangle bounds = super.getBounds();
g.setColor(BACKGROUND);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
g.setColor(BAR_GRAPH_COLOR);
g.fillRect(bounds.x, bounds.y, (int) (bounds.width * proportion), bounds.height);
g.setColor(BORDER_COLOR);
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
label.setText(String.format("%s of %s (%.1f%%)", actual, expected, proportion * 100));
super.paint(g);
g.dispose();
}
}
Ed ecco il semplice cablaggio di prova:
package com.mycompany.view;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class MyFrame extends JFrame {
public MyFrame() {
super();
super.setLayout(new GridLayout(3, 1));
super.setPreferredSize(new Dimension(300, 200));
BarGraphPanel a = new BarGraphPanel();
BarGraphPanel b = new BarGraphPanel();
BarGraphPanel c = new BarGraphPanel();
a.setActualAndExpected(75, 100);
b.setActualAndExpected(85, 200);
c.setActualAndExpected(20, 300);
super.add(a);
super.add(b);
super.add(c);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable t) { }
MyFrame frame = new MyFrame();
frame.pack();
frame.setVisible(true);
}
}
Il cablaggio di test crea un semplice frame e quindi aggiunge tre di questi controlli.
Le etichette sono tutte renderizzate correttamente, il che mi indica che il metodo paint () viene effettivamente chiamato, ma i rettangoli non vengono disegnati sull'oggetto Graphics.
Cosa sto sbagliando?
E perché la programmazione di Swing fa tanto schifo?
Ecco il mio codice finale. Grazie a tutti per il vostro aiuto!
public void paintComponent(Graphics g) {
double proportion = (expected == 0) ? 0 : ((double) actual) / expected;
Rectangle bounds = super.getBounds();
g.setColor(BACKGROUND);
g.fillRect(0, 0, bounds.width, bounds.height);
g.setColor(BAR_GRAPH_COLOR);
g.fillRect(0, 0, (int) (bounds.width * proportion), bounds.height);
g.setColor(BORDER_COLOR);
g.drawRect(0, 0, bounds.width - 1, bounds.height - 1);
FontMetrics metrics = g.getFontMetrics();
String label = String.format("%s of %s (%.1f%%)", actual, expected, proportion * 100);
Rectangle2D textBounds = metrics.getStringBounds(label, g);
g.setColor(FOREGROUND);
g.drawString(label, 5, (int) ((bounds.height + textBounds.getHeight()) / 2));
}
Soluzione
Penso che tu abbia quasi risposto alla tua domanda nei commenti, insieme alla risposta di David. Cambia paint(Graphics g)
in paintComponent(Graphics g)
e rimuovi le ultime due righe del metodo, e dovresti andare bene.
MODIFICA: Stranamente, questo funziona solo per la prima barra delle tre. Altri test in corso ...
A proposito, hai un errore off-by-one nel codice di confine. Dovrebbe essere:
g.setColor(BORDER_COLOR);
g.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
EDIT2: OK, capito. Il tuo metodo completo paintComponent
dovrebbe essere il seguente:
@Override
public void paintComponent(Graphics g) {
double proportion = (expected == 0) ? 0 : ((double) actual) / expected;
Rectangle bounds = super.getBounds();
g.setColor(BACKGROUND);
g.fillRect(0, 0, bounds.width, bounds.height);
g.setColor(BAR_GRAPH_COLOR);
g.fillRect(0, 0, (int) (bounds.width * proportion), bounds.height);
g.setColor(BORDER_COLOR);
g.drawRect(0, 0, bounds.width-1, bounds.height-1);
label.setText(String.format("%s of %s (%.1f%%)", actual, expected, proportion * 100));
}
Nota che le coordinate fornite a g.fillRect()
e g.drawRect()
sono relative al componente, quindi devono iniziare da (0,0).
E no, non posso aiutarti con la tua ultima domanda, anche se sento il tuo dolore. :)
Altri suggerimenti
Nel tuo JPanel hai chiamato super.setOpaque (true). JPanel riempirà completamente lo sfondo quando chiami super.paint () e sovrascrivi i tuoi rangoli.
Non sono sicuro che questa sia la fonte del tuo problema, ma in Swing dovresti sostituire paintComponent(Graphics2D)
invece ...
Se non altro, penso che dovresti chiamare super.paint (g); all'inizio del metodo, non in fondo. È possibile che la superclasse stia attingendo alle tue cose.