Бесконечный цикл при обновлении графики JPanel - PullRequest
2 голосов
/ 25 сентября 2011

Итак, я рисую графику в JPanel объекте, используя Grahics2D.
JPanel помещается в JScrollPane для случаев, когда моя графика больше, чем у окна.
Но после того, как я нарисовал свою графику, размер JPanel не изменился, и я не могу прокрутить, чтобы увидеть остальную часть моей графики, поэтому я определяю нижнюю и самую левую точки и устанавливаю размер вручную в методе, который рисует ( метод называется drawTrack()).
Когда я переключаю окна или делаю что-то еще, что заставляет JPanel быть нарисованным снова, моя графика исчезает, поэтому я переписываю методы paint(), repaint(), validate(), invalidate() и там я вызываю метод drawTrack() рисовать мою графику на каждом возможном случае перерисовки JPanel.
Проблема в том, что когда JPanel вызывает один из методов, которые выполняют перерисовку, я вызываю в них drawTrack(), который после перерисовки моей графики устанавливает размер вручную, так что я могу прокручивать JScrollPane и видеть всю мою графику. Но когда я вызываю метод setSize() на JPanel, который заставляет его снова перерисовываться, то есть вызывает drawTrack() и т. Д. И т. П.
Полосы прокрутки появляются, потому что размер правильный, но он создает бесконечный цикл, который перерисовывает мою графику снова и снова. И если я не вызову метод setSize(), мой JPanel получит размер по умолчанию, чтобы он мог поместиться в окне просмотра JScrollPane, и поэтому я не смогу прокрутить его, чтобы увидеть мою графику.
Есть предложения?

Ответы [ 3 ]

5 голосов
/ 25 сентября 2011

Когда вы изменяете размер JPanel, вы стимулируете перерисовку, и поэтому, если вы изменяете размер в методе paint или paintComponent или в методе, вызываемом любым из этих методов, для меня имеет смысл вызвать риск бесконечногоloop.

Решение: Не изменяйте размер в методе 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();
         }
      });
   }
}
3 голосов
/ 25 сентября 2011

поэтому я переписал методы paint (), repaint (), validate (), invalidate (), и там я вызываю метод drawTrack ()

Это не нужно. Пользовательский код рисования должен вызываться только из метода paintComponent ().

0 голосов
/ 27 июня 2012

Столкнулся с аналогичной проблемой: метод 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.
    }

}
...