2009-02-02 14 views
3

Je travaille sur un simple petit composant d'oscillation, et je m'arrache les cheveux en essayant de comprendre pourquoi ma méthode de peinture ne fonctionne pas.La méthode de peinture Java ne peint pas?

L'idée derrière ce composant est que c'est un petit JPanel avec un label. L'arrière-plan (derrière l'étiquette) est censé être blanc, avec un rectangle de couleur sur le côté gauche indiquant le rapport de deux mesures: "réel" et "attendu".

Si vous aviez un groupe de ces composants alignés verticalement, ils formeraient un graphique à barres, composé de barres horizontales.

Ce genre de chose devrait être super simple.

Quoi qu'il en soit, voici le code:

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

} 

Et voici le faisceau de test simple:

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

} 

Le harnais de test crée un cadre simple et ajoute trois de ces contrôles.

Les étiquettes sont toutes affichées correctement, ce qui m'indique que la méthode paint() est en cours d'appel, mais que les rectangles ne sont pas dessinés dans l'objet Graphics.

Qu'est-ce que je fais mal?

Et pourquoi la programmation Swing est-elle si chiante?


Voici mon code final. Merci à tous pour votre aide!

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)); 
} 
+0

Essayez de supprimer "super.paint (g)" et "g.dispose()" et voyez ce qui se passe. –

+0

Intéressant. Si je supprime "super.paint (g)" et "g.dispose()", alors j'obtiens les rectangles d'arrière-plan corrects, mais je perds le rendu de l'étiquette au premier plan. – benjismith

+0

Hmm ... que diriez-vous de mettre un "super.paint (g)" avant de peindre les barres? Vous pouvez également utiliser "g.drawString()" pour afficher du texte. –

Répondre

4

Je pense que vous avez presque répondu à votre question dans les commentaires, avec la réponse de David. Remplacez paint(Graphics g) par paintComponent(Graphics g) et supprimez les deux dernières lignes de la méthode, et tout devrait bien se passer.

EDIT: Bizarrement, cela ne fonctionne que pour la première barre des trois. Plus de tests en cours ...

Par ailleurs, vous avez une erreur de décalage dans le code de peinture de bordure. Il devrait être:

g.setColor(BORDER_COLOR); 
g.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); 

EDIT2: OK, obtenu. Votre méthode complète paintComponent devrait être comme suit:

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

Notez que les coordonnées données à g.fillRect() et g.drawRect() sont par rapport au composant, ils doivent donc commencer à (0,0).

Et non, je ne peux pas vous aider avec votre dernière question, même si je ressens votre douleur. :)

0

Je ne sais pas si cela est la source de votre problème, mais Swing vous êtes censé remplacer paintComponent(Graphics2D) à la place ...

+0

Oui, dans différentes versions de ce code, j'ai utilisé paint() et paintComponent(). Cela ne fait aucune différence. – benjismith

+0

Si vous surchargez paintComponent(), vous n'avez pas à vous soucier de peindre des enfants. –

+0

En outre, vous n'avez pas à vous soucier de peindre la bordure. peindre des délégués à paintComponent, paintBorder et paintChildren. –

1

Dans votre JPanel, vous avez appelé super.setOpaque (true). Le JPanel va complètement remplir l'arrière-plan lorsque vous appelez super.paint() et écraser vos retangles.

0

Si quelque chose, je pense que vous devriez appeler super.paint (g); au sommet de votre méthode, pas tout en bas. Il est possible que la superclasse soit attirée par vos affaires.

+0

J'ai essayé de l'appeler en haut et en bas et cela n'a fait aucune différence. Mais cela aurait pu être à cause d'une des autres erreurs. – benjismith