Перекраска JPanel внутри рамы - PullRequest
5 голосов
/ 09 января 2011

У меня есть JPanel внутри рамы. Содержимое JPanel должно обновляться при каждом вызове paintComponent (который вызывается repaint()), но когда я делаю это, как показано ниже, я просто вижу белое окно. (Прошу прощения за изуродованные отступы, Eclipse делает всякие странные вещи с вкладками.)

private static void handleGUI() 
{       
    JFrame frame = new JFrame("Animation");
    frame.setPreferredSize(new Dimension(100, 100));

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Board b = new Board();

    frame.getContentPane().add(b);

    frame.pack();
    frame.setVisible(true);

    while(true)
    {
        System.out.println("Repainting panel");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        b.repaint();
    }
}

public class Board extends JPanel
{
public Board() { t=0; }

    private int t;

public void paintComponent(Graphics g) 
{
    super.paintComponent(g);

    ++t;

    /* Variables snipped */

    g.setColor(Color.white);
    g.drawOval(0, 0, width, height);

    BufferedImage image = ImageIO.read(new File(imagePath));
    g.drawImage(image, x(t), y(t));
    /* There's some more image and rectangle drawing ahead */
}

}

Ответы [ 3 ]

6 голосов
/ 09 января 2011

У вас есть несколько проблем с вашим кодом, одна была упомянута выше (1+ повторение - хотя мне кажется, что у вас есть код в вашем методе paintComponent, который выполняет рисование), ваш метод paintComponent имеет недостатки, но кроме того, у вас есть цикл while (true) и Thread.sleep в главном потоке Swing, EDT, который переведет Swing и весь ваш графический интерфейс в спящий режим. Вместо этого лучше использовать таймер Swing. Также вы заявляете,

Содержимое JPanel должно обновляться с каждым вызовом paintComponent (который вызывается repaint ()),

Вы уверены, что хотите поместить логику программы в метод paintComponent? Обычно это вызывает недовольство, поскольку вы, программист, не имеете полного контроля над тем, когда вызывается этот метод. Он может вызываться, когда вы вызываете repaint (но не всегда), и может вызываться из-за сообщений от ОС, когда вы не ожидаете, что он будет вызван.

Кроме того, вы никогда не захотите читать файл внутри метода paintComponent, так как это замедлит ваше рисование до кло.

Я бы порекомендовал эти изменения:

1) Создайте таймер Swing с периодом 1000 и в методе actionPerformed его ActionListener прочитайте ваше изображение (предпочтительно в фоновом потоке, если изображение имеет какой-либо значительный размер) и прочитайте изображение в поле класса, скажем, называется изображение.

2) В том же методе actionPerformed таймера, увеличивайте t.

3) После того, как изображение было прочитано, вызовите repaint на чертеже JPanel и попросите JPanel чертежа использовать переменную image, чтобы закрасить изображение. Будьте осторожны, если вы используете фоновый поток для чтения изображения, так как вам нужно, чтобы этот поток уведомлял GUI, когда изображение было полностью прочитано. Если для этого используется SwingWorker, вы можете добавить PropertyChangeListener, который прослушивает к значению состояния SwingWorker и срабатывает, когда это меняется на StateValue.DONE.

Если что-то из этого неясно или сбивает с толку, пожалуйста, попросите разъяснений.

edit: если изображения не слишком велики, вы можете прочитать их все за один раз или выполнить пакетное считывание, когда требуется куча. Нет необходимости читать изображения непосредственно перед их использованием.

2 голосов
/ 09 января 2011

Не заставляйте нить спать. Используйте таймер Swing, чтобы активировать события перерисовки.

1 голос
/ 09 января 2011

ваш paintComponent просто вызывает super.paintComponent.Так что JPanel пока сам красит, который будет светло-серым, или белым, или светло-коричневым, или что-то в зависимости от вашего внешнего вида.

...