JPanelのグラフィックスを更新する際の無限ループ

awt graphics java swing
JPanelのグラフィックスを更新する際の無限ループ

それで、 Grahics2D`を使用して JPanel`オブジェクトにグラフィックを描画しています。 +グラフィックがウィンドウよりも大きい場合、「JPanel」は「JScrollPane」に配置されます。 +しかし、グラフィックを描画した後、「JPanel」のサイズは変更されず、グラフィックの残りの部分を見るためにスクロールすることはできません。 (メソッドは drawTrack()`と呼ばれます)。 +ウィンドウを切り替えたり、JPanelを再度描画する何かを行うと、グラフィックが消えるので、 `paint()repaint()validate()invalidate()`メソッドを書き直し、そこで、JPDrawを再描画するあらゆる可能なケースでグラフィックを描画するために、 `drawTrack()`メソッドを呼び出します。 +問題は、 `JPanel`が再描画を行うメソッドの1つを呼び出すと、その中で drawTrack() を呼び出します。グラフィックを再描画した後、手動でサイズを設定し、 JScrollPane`をスクロールしてグラフィック全体。 しかし、JPanelで setSize()`メソッドを呼び出すと、再描画されます。つまり、 `drawTrack()`などを呼び出します。 +スクロールバーはサイズが正しいために表示されますが、無限のループが作成され、グラフィックが何度も再描画されます。 そして、 `setSize()`メソッドを呼び出さない場合、 `JPanel`はデフォルトサイズを取得するため、 JScrollPane`のビューポートに収まるため、スクロールしてグラフィックを見ることができません。 助言がありますか?

  2  0


ベストアンサー

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

5


_
したがって、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.
    }

}

0


タイトルとURLをコピーしました