1

I am a bit sorry to ask this question, since it seems to be a bit obvious, but I can't find my solution alone.

I am coding a little app in Java, and I encounter some issues "redrawing" my swing components. Basically, I want my JFrame to update when an event occurs. I managed to reproduced the issue in the code below. This code is supposed to display two buttons (which it does), and replace them with a third button when you click on the first button (which it doesn't).

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example extends JFrame implements ActionListener {

    private JButton button = new JButton("Button 1");
    private JButton button2 = new JButton("Button 2");
    private JButton button3 = new JButton("Button 3");
    private JPanel buttons = new JPanel();

    public void init() {
        this.setVisible(true);
        this.setSize(500,500);
        buttons.add(button);
        buttons.add(button2);
        this.add(buttons);
        this.button.addActionListener(this);
    }

    public void update() {
        this.removeAll();
        buttons.add(button3);
        this.revalidate();
    }

    public static void main(String[] args) {
        Example ex = new Example();
        ex.init();
    }

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button) {
            update();
        }
    }
}

I am pretty sure that I am doing something wrong in the update() method. I actually have a lot of trouble to understand how works removeAll(), revalidate(), repaint() etc, and I guess that is the problem. I tried to call the same methods on the buttons panel, it almost worked but I still have a graphic bug, and I would like to do it for all the container. I also tried to call these methods on this.getContentPane(), but it doesn't work.

Can anyone try to help me with it?

Frakcool
  • 10,915
  • 9
  • 50
  • 89
Francois51
  • 381
  • 2
  • 15

2 Answers2

3

You're removing all components from this (which in this case is the JFrame (as you're extending it, which isn't needed, and instead you should create an instance from it rather than inherit from it, as you're not changing the behavior of the JFrame so it's better to just create an instance of it). See: Extends JFrame vs. creating it inside the program

In this case you're adding your components in this way:

JFrame > buttons (JPanel) > JButtons

And you're trying to remove

JFrame > everything

That includes the contentPane, instead you should call.

buttons.removeAll()

Inside the update() method.

And also call this.repaint() so your update() method should become:

public void update() {
    buttons.removeAll();
    buttons.add(button3);
    this.revalidate();
    this.repaint();
}

Or the best approach is to use CardLayout as recommended by @AndrewThompson in the comment below. This way you don't have to handle removing / repainting for each component, as CardLayout will do it for you. For example

Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • 2
    *"..instead you should.."* Use a [`CardLayout`](http://download.oracle.com/javase/8/docs/api/java/awt/CardLayout.html), as it was *designed* for this type of situation. – Andrew Thompson May 07 '20 at 16:41
  • 1
    You're right @AndrewThompson I forgot to mention about Card Layout, in my mind I was thinking about it, then forgot to mention it. – Frakcool May 07 '20 at 16:56
  • 1
    *"I was thinking about it, then forgot to mention it"* Ah yes, that makes sense. To be honest, I value your experience enough to have been surprised that it was not mentioned, but 'forgot' explains perfectly. I regularly do that, and it's only when coming back to an answer hours (up to years) later that I spot the omission. Or when someone prompts we with words to the effect *"What about..?"* ;) – Andrew Thompson May 08 '20 at 00:25
  • 1
    I'm not as experienced as you, MadProgrammer, Hovercraft or many others in Swing, most of my knowledge comes from answering questions in Swing here but been recognized by someone like you makes me cry tears of joy :') once again thanks for pointing it out – Frakcool May 08 '20 at 00:32
  • Thank you very much for your answers. I actually simplified a bit my problem, so I am not sure the CardLayout will be my solution, but I think I should be ok now. Still, I don't really understand : if I call removeAll on my "buttons" Panel, why can't I call revalidate on it too? Also, I don't get why we need revalidate AND repaint, but that's a lot of questions, maybe for another time... – Francois51 May 09 '20 at 08:54
0

this works,

public void update() {
    buttons.remove(button);
    buttons.remove(button2);
    buttons.add(button3);
    this.revalidate();
    this.repaint();
}
Erwin
  • 460
  • 2
  • 6