【问题标题】:Infinite loop when updating JPanel's graphics更新 JPanel 的图形时无限循环
【发布时间】:2011-09-25 14:34:27
【问题描述】:

所以,我正在使用Grahics2DJPanel 对象中绘制图形。
JPanel 放置在 JScrollPane 中,用于我的图形大于窗口的情况。
但是在我绘制图形后,JPanel 的大小没有改变,我无法滚动查看图形的其余部分,所以我找到了最低和最左边的点,并在绘图方法中手动设置大小(方法称为drawTrack())。
当我切换窗口或执行其他操作使 JPanel 再次被绘制时,我的图形消失了,所以我重写了paint()repaint()validate()invalidate() 方法,并在其中调用了drawTrack() 方法在重绘 JPanel 的所有可能情况下绘制我的图形。
问题是,当JPanel 调用其中一种进行重绘的方法时,我在其中调用drawTrack(),在重绘我的图形后手动设置大小,以便我可以滚动JScrollPane 并查看我的整个图形。但是当我在 JPanel 上调用 setSize() 方法时,它会再次重绘,这意味着调用 drawTrack() 等等。
出现滚动条是因为大小正确,但它会创建一个无限循环,一遍又一遍地重绘我的图形。如果我不调用setSize() 方法,我的JPanel 将获得默认大小,因此它可以适合JScrollPane 的视口,因此我无法滚动它来查看我的图形。
有什么建议吗?

【问题讨论】:

  • 你能提供一个SSCCE吗?否则我认为我们无法为您提供帮助。
  • 请查看我的意思的示例以及下面的 SSCCE 示例。

标签: java swing graphics awt


【解决方案1】:

当您调整 JPanel 的大小时,您会触发重绘,因此,如果您在 paint 或 paintComponent 方法或在这两种方法中调用的方法中更改大小,那么您有可能导致无限循环。

解决方案:不要在paint 或paintComponent 方法中调整任何东西的大小。该方法仅用于绘画,仅用于绘画。相反,如果您想设置 JPanel 的大小,请覆盖其 getPreferredSize() 方法。

这是一个“多彩”的例子:

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

@SuppressWarnings("serial")
public class ImageReSize extends JPanel {
   private static final int INIT_WIDTH = 400;
   private static final int MAX_WIDTH = 1200;

   private static final int TIMER_DELAY = 20;
   protected static final int WIDTH_STEP = 5;
   private int width = INIT_WIDTH;
   private int height = INIT_WIDTH;
   private boolean growing = true;

   public ImageReSize() {
      new Timer(TIMER_DELAY, new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if (growing && width < MAX_WIDTH) {
               width += WIDTH_STEP;
               height += WIDTH_STEP;
            } else {
               growing = false;
            }

            if (!growing && width > INIT_WIDTH) {
               width -= WIDTH_STEP;
               height -= WIDTH_STEP;
            } else {
               growing = true;
            }
            // get the parent container which is the scrollpane's viewport
            JComponent parent = (JComponent)getParent();
            parent.revalidate(); // let it relayout the changed size JPanel
            parent.repaint();  // and repaint all
         }
      }).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D)g;
      float x = (float)width / 10;
      float y = (float)height / 10;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(new GradientPaint(x, 0, Color.green, 0, y, Color.black, true));
      g2.fillRect(0, 0, getWidth(), getHeight());
      g2.setPaint(new GradientPaint(0, 0, Color.blue, x, y, Color.red, true));
      g2.fillOval(0, 0, width, height);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(width, height);
   }

   private static void createAndShowUI() {
      ImageReSize imageReSize = new ImageReSize();
      JFrame frame = new JFrame("ImageReSize");
      frame.getContentPane().add(new JScrollPane(imageReSize));
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

【讨论】:

    【解决方案2】:

    所以我重写了 paint()、repaint()、validate()、invalidate() 方法,并在其中调用了 drawTrack() 方法

    这是不必要的。自定义绘画代码只能从 paintComponent() 方法调用。

    【讨论】:

      【解决方案3】:

      遇到类似问题:JPanel 的paintComponent 方法调用了其他“方法”,涉及到Graphics 的更改,因此需要另一个paintComponent 循环。

      我还没有找到将这些“方法”移到paintComponent之外的结构化方法,但找到了以下解决方案:用 if 子句包围这些“方法”并用布尔标志中断循环:

      boolean flag;
      
      @Override
      public void paintComponent(Graphics g) {
      
          if (flag) {
              gModify(); // Method that modifies Graphics g object and calls another paintComponent loop.
              flag = !flag; // True to false - miss gModify() in the second paintComponent entry to break the loop.
          } else {
              flag = !flag; // False to true - allow gModify() after second  paintComponent entry.
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        • 1970-01-01
        • 2019-03-15
        • 2018-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多