【问题标题】:Java Paint Method Doesn't Paint?Java Paint 方法不绘制?
【发布时间】:2010-10-04 23:42:52
【问题描述】:

我正在开发一个简单的小摆动组件,我正在扯头发试图找出为什么我的绘画方法不起作用。

这个组件背后的想法是它是一个带有标签的小型 JPanel。背景(标签后面)应该是白色的,左侧有一个彩色矩形表示两个测量值的比率:“实际”和“预期”。

如果你有一堆这些组件垂直对齐,它们会形成一个条形图,由水平条组成。

这种东西应该超级简单。

总之,代码如下:

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

}

这是简单的测试工具:

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

}

测试工具创建一个简单的框架,然后添加其中三个控件。

所有标签都正确呈现,这表明paint() 方法实际上正在被调用,但矩形并未被绘制到 Graphics 对象。

我做错了什么?

为什么 Swing 编程这么烂?


这是我的最终代码。谢谢大家的帮助!

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

【问题讨论】:

  • 尝试删除“super.paint(g)”和“g.dispose()”看看会发生什么。
  • 有趣。如果我删除“super.paint(g)”和“g.dispose()”,我会得到正确的背景矩形,但我会丢失前景中标签的呈现。
  • 嗯...在绘制条形之前放置一个“super.paint(g)”怎么样?或者,您可以使用“g.drawString()”来呈现文本。

标签: java swing label jpanel paint


【解决方案1】:

我认为您几乎已经在 cmets 中回答了您自己的问题,以及 David 的回答。把paint(Graphics g)改成paintComponent(Graphics g),去掉方法的最后两行,就可以了。

编辑:奇怪的是,这仅适用于三个小节中的第一个。更多测试正在进行中...

顺便说一句,您的边框绘制代码中有一个错误。应该是:

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

EDIT2:好的,知道了。您的完整paintComponent 方法应如下所示:

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

请注意,g.fillRect()g.drawRect() 的坐标是相对于组件的,因此它们必须从 (0,0) 开始。

不,我不能帮助你回答你的最后一个问题,尽管我能感觉到你的痛苦。 :)

【讨论】:

    【解决方案2】:

    在您的 JPanel 中,您调用了 super.setOpaque(true)。当您调用 super.paint() 并覆盖您的 retangles 时,JPanel 将完全填充背景。

    【讨论】:

      【解决方案3】:

      不确定这是否是您问题的根源,但在 Swing 中您应该改写 paintComponent(Graphics2D)...

      【讨论】:

      • 是的,在这段代码的各个版本中,我一直在使用paint() 和paintComponent()。没有任何区别。
      • 如果重写paintComponent(),就不用担心画孩子了。
      • 另外,你不用担心画边框。将代表绘制到paintComponent、paintBorder 和paintChildren。
      【解决方案4】:

      如果有的话,我认为你应该调用 super.paint(g);在您方法的顶部,而不是在最底部。超类有可能在你的东西之上。

      【讨论】:

      • 我试过在顶部和底部调用它,但没有任何区别。但这可能是因为其他错误之一。
      猜你喜欢
      • 2017-06-27
      • 2013-11-29
      • 2013-03-12
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      • 2017-03-17
      • 1970-01-01
      相关资源
      最近更新 更多