1

我已经用 Netbeans 编写 Java 代码大约一年了,并且编写了很多数据操作代码,这些代码在屏幕上绘制图形。我一般在我的主窗口中植入一个JPanel对象,编写自定义绘画代码,根据需要调用repaint()方法。

但是今天,我第一次尝试从包含面板的类(对象)调用面板上的重绘。虽然编译器没有发现任何问题,并且在调试模式下,它正确地单步执行了对 repaint 的外部调用,但实际上并没有发生 repaint,代码也没有真正进入 repaint 方法。

我写了一个极简程序来演示这个问题,如下所示(Main 被省略,因为它只包含设置两个屏幕面板的代码。)

---类的描述,首先包含绘图表面,其他重绘调用---

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Panel1 extends JComponent
{
   GraphPnl graphPnl;
   boolean colorFlag;

   public Panel1()
   {
     setLayout(null);
     colorFlag = true;

     graphPnl = new GraphPnl();
     graphPnl.setBounds(10, 10, 110, 110);
     graphPnl.setBackground(Color.black);
     add(graphPnl);

}//Panel1()

public class GraphPnl extends JPanel
{
  //just draws a line segment, toggling color

  @Override
  public void paint(Graphics g)
  {
      super.paint(g);
      Graphics2D g2 = (Graphics2D) g;
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);

      if (colorFlag) {g2.setColor(Color.red);} else {g2.setColor(Color.green);}
      g2.drawLine(10, 10, 50, 50);
   }//paint
 }//GraphPnl
}//Panel1

import javax.swing.*;
import java.awt.event.*;

public class Panel2 extends JComponent
{
   JButton testBtn;
   TestAction testAction;
   Panel1 p1;

   public Panel2()
   {
      p1 = new Panel1();
      testBtn = new JButton("Click");
      testBtn.setBounds(10, 10, 80, 30);
      add(testBtn);
      testAction = new TestAction();
      testBtn.addActionListener(testAction);
   }//Panel2()


   public class TestAction implements ActionListener
   {
     public void actionPerformed(ActionEvent evt)
     {
       p1.colorFlag = ! p1.colorFlag;
       p1.graphPnl.repaint();
     }
   }//TestAction
}//Panel2

如果有人对此有任何见解,或者知道解决方法,我很高兴收到您的来信。

提前感谢您的任何见解。

约翰·多纳

4

3 回答 3

1

“Swing 程序应该覆盖paintComponent()而不是覆盖paint()。”—<a href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html#callbacks" rel="nofollow">绘画AWT 和 Swing:绘制方法

main被省略,因为它只包含设置两个屏幕面板的代码。

验证您是否在 EDT 上构建了 GUI,如文章Initial Threads中所示。

附录:这是一个显示这两个原则的示例:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @see http://stackoverflow.com/questions/4282159 */
public class GraphPanel extends JPanel {

    private boolean colorFlag;

    public GraphPanel() {
        this.setPreferredSize(new Dimension(640, 480));
    }

    public void toggle() {
        colorFlag = !colorFlag;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        if (colorFlag) {
            g2.setColor(Color.red);
        } else {
            g2.setColor(Color.blue);
        }
        g2.drawLine(0, 0, getWidth(), getHeight());
    }

    private void display() {
        JFrame f = new JFrame("GraphPanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this, BorderLayout.CENTER);
        f.add(new ControlPanel(this), BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new GraphPanel().display();
            }
        });
    }
}

class ControlPanel extends JPanel {

    public ControlPanel(final GraphPanel gp) {
        this.add(new JButton(new AbstractAction("Click") {

            @Override
            public void actionPerformed(ActionEvent e) {
                gp.toggle();
                gp.repaint();
            }
        }));
    }
}

附录:正如@camickr 的评论中所述,布局管理器的视觉指南可能有助于指导您的布局选择。

于 2010-11-26T04:10:22.380 回答
1

Main 被省略,因为它只包含设置两个屏幕面板的代码。)

好吧,根据定义,当您遇到问题时,在问题解决之前您不知道什么代码是相对的或不相关的。所以应该发布一个完整的SSCCE 。

作为一个疯狂的猜测,我会说你的组件的大小为 0,所以没有什么可以画的。

我一般在我的主窗口中种植一个JPanel对象,编写自定义绘画代码,根据需要调用repaint()方法

您可能很幸运,因为您将面板添加到 BorderLayout 的中心,这会自动为面板提供框架可用的所有空间。

rashgod 的示例显示了一种设置自定义组件的首选大小的方法。另一种方法是覆盖 getPreferredSize() 方法以返回正确的值。

您真的应该学习如何使用布局管理器而不是使用空布局,并且您将来会避免类似的问题。除非您有拖放类型的应用程序,否则无需使用空布局。

于 2010-11-26T05:01:27.650 回答
0

我相信当您绘制 JComponent 时,剪辑区域会设置为该 JComponent。因此,如果其他组件尝试绘制(或者如果您调用它们的重绘),它们将不会,因为剪辑。

于 2010-11-26T02:41:06.733 回答