I'm not confident with Java, but I'm developing a tool for monitoring our company Server HDisks because of some problems we have.
I've been creating a simple frame with a simple menu and a JPanel with some information, but it is not important.
My idea is simply: press the JButton of the JFrame, then my service (which is a class extends Thread and sleeps for a while each cycle) starts.
I made all the classes, but I have this problem: when I press the button, the background class starts, but I lose control of the main frame.
How can I separate the frame class between my background class?
then my service (which is a Class extends Thread and sleeps for a while each cycle) starts. I made all the classes, but I have this problem: when I press my JButton, the background class starts, but I loose control of the main JFrame.
Not exactly sure what "loose control of the main JFrame" means. But I'm guessing it no longer responds to user events.
This would be because your Thread.sleep is causing the Event Dispatch Thread (EDT) to sleep, so you are either:
not creating the Thread correctly, or
sleeping the wrong Thread.
In any case I would suggest that in the ActionListener you add to your button that you start a SwingWorker. A SwingWorker will create the Thread for you and it allows you to communicate properly with the frame.
Read the section from the Swing tutorial on Concurrency for more information and examples to get you started. The tutorial will explain more about the EDT.
Could you provide more information?
But for what I understood you should add an event listener to your JButton.
Example code:
BackGroundThread task = new BackGroundThread();
JButton btn = new JButton("Run task");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
task.start();
}
});
Related
Through some searching, I made about ActionListeners and GUI. I think I have come to a conclusion that all the changes you do that affect the GUI, in the ActionListener, actually happen when ActionListener comes to it's end
I am currently making a memory game. In the action listener of a card button I first flip the image (that changes it's icon) and the I check if a have a match and in the case I don't have one I close the card(change icon).
Since those two happen in the same actionListener as a result if I dont have a match I only see the first card I pick and he second seems to no react to flip.
Sorry if it's confusing how I explain it. I think that the problem is the actionListener but maybe I am wrong. What would you suggest?
c.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae){
selectedCard = c;
String imgName = "Images/"+c.getId()+".jpg";
URL imageURL = this.getClass().getResource(imgName);
if (imageURL != null) {
ImageIcon icons = new ImageIcon(imageURL);
c.setIcon(icons);
}
c.setEnabled(false);
c.setDisabledIcon(c.getIcon());
pl.singlePlay(c);
if(pl.getMatch()==false){
for (Cards cd : cards){
if(cd.getMatched()==false){
cd.setEnabled(true);
cd.setIcon(icon);
}
}
}
});
I have come to a conclusion that all the changes you do that affect the GUI, in the ActionListener, actually happen when ActionListener comes to it's end
Yes, all code invoked from any listener executes on the Event Dispatch Thread (EDT). This thread is responsible for updating the GUI and so the GUI can't be updated until the code has finished executing. Read the section from the Swing tutorial on Concurrency for more information.
Since those two happen in the same actionListener
If you want to schedule animation, that is show one Icon and then seconds later show another Icon, then you can use a Swing Timer. The Timer allows you to schedule another event. The tutorial link from above also has a section on How to Use Swing Timers to get you started.
In Java, I'm using an ActionListener for an array of JButtons. I would like for an earlier part of the ActionListener to set a new ImageIcon to a JButton, that change to be displayed immediately, then near the end of the ActionListener to set the JButton's ImageIcon back to null after a second long delay.
My problem is that none of the changes that happen to the JButton get displayed in the GUI window that it is set in until the ActionListener is completely finished, making the change in the JButton's ImageIcon unnoticeable. Is there any way to make an ActionListener commit a change to a JButton before it has finished executing the entire ActionListener, or should I be going about this differently?
The reason this is happening:
Swing repaints the buttons on the same thread (EDT) as the ActionListener is ran on. Hence if it is executing you ActionListener it cannot repaint since the thread is busy - as simple as that. You may have noticed that while your action listener is executing you also can't properly move your frames around etc. (GUI freezes up).
The solution:
Move heavy processing outside the EDT. It doesn't belong there anyway. As you could have guessed - use a background thread/thread pool for that. A good guide to it is Swing tutorial for concurrency
Notes:
As portrayed in the guide you do not want to modify components outside the EDT. As such the easiest strategy is to make a Runnable to execute on a background thread, start it, change the picture on the button and return without waiting for the task to finish.
public void actionPerformed(ActionEvent ae) {
Runnable task = new Runnable() {..};
executor.execute(task);
button.setIcon(newIcon);
return;
}
Note that this doesn't lock up the EDT for the task, hence allowing Swing to change the picture immediately.
This of course means that the user has no idea if the task has finished or not (And if there were any exceptions)! It is in the background after all! Hence there is an extra state of your execution: GUI is responsive and non-frozen, button is changed, but task is still running. In most applications this may be a problem (the user will spam the button or your background tasks may interleave). In that case you may want to use a SwingWorker to have a "processing" state as well.
public void actionPerformed(ActionEvent ae) {
new TaskWorker().execute();
button.setIcon(loadingIcon); //Shows loading. Maybe on button, maybe somewhere else.
return;
}
private class TaskWorker extends SwingWorker<Void, T> {
public Void doInBackground() {
//Do your task in the background here
}
protected void done() {
try {
get();
button.setIcon(doneIcon);
catch (<relevant exceptions>) {
button.setIcon(failedIcon);
}
}
}
Here done() is called on the EDT when doInBackground() is finished.
You could create a new Thread or a Thread from a Thread pool if you have one. And with that let the task work on a seperate Thread so that the ActionListener returns immediatly. And then in the other Thread you do your code and repaint the button. This is by the way a threory I'm not sure if it will work.
I am very new to Swing.
I have
itemActionButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg) {
itemAction();
}
});
But when the button is clicked, instead of running this action on another thread, I would like the parent's form's thread to wait until it the action is completed before refreshing, allowing additional clicks, etc.
How can I do this?
Code in the ActionListener executes on the EDT, which prevents the GUI from repainting and responding to other events.
If you have a long running task and you don't want to block the EDT then you need to use another Thread.
Read the section from the Swing tutorial on Concurrency for more information and a solution by using a SwingWorker.
I have written a small code in java for simpleGUI.
package guidemo1;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class GuiDemo1 implements ActionListener{
JButton button;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
GuiDemo1 gui=new GuiDemo1();
gui.go();
}
public void go()
{
JFrame frame=new JFrame();
button=new JButton();
frame.getContentPane().add(button);
button.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
button.setText("I've been clicked");
}
}
I am newbie to JAVA.I have few questions related to this program.
Can some one explain how actionPerformed method gets executed with out any call?
Here I have defined frame object locally to the go() method and we are using button in actionPerformed which is another method.How is that possible?Isn't the button gets embedded on the frame?
Thanks..
Welcome to an event driven environment.
In this environment, you register "listeners" that wait until something happens and then report back to you via a well defined interface structure.
Basically, what's a happening, is you registered yourself as an interested party to action events that may occur on a button. You've done this by implementing the ActionListener interface. This allows the button, when an action is performed to call back to your actionPerformed method at some time in the future.
This is commonly known as an observer pattern.
You might find Writing Event Listeners a useful read
Your class implements ActionListener, so you have to define the actionPerformed method. You also call button.addActionListener(this) which registers the current object as the listener for the button press.
When a button press event is triggered, all the listeners will be notified, including the object that you have registered as a listener.
Can some one explain how actionPerformed method gets executed with out any call?
The GUI framework Swing runs action handling code in the background. Whenever a button is pressed or the user interacts with the GUI in some other way, Swing will notify your application through one of many Listener interfaces. In order to receive these events, your class needs to implement the proper Listener interface and be registered as a listener on each component it is interested in.
Your class implements the ActionListener interface and calls addActionListener to register itself to the button. When a button is clicked, Swing will attempt to notify all registered ActionListeners by calling their actionPerformed method. That's how the "magic" happens.
Here I have defined frame object locally to the go() method and we are using button in actionPerformed which is another method.How is that possible?Isn't the button gets embedded on the frame?
You add the button to the frame's content pane - this puts the button inside the frame in your layout, not in your code. Because you declare button as an instance variable by putting JButton button; outside any method, it is still accessible from any (non-static) method in that class.
As for the second question, Java is a reference language. All objects reside on the heap and are alive as long as someone holds the reference to them.
In Swing, the case is a little bit more complicated. The Swing library holds reference to all GUI elements (such as JFrame and JButton), so that's why they don't get deleted, even if you don't hold reference to them any more.
As for the first question, look at what the main thread does - it creates a new object GuiDemo1, calls the go() method which creates a JFrame, and displays that frame. There is a special Swing thread, the Event Dispatch Thread, that waits in the background for events in the GUI to happen. Displaying the frame starts the EDT which then renders the frame and sleeps. The main thread, having completed all the work in the main method then DIES.
Now you have a JFrame displayed and Event Dispatch Thread sleeping. The EDT is now waiting for user interaction (events) with the JFrame - the Swing is event-driven. Each time you interact with the frame, Swing creates an event for it and wakes the EDT to handle the event. So for example, if you click a button, the EDT wakes, animates the button "click" and calls all action listeners. Thats when your method actionPerformed gets called.
implement ActionListener
add ActionListener to your interface
add actionPerformed method to your class
set a timer and start it in your class
that will do it
I'm just getting to grips with GUI programming in java. Here is a trivial program (from O'Reilly's "Head First Java") which on the face of it looks easy to understand, but there's an aspect of it which I don't follow.
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame frame=new JFrame();
JButton button = new JButton("click me");
frame.getContentPane().add(button);
frame.setSize(300,300);
frame.setVisible(true);
}
}
This simple program, when compiled and run, will open a window with a button on it.
What I don't understand is what is happening with the flow of execution. When I run this program, the static main method of the Test class runs, all the commands in main() are executed -- so why doesn't the process terminate after the window appears? Why am I still sitting on what looks like an infinite loop? What is looping?
If I add the line
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
then I find the result even more imcomprehensible. Now, of course, the program terminates
once I've closed the window. But again I don't see why. The frame will be on the stack but I don't see where the program flow is and just the existence of something on the stack is not enough to keep the program alive, surely? I'm missing something fundamental which as far as I can see is not covered in the book I'm reading. I am slightly surprised by this -- "Head first Java" has been very good up until now at pointing out subtleties and explaining what is really going on, but doesn't seem to address this point (at least not that I've spotted).
why doesn't the process terminate after the window appears?
Because the Java Virtual Machine exits only after all non-daemon threads have finished. While not apparent, there's in fact two threads in your program: the main thread, and the event dispatching thread, which does everything related to the Swing GUI components. The event dispatching thread keeps going as long as any GUI components are visible.
Actually the program, while it may work, is wrong, because you're creating and accessing Swing components from the main thread. You ought to be doing all GUI work in the event dispatching thread. That is, it should be something like:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
JFrame frame=new JFrame();
JButton button = new JButton("click me");
frame.getContentPane().add(button);
frame.setSize(300,300);
frame.setVisible(true);
});
}
The Java process terminates when the last non-demon thread dies. Normally there is just one, the main thread. When you display Swing components additional non-demon threads for event dispatching and GUI shotdown are started. Those terminate when the last top-level component gets disposed. In your sample the main thread dies after leaving the main method. You can have a look into the threads with a debugger or jvisualvm from the JDK tools.
The rest of the GUI flow is event driven. When you e.g. click on the frame's close button an event is generated and sent to the appropriate listeners within the event dispatching thread.
Setting JFrame.EXIT_ON_CLOSE as default close operation is like adding a default event listener to the frame. A quite harsh one, it just shuts down the JVM without respect to the rest of the application's state.