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

Я подкласс JPanel переписать paintComponent (Графика), я хочу нарисовать изображение на jpanel в 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);
        }
    }
}

Ответы на вопрос(5)

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

Appends the specified component to the end of this container. This is a convenience method for addImpl(java.awt.Component, java.lang.Object, int). This method changes layout-related information, and therefore, invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component.

Emphasis added.

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

 28 мая 2018 г., 09:12
Я получаю лучшие результаты сrevalidate(). validate() выполняет работу, но не изменяет размеры, чтобы соответствовать новым добавленным компонентам.

У меня тоже была такая же проблема, но я нашел решение. Просто создайтеjframe возьмите сверху и позвонитеjframe методы внизу, какjf.pack(), jf.setVisible(), jf.setSize(), jf.setDefaultCloseOpetion() должно быть в нижней части всех пользовательских интерфейсов, добавленных в этом кадре, вы найдете, что он отлично работает.

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

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

Рекомендуется обновлять и изменять графический интерфейс с помощью EDT. Вот дополнительная информация о EDT, если вы заинтересованы:

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

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

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

 nautilusvn17 июн. 2012 г., 10:52
Спасибо Джону, все работает отлично!
 17 июн. 2012 г., 14:30
+1 за ценный вклад. Просто предложение, не нужно ставитьrepaint() звонить внутри EDT, так как звонить безопасноrepaint() из любой темы, как описаноhere
 17 июн. 2012 г., 19:09
& quot; подклассы компонентов Swing, имеющих делегат пользовательского интерфейса & # x2026; должен ссылатьсяsuper.paintComponent()& Quot; & # x2014;The Paint Methods.

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

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

jframe.setContentPane(new MyContentPane());

исправить это с помощью:

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

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

Вот полный пример. Запустите его и затем раскомментируйте & quot; f.setVisible (true); & quot; инструкции в классах 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);
    }
}

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

С уважением.

 15 янв. 2014 г., 02:44
Отлично! Не уверен, почему это работает, но это единственное, что решило мою проблему. До этого я делал это: Dimension size = frame.getSize (); Boolean maximized = frame.getExtendedState () == JFrame.MAXIMIZED_BOTH; frame.setSize (new Dimension ((int) size.getWidth () - 1, (int) size.getHeight () - 1)); if (maximized) frame.setExtendedState (JFrame.MAXIMIZED_BOTH); else frame.setSize (size); Ваш ответ намного, намного чище и намного менее хакерский. Спасибо!
 15 янв. 2014 г., 14:13
@ dberm22 на самом деле, нет необходимости взламывать (по крайней мере, в этом примере, не проверял оригинал с изображением, возможно, разных размеров или состояний расширенного размера, что также может быть сложно): установка contentPane is-a является модификацией контейнерной иерархии фрейма и, как таковая, требует revali, даты на фрейме.

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

Ваш ответ на вопрос