Member Avatar for jaredleo999

Basically When i click b1 in the Pincode method i want the Balance(); method to run and display a JButton "2" but i want to clear the frame and panel first, so it looks as if its a new frame...

Any help is much appreciated thanks! :)

import java.awt.*;
import javax.swing.*;
import java.text.*;
import java.lang.*;
import java.awt.event.*;

public class Test {
	public static JFrame Frame = new JFrame("Test");
	
	public static void Pincode() {
		
		
		Frame.setSize(1440,900);
		Frame.setVisible(true);
		Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel panel = new JPanel();
		panel.setLayout(null);
		Frame.add(panel);
		
		JButton b1 = new JButton("1");
		b1.setBounds(570,300,100,100);
		panel.add(b1);
		b1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
            	    
            	    Balance();
            }
        });
	
	
	
	}
	public static void Balance() {
		
		Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel panel = new JPanel();
		panel.setLayout(null);
		Frame.add(panel);
		
		JButton b2 = new JButton("2");
		b2.setBounds(570,300,100,100);
		panel.add(b2);
	}
	
	public static void main(String [] args){
		Pincode();
	}
	


}

Recommended Answers

All 17 Replies

@BestJewSinceJC the problem in that code is not the call of the RemoveAll method only, but I think that is a question of thread synchronisation;
because the button that execute the action listener try to remove it self will its action listener does not returns yet.

No, it has nothing to do with thread synchronization. The JFrame removes all of its child components. Even if the JFrame made changes to the JButton when it removes the button, it would not cause any thread synchronization problems, since there is only one thread in the OP's program, which is the main() thread.

If it is so try to call removeAll on the button in it's action listener and you will see that it will not.
Swing components can be accessed by only one thread at a time. Generally, this thread is the event-dispatching thread if we exclude a few operations that are guaranteed to be thread-safe.
there can be no denying that If we need access to the UI from outside event-handling or drawing code, then we can use the SwingUtilities or EventQueue with invokeLater function; this is because "once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread."
And Just try to remove this button with it's own action listener please.

Hope it helps.

Agreed with what you said above, as the Java documentation says. What is the synchronization error in the below code? It looks like it works to me. Like I said above, as far as I'm concerned, only one thread in this program access the UI components, and that is the main() thread.

public class Test {
	public JFrame Frame = new JFrame("Test");
	
	public Test() {
		Frame.setSize(1440,900);
		Frame.setVisible(true);
		Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		final JPanel panel = new JPanel();
		Frame.add(panel);
		
		JButton b1 = new JButton("1");
		panel.add(b1);
		b1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
            	 	panel.removeAll();
            	 	Frame.repaint();
            }
        });

	
	}
	
	public static void main(String [] args){
		new Test();
	}
}

Sure the remove is a methode of the Frame; but it is called in side the JButton.

The addActionListener adds a listener to the listenerList that is variable of type EventListenerList of the JButton (in fact the listenerList is declared in the JComponent and the JButton inherite it from)
Thus the execution of the actionPerformed of the the action listen is called inside the JButton while that action try to remove the same button that is actualy executing the action.

.. I still don't see how this is an issue. The code I posted above appears to work. Are you saying it doesn't or has hidden errors? @ OP: terribly sorry for jacking your thread, too interesting now though

:)

I'm sorry to tell you that the code does not work for me when I try to execute it more that ones ; some time the button apear some time it does not.
the situation is worst with an uspected behaviour if you make this chage:

Frame.removeAll();

in stead of

panel.removeAll();

This code is wrong.

But when I test this main method

public static void main(String[] args) {
         java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Test();
            }
        });
        
    }

The button disapper only if the removeAll is called over the JPanel like you wrote:

panel.removeAll();

but not with JFrame:

Frame.removeAll();

I'm realy sorry if you still don't see how this is an issue.

I agree with you about the general Swing knowledge. Of course, it is always a best practice to run code on the EDT. I'm simply unable to produce a buggy test case thus far for this problem, so it is hard for me to see how it is an issue here.

The right way to do this follows:

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

/**
 *
 * @author Moutanna
 */
public class Test {

    public JFrame Frame = new JFrame("Test");
    Container content = Frame.getContentPane();

    public Test() {
        Frame.setSize(1440, 900);
        Frame.setVisible(true);
        Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel(null);
        Frame.add(panel);

        JButton b1 = new JButton("1");
        b1.setBounds(570, 300, 100, 100);
        panel.add(b1);
        //Just for test
        panel.setBackground(Color.red);
        b1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                JButton b2 = new JButton("2");
                content.removeAll();
                JPanel panel = new JPanel(null);
                 //Just for test
                panel.setBackground(Color.green);
                b2.setBounds(570, 300, 100, 100);
                panel.add(b2);
                content.add(panel);
                ((JPanel) content).revalidate();

            }
        });


    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Test();
            }
        });

    }
}

Yet, I have already stated that I agree with you that invoking on the EDT is the best practice. I've already read the Java Sun documents on Swing, as well as many of their examples that use code doing so. But that still ignores the question I asked, which is "why is the code that I provided previously buggy."

Btw, the code in the actionPerformed method always runs in the Event Dispatch Thread, as stated here. Maybe I misunderstand that document or I misunderstand you, because I thought you were implying otherwise elsewhere in this thread.

edit:

Anyway, I'm really not trying to be frustrating, so if it is frustrating to you, just stop replying and someone else will give their input/reasoning as to why you're right later.

Interesting conversation, may I join in please?
BJSJC: your statement about "only one thread" in posts #4 and #6 is wrong, there's also the EDT, as you note later.
moutanna's post #7 is very misleading. The listener method is NOT called "inside the button"; the method is running on the EDT for an instance of a Listener class whose execution is not going to be affected by changes to a component that happens to have a reference to it.
Constructing a window from a main thread may not be what the API doc recommends, but it is very common practice and never seems to create a problem provided that the window is only made visible as the last step. If (as in the posted code) the setVisible comes early you could theoretically get a semi-constructed window displayed followed by unpredicable stuff if the EDT happens to interrupt the main thread while it's still configuring the window.

Thinks James yo'r right; the setVisible should be called after adding all components to the container. Above all I focused on actionPerformed method, the point here is to use the container with some cast to clear the JFrame and then add other components.
In fact the common way is to de clare a class that extends a JFrame,
add all components i it's constructor and then call the setVisible on it in the run method.
Some thing like:

public class Test extends JFrame{
public Test(){
//Add all components here and add the listeners ....
}

public static void main(){
java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Test().setVisible(true);
            }
        });
}
}

And the whole class could look like:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Test extends JFrame {

    public Test() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1440, 900);
        JPanel panel = new JPanel();
        panel.setLayout(null);
        //Just for test
        panel.setBackground(Color.orange);
        add(panel);
        JButton b1 = new JButton("1");
        b1.setBounds(570, 300, 100, 100);
        panel.add(b1);
        b1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent event) {
                Balance();
            }
        });
    }

    public void Balance() {
        JButton b2 = new JButton("2");
        getContentPane().removeAll();
        JPanel panel = new JPanel(null);
        //Just for test
        panel.setBackground(Color.green);
        b2.setBounds(570, 300, 100, 100);
        panel.add(b2);
        getContentPane().add(panel);
        ((JPanel) getContentPane()).revalidate();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Test().setVisible(true);
            }
        });

    }
}

Hope it helps.

Interesting conversation, may I join in please?
BJSJC: your statement about "only one thread" in posts #4 and #6 is wrong, there's also the EDT, as you note later.
moutanna's post #7 is very misleading. The listener method is NOT called "inside the button"; the method is running on the EDT for an instance of a Listener class whose execution is not going to be affected by changes to a component that happens to have a reference to it.
Constructing a window from a main thread may not be what the API doc recommends, but it is very common practice and never seems to create a problem provided that the window is only made visible as the last step. If (as in the posted code) the setVisible comes early you could theoretically get a semi-constructed window displayed followed by unpredicable stuff if the EDT happens to interrupt the main thread while it's still configuring the window.

Agreed, I actually didn't realize about the EDT until I put the SwingUtilities.isEventDispatchThread() test in the actionPerformed method, as I mentioned in my previous post. Good info though, thank you for the input.

edit:

P.S. I agree about the setVisible, I hadn't noticed that the OP put it before other relevant code or I would have moved that call to after the frame was fully constructed.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.