Question

Je travaille sur un petit composant de balançoire simple et je m'arrache les cheveux pour essayer de comprendre pourquoi ma méthode de peinture ne fonctionne pas.

L’idée de ce composant est qu’il s’agit d’un petit JPanel avec une étiquette. Le fond (derrière l'étiquette) est supposé être blanc, avec un rectangle de couleur sur le côté gauche indiquant le rapport entre deux mesures: & "Actuel &"; et " attendu ".

Si plusieurs de ces composants étaient alignés verticalement, ils formeraient un diagramme à barres, composé de barres horizontales.

Ce genre de chose devrait être très 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 harnais 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 faisceau de test crée un cadre simple, puis ajoute trois de ces commandes.

Les étiquettes sont toutes correctement rendues, ce qui m'indique que la méthode paint () est en train d'être appelée, mais que les rectangles ne sont pas dessinés sur l'objet Graphics.

Qu'est-ce que je fais de travers?

Et pourquoi la programmation Swing est-elle si nulle?

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));
}
Était-ce utile?

La solution

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

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

En passant, vous avez une erreur particulière dans le code de dessin de bordure. Ce devrait être:

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

EDIT2: OK, compris. Votre méthode paintComponent complète doit être la suivante:

@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 relatives au composant, elles 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. :)

Autres conseils

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

Vous n'êtes pas sûr que ce soit la source de votre problème, mais dans Swing, vous êtes censé remplacer paintComponent(Graphics2D) à la place ...

Si quoi que ce soit, je pense que vous devriez appellerez super.paint (g); au sommet de votre méthode, pas au fond. Il est possible que la superclasse tire au-dessus de vos affaires.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top