Pergunta

Eu estou trabalhando em um componente simples e pequeno swing, e eu estou fazendo meu cabelo tentando descobrir por que o meu método de pintura não está funcionando.

A idéia por trás deste componente é que ele é um pequeno JPanel com uma etiqueta. O fundo (por trás do rótulo) é suposto ser branco, com um retângulo colorido no lado da mão esquerda indicando a razão de duas medidas:. "Real" e "esperado"

Se você tinha um monte de estes componentes alinhados verticalmente, eles formam um gráfico de barras, composto por barras horizontais.

Este tipo de coisa deve ser super-simples.

De qualquer forma, aqui está o código:

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

}

E aqui está o simples equipamento de teste:

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

}

O equipamento de teste cria um quadro simples e, em seguida, adiciona três destes controles.

As etiquetas são todos processados ??corretamente, o que indica para mim que o método paint () está realmente sendo chamado, mas os retângulos não estão sendo atraídos para o objeto Graphics.

O que estou fazendo de errado?

E por que a programação balanço sugar tanto?


Aqui está o meu código final. Obrigado a todos por sua ajuda!

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));
}
Foi útil?

Solução

Eu acho que você quase respondeu a sua própria pergunta nos comentários, juntamente com a resposta de David. Mudança paint(Graphics g) para paintComponent(Graphics g) e retire as duas últimas linhas do método, e você deve ser fino.

EDIT: Estranhamente, isso só funciona para o primeiro bar dos três. Mais testes em andamento ...

A propósito, você tem um erro off-by-one no código de pintura de fronteira. Ele deve ser:

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

EDIT2: OK, entendi. Seu método paintComponent completa deve ser a seguinte:

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

Note que as coordenadas dadas a g.fillRect() e g.drawRect() são em relação ao componente, para que eles devem começar em (0,0).

E não, eu não posso ajudá-lo com sua última pergunta, embora eu sinto sua dor. :)

Outras dicas

Em seus JPanel, você chamou super.setOpaque (true). O JPanel vai encher completamente em segundo plano quando você chamar super.paint () e substituir seus retangles.

Não tenho certeza se esta é a origem do problema, mas no Swing você deveria paintComponent(Graphics2D) override vez ...

Se qualquer coisa, eu acho que você deveria estar chamando super.paint (g); No topo do seu método, não na parte inferior. É possível que a superclasse é desenho em cima do seu material.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top