JPanel не обновляется до изменения размера Jframe - программирование
Подтвердить что ты не робот

JPanel не обновляется до изменения размера Jframe

I подкласс JPanel для перезаписи paintComponent (Graphics), я хочу нарисовать изображение на jpanel в jframe.

Но мое изображение не появилось, пока я не внес изменения в размер jframe. Это мой код:

public class ImagePanel extends JPanel{

    public void setImage(BufferedImage bi)
    {
        image = bi;
        revalidate();
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(image != null)
        {
            g.drawImage(image, 0, 0, this);
        }
    }
}
4b9b3361

Ответ 1

Убедитесь, что вы вызываете setVisible() после добавления компонентов и вызываете pack(), как описано в этом связанном пример. Вам также может понадобиться принять layout. Вызов repaint(), как предложено здесь, может исправить симптом, но не основной причиной.

Ответ 2

Если вы хотите "обновить" JPanel, тогда вы должны вызвать repaint(), который вызовет ваш paintComponent(). Это должно решить вашу проблему:

public void setImage(BufferedImage bi)
{
    image = bi;
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            repaint();
        }
    });
}

Хорошая практика обновления и изменения GUI с помощью EDT. Heres больше информации об EDT, если вам интересно:

Как работает поток отправки событий?

repaint не нужно вызывать из EDT. Если вы меняете GUI, например, устанавливаете текст в JLabel, он должен быть внутри EDT. Heres больше информации о том, что можно назвать вне EDT (любезно предоставлено nIcE cOw):

Безопасно использовать Component.repaint() вне EDT?

Ответ 3

Посмотрите документы для JPanel.add(), которые он наследует от java.awt.Container:

Добавляет указанный компонент в конец этого контейнера. Это удобный метод для addImpl (java.awt.Component, java.lang.Object, int). Этот метод изменяет информацию, относящуюся к компоновке, и поэтому аннулирует иерархию компонентов. Если контейнер уже был отображен, иерархия должна быть проверена после этого, чтобы отобразить добавленный компонент.

Добавлен акцент.

Поэтому, если вы измените Контейнер после его отображения, вы должны вызвать validate(), чтобы он отображался. Просто вызвать repaint() недостаточно. Возможно, вы заметили, что также работает вызов setVisible(true); это потому, что он вызывает validate() внутренне.

Ответ 4

У меня была та же проблема и исправлена ​​ее вызовом setVisible (true); JFrame, который я использовал.

Пример: если ваш JFrame не обновляется после использования:

jframe.setContentPane(new MyContentPane());

исправить:

jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);

Я знаю, что это звучит глупо, даже если ваш JFrame уже виден, но единственный способ, который я нашел, чтобы решить эту проблему (решение, предложенное выше, не сработало для меня).

Вот полный пример. Запустите его, а затем раскомментируйте "f.setVisible(true)"; инструкции в классах Panel1 и Panel2, и вы увидите разницу. Не забывайте импортировать (Ctrl + Shift + O для автоматического импорта).

Основной класс:

public class Main {
    private static JFrame f;
    public static void main(String[] args) {
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new Panel1(f));
        f.pack();    
        f.setVisible(true);
    }
}

Класс Panel1:

public class Panel1 extends JPanel{
    private JFrame f;
    public Panel1(JFrame frame) {
        f = frame;
        this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        JButton b = new JButton("Panel 1");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                f.setContentPane(new Panel2(f));
                // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                //f.setVisible(true);
            }
        });
        add(b);
    }
}

Класс Panel2:

public class Panel2 extends JPanel{
    private JFrame f;
    public Panel2(JFrame frame) {
        f = frame;
        this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        JButton b = new JButton("Panel 2");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                f.setContentPane(new Panel1(f));
                // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                //f.setVisible(true);
            }
        });
        add(b);
    }
}

Надеюсь, что это поможет.

С уважением.