从另一个类调用时 Java 重绘方法不起作用

发布于 2024-10-05 01:41:52 字数 1876 浏览 2 评论 0原文

我使用 Netbeans 编写 Java 代码已经大约一年了,并且编写了大量在屏幕上绘制图表的数据操作代码。我通常在主窗口中放置一个 JPanel 对象,编写自定义绘画代码,并根据需要调用 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

如果有人对此有任何见解,或者知道解决方法,我会很高兴听到 来自你。

预先感谢您的任何见解。

约翰·多纳

I have been coding up Java with Netbeans for about a year now, and have written a lot of data manipulation code which plots graphs on-screen. I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed.

But today, for the first time, I tried to invoke a repaint on a panel from a class (object) other than the one that contained the panel. Although the compiler found nothing wrong with this, and in debugging mode, it single-stepped properly to the exterior call to the repaint, no repaint actually occurred, and the code did not actually step into the repaint method.

I wrote a minimalist program to demonstrate the problem, as shown below (Main is ommitted, since it only contains code to set up the two on-screen panels.)

--- Description of classes, first contains the drawing surface, other the repaint call ---

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

If anyone has any insights into this, or knows of a workaround, I'd be very happy to hear
from you.

Thanks in advance for any insights.

John Doner

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

筱果果 2024-10-12 01:41:52

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

好吧,根据定义,当您遇到问题时,您不知道哪些代码是相关的或不相关的,直到问题得到解决。因此,应该发布完整的 SSCCE

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

我通常在主窗口中放置一个 JPanel 对象,编写自定义绘画代码,并根据需要调用 repaint() 方法

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

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

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

Main is ommitted, since it only contains code to set up the two on-screen panels.)

Well, by definition when you have a problem you don't know what code is or isn't relative until the problem is solved. So a complete SSCCE should be posted.

As a wild guess I would say your component has a size of 0 so there is nothing to paint.

I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed

You probably got lucky because you added the panel to the center of a BorderLayout which automatically gives the panel all the space available to the frame.

trashgod's example shows one way to set the preferred size of a custom component. Another way is to override the getPreferredSize() method to return the proper value.

You really should learn how to use layout manager rather than using null layouts and you will avoid problems like this in the future. There is no need to use a null layout unless you have a drag/drop type of application.

生生漫 2024-10-12 01:41:52

“Swing 程序应该重写 paintComponent(),而不是重写 paint()。”—在 AWT 和 Swing 中绘制:绘制方法

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

验证您是否在 EDT 上构建了 GUI,如文章 初始线程

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

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 的评论中所述, 布局管理器视觉指南可能有助于指导您的布局选择。

"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods.

main is ommitted, since it only contains code to set up the two on-screen panels.

Verify that you construct your GUI on the EDT, as shown in the article Initial Threads.

Addendum: Here's an example showing both principles:

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

Addendum: As noted in @camickr's comment, A Visual Guide to Layout Managers may help guide your layout selection.

讽刺将军 2024-10-12 01:41:52

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

I believe that when you are painting a JComponent, the clip region is set to that JComponent. So if other components try to paint (or if you call their repaint), they won't, because of the clipping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文