I'm new into programming and I'm having some trouble with this.
The problem is, I'm using the Swing palette to create an assignment where I'm using a JDialog to display a timer at the same time of another frame, when I dispose this frame to change to another and return to the previous one the timer in the JDialog overlaps the first one that was running, and I couldn't managed to fix it.
Here's the code.
MAIN
public static void main(String[] args) {
Panel0 screen=new Panel0();
screen.setTitle("");
screen.setLocationRelativeTo(screen);
screen.setVisible(true);
}
1st FRAME
public class Panel0 extends javax.swing.JFrame {
Panel s=new Panel();
private void fisica1ActionPerformed(java.awt.event.ActionEvent evt) {
s.time();
s.setTitle("FISIC I");
s.setLocationRelativeTo(s);
s.setVisible(rootPaneCheckingEnabled);
s.dialog.setVisible(rootPaneCheckingEnabled);
dispose();
}
2nd FRAME
public class Panel extends javax.swing.JFrame {
private void EndActionPerformed(java.awt.event.ActionEvent evt) {
dialog.dispose();
dialog.setDefaultCloseOperation(0);
Panel0 pan=new Panel0();
pan.setLocationRelativeTo(p1);
pan.setVisible(rootPaneCheckingEnabled);
dispose();
}
void time(){
t=new Timer(1,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime<0) {
startTime=System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long clockTime = now - startTime;
if (clockTime >= duration) {
clockTime = duration;
t.stop();
}
SimpleDateFormat sdf=new SimpleDateFormat("mm:ss:SS");
clock.setText(sdf.format(duration-clockTime));
}
});
t.setInitialDelay(0);
if (!t.isRunning()) {
startTime = -1;
t.start();
}
}
I omitted the inizialization of the Timer and such, because I don't think that's the problem.
To clarify something: Once I close the 2nd frame the 1st opens and gives me options to repeat this process over and over, and everytime the JDialog named "dialog" overlaps with its data (you can see the numbers of the clock overlaping).
dispose() does not means that you will "destroy" the object or clear its state. It means that you will release graphics resources attached to that frame (low level window handle and stuff). It still can be reused with setVisible(true)
I assume that you want to reuse our popup - this is just fine, but I think that you are forgetting to stop the "disposed" timer thus every new timer you create on action will be exposed to so called "racing conditions".
Timers are simple background task and they must be stopped explicitly - it will not be done by itself.
Every call to s.time(); starts new timer without stopping previous one.
Simply speaking: you have multiple timers updating the same text field.
Solution: Stop previous timer before running new OR restart previous timer.
Related
I am trying to setup a program that enables the user to display a transition when clicking the next and previous button. When pressing next, the swing timer should trigger and start the animation. When transitioning, there should be a flag that states it is in the transition period. The Swing timer should fire once every tenth of a second and essentially last 1 second.
public class guiCreation {
static Timer timer;
static boolean flag = false;
private static void guiInterface() {
next.addActionListener(new ActionListener(){
timer = new Timer(1000, this);
public void actionPerformed(ActionEvent e){
nextGest();
}
});
//should go to the next tab
previous.addActionListener(new ActionListener(){
//if the list gets to the beginning, disable button
public void actionPerformed(ActionEvent e){
prevGest();
}
});
}
public static void nextGest() {
timer.start();
previous.setEnabled(true);
next.setEnabled(true);
//if the list gets to the end, disable button
if (cardLayout.isNextCardAvailable()) {
status.setText(" Next button has been clicked");
//System.out.println("This is the" + size);
cardLayout.next(cardPanel);
next.setEnabled(cardLayout.isNextCardAvailable());
}
}
public static void prevGest() {
if (cardLayout.isPreviousCardAvailable()) {
timer.start();
next.setEnabled(true);
previous.setEnabled(true);
status.setText(" Previous button has been clicked");
cardLayout.previous(cardPanel);
previous.setEnabled(cardLayout.isPreviousCardAvailable());
}
}
}
This: "The Swing timer should fire once every tenth of a second ..." -- does not agree with this: timer = new Timer(1000, this); Your Timer is firing once every second, not every 10th of a second.
Instead, you should:
Create a new Timer(100, ...), one that fires every 10th of a second
Store in an instance field the start time in msecs when the Timer begins (likely do this in your button's ActionListener)
Within the Timer's ActionListener get the current mSecs and use this to check the elapsed time
Stop the Timer via ((Timer) e.getSource()).stop(); once 1 full second has elapsed
No need for a flag, since all you need to do is to check if the Timer isn't null and if it .isRunning(). e.g., if (timer != null && timer.isRunning()) { -- then the animation is proceeding.
Unrelated suggestion:
Get out of the static world and into the instance world. You're programming in Java, a language that is built to use OOPs from the ground up, and you don't want to fight against the OOPs paradigm.
I want to create a program that when a button is clicked, a panel may or may not change it's color. I have an array of panels that will turn red if a wrong combination is chosen. But I just want to make it red for about 1-2 seconds. After that I will change again the panel background to null. I want every panel to have it's own timer when it goes red. So far here is my code:
javax.swing.Timer timer = new javax.swing.Timer (250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pnlArray [count - 2][count2].setBackground (Color.RED);
};
});
pnlArray [count - 2][count2].setBackground (null);
This code generates an error: local variables referenced from an inner class must be final or effectively final. Obviously, pnlArray[][] is not a final panel. Thread.sleep() method however, freezes the whole program. How can I achieve this?
I found a solution to my question using java.util.Timer package. Since the Timer() class needs final to run the run() method, I assigned the JPanel to a final variable. Then I canceled the timer once the first delay is over.
final JPanel pnlChange = pnlArray [count - 2][count2];
pnlChange.setBackground (Color.RED);
java.util.Timer timer = new java.util.Timer ();
TimerTask task = new TimerTask () {
int seconds = 4;
int divisor = 0;
#Override
public void run() {
divisor++;
if (divisor % seconds == 0) {
timer.cancel ();
pnlChange.setBackground (null);
}
}
};
timer.schedule(task, 0, 1000);
This post relates to my last one regarding a timer. I decided the easiest thing to do for immediate results was to just write a Counter thread that counts down from a certain time (in this case 5 seconds) and if the counter reaches 0, the JFrame closes and let's the user know that time has expired.
I'm running into some trouble, however. I cannot seem to make the JFrame close when the counter reaches 0. I'm not sure if I'm missing something stupid or if I am misunderstanding the way threads work and the way JFrames work. Here is the code, let me know what you think.
On a side note, I understand it would probably be most efficient to use a swing.Timer, but I just don't quite grasp the nature of them yet. I'm under self-imposed time constraints (I'm not a student or anything, I just like to stay motivated) and so I'm "jerry-rigging" this thing for now.
Anyway, on to the code!
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
public class RacerDoom extends JFrame {
boolean timesUp=false;
public RacerDoom() {
//create JFrame
super("Racer Doom Squared");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
if(timesUp==true) {
dispose();
JOptionPane.showConfirmDialog(null, "Time's Up! Click Okay to try again!");
}
Counter c1 = new Counter();
c1.start();
//Counter
private class Counter extends Thread {
public Counter() {}
public void run() {
for(int i=5;i>=0;i--) {
if(i==0) {
timesUp=true;
}
System.out.println(i);
try{
Thread.sleep(1000);
}
catch(InterruptedException e){}
}
}
}
...
EDIT: I have the timer implemented and working. It does exactly what I need it to, but I can't get the timer.stop(); command to work. I get the error "The local variable timer may not have been initialized.
Like I said, the timer works, it just never stops working until the program is terminated. Here is the constructor code for the JFrame, where the timer is located.
int counter = 0;
public RacerDoom() {
//create JFrame
super("Racer Doom Squared");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
final Timer timer=new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(counter>=10) {
timer.stop(); //the error occurs here
dispose();
JOptionPane.showConfirmDialog(null, "Time's Up!");
}
else{
counter++;
}
System.out.println(counter);
}
});
//inner thread
Move1 m1 = new Move1();
m1.start();
timer.start();
}
Thats easy to do with the help of a swing timer.. See this code sample:
final java.swing.Timer timer=new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(counter>5) {
timer.stop();
<dispose the fram here>
}else{
counter++;
}
}
});
timer.start();
I put this code in the constructor of my JFrame which will run in the Event despatch thread. If you dont want hang up your GUI, make sure that you run this timer on another thread and when you are disposing the JFrame wrap the call with SwingUtilities.invokeLater() - This ensures that the call gets queued on the event despatch thread.
I think your code is not working for the same reason, that you trying to something that does not get queued up in the event despatch thread. Here's an article that will get you going
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
How can I update the JProgressBar.setValue(int) from another thread?
My secondary goal is do it in the least amount of classes possible.
Here is the code I have right now:
// Part of the main class....
pp.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
new Thread(new Task(sd.getValue())).start();
}
});
public class Task implements Runnable {
int val;
public Task(int value){
this.val = value;
}
#Override
public void run() {
for (int i = 0; i <= value; i++){ // Progressively increment variable i
pbar.setValue(i); // Set value
pbar.repaint(); // Refresh graphics
try{Thread.sleep(50);} // Sleep 50 milliseconds
catch (InterruptedException err){}
}
}
}
pp is a JButton and starts the new thread when the JButton is clicked.
pbar is the JProgressBar object from the Main class.
How can I update its value?(progress)
The code above in run() cannot see the pbar.
Always obey swing's rule
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.
What you can do is to create an observer that will update your progress bar -such as
- in this instance you want to show progress of data being loaded on click of a button.
DemoHelper class implements Observable and sends updates to all observers on when certain percent of data is loaded.
Progress bar is updated via public void update(Observable o, Object arg) {
class PopulateAction implements ActionListener, Observer {
JTable tableToRefresh;
JProgressBar progressBar;
JButton sourceButton;
DemoHelper helper;
public PopulateAction(JTable tableToRefresh, JProgressBar progressBarToUpdate) {
this.tableToRefresh = tableToRefresh;
this.progressBar = progressBarToUpdate;
}
public void actionPerformed(ActionEvent e) {
helper = DemoHelper.getDemoHelper();
helper.addObserver(this);
sourceButton = ((JButton) e.getSource());
sourceButton.setEnabled(false);
helper.insertData();
}
public void update(Observable o, Object arg) {
progressBar.setValue(helper.getPercentage());
}
}
Shameless plug: this is from source from my demo project
Feel free to browse for more details.
You shouldn't do any Swing stuff outside of the event dispatch thread. To access this, you need to create a Runnable with your code in run, and then pass that off to SwingUtilities.invokeNow() or SwingUtilities.invokeLater(). The problem is that we need a delay in your JProgressBar checking to avoid jamming up the Swing thread. To do this, we'll need a Timer which will call invokeNow or later in its own Runnable. Have a look at http://www.javapractices.com/topic/TopicAction.do?Id=160 for more details.
There is need not to call pbra.repaint explicitly.
Update JProgressBar shall be done through GUI dispatch thread.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Remember to make pbar final variable.
pbar.setValue(i);
}
});
What is the proper way to terminate a Swing application from the code, and what are the pitfalls?
I'd tried to close my application automatically after a timer fires. But just calling dispose() on the JFrame didn't do the trick - the window vanished but the application did not terminate. However when closing the window with the close button, the application does terminate. What should I do?
Your JFrame default close action can be set to "DISPOSE_ON_CLOSE" instead of EXIT_ON_CLOSE (why people keep using EXIT_ON_CLOSE is beyond me).
If you have any undisposed windows or non-daemon threads, your application will not terminate. This should be considered a error (and solving it with System.exit is a very bad idea).
The most common culprits are java.util.Timer and a custom Thread you've created. Both should be set to daemon or must be explicitly killed.
If you want to check for all active frames, you can use Frame.getFrames(). If all Windows/Frames are disposed of, then use a debugger to check for any non-daemon threads that are still running.
I guess a EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
before System.exit(0) is better since you can write a Window Listener to make some cleaning operations before actually leaving the app.
That window listener allows you to defined:
public void windowClosing(WindowEvent e) {
displayMessage("WindowListener method called: windowClosing.");
//A pause so user can see the message before
//the window actually closes.
ActionListener task = new ActionListener() {
boolean alreadyDisposed = false;
public void actionPerformed(ActionEvent e) {
if (frame.isDisplayable()) {
alreadyDisposed = true;
frame.dispose();
}
}
};
Timer timer = new Timer(500, task); //fire every half second
timer.setInitialDelay(2000); //first delay 2 seconds
timer.setRepeats(false);
timer.start();
}
public void windowClosed(WindowEvent e) {
//This will only be seen on standard output.
displayMessage("WindowListener method called: windowClosed.");
}
Try:
System.exit(0);
Crude, but effective.
May be the safe way is something like:
private JButton btnExit;
...
btnExit = new JButton("Quit");
btnExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
Container frame = btnExit.getParent();
do
frame = frame.getParent();
while (!(frame instanceof JFrame));
((JFrame) frame).dispose();
}
});
The following program includes code that will terminate a program lacking extraneous threads without explicitly calling System.exit(). In order to apply this example to applications using threads/listeners/timers/etc, one need only insert cleanup code requesting (and, if applicable, awaiting) their termination before the WindowEvent is manually initiated within actionPerformed().
For those who wish to copy/paste code capable of running exactly as shown, a slightly-ugly but otherwise irrelevant main method is included at the end.
public class CloseExample extends JFrame implements ActionListener {
private JButton turnOffButton;
private void addStuff() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
turnOffButton = new JButton("Exit");
turnOffButton.addActionListener(this);
this.add(turnOffButton);
}
public void actionPerformed(ActionEvent quitEvent) {
/* Iterate through and close all timers, threads, etc here */
this.processWindowEvent(
new WindowEvent(
this, WindowEvent.WINDOW_CLOSING));
}
public CloseExample() {
super("Close Me!");
addStuff();
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
CloseExample cTW = new CloseExample();
cTW.setSize(200, 100);
cTW.setLocation(300,300);
cTW.setVisible(true);
}
});
}
}
If I understand you correctly you want to close the application even if the user did not click on the close button. You will need to register WindowEvents maybe with addWindowListener() or enableEvents() whichever suits your needs better.
You can then invoke the event with a call to processWindowEvent(). Here is a sample code that will create a JFrame, wait 5 seconds and close the JFrame without user interaction.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ClosingFrame extends JFrame implements WindowListener{
public ClosingFrame(){
super("A Frame");
setSize(400, 400);
//in case the user closes the window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
//enables Window Events on this Component
this.addWindowListener(this);
//start a timer
Thread t = new Timer();
t.start();
}
public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){}
//the event that we are interested in
public void windowClosed(WindowEvent e){
System.exit(0);
}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
//a simple timer
class Timer extends Thread{
int time = 10;
public void run(){
while(time-- > 0){
System.out.println("Still Waiting:" + time);
try{
sleep(500);
}catch(InterruptedException e){}
}
System.out.println("About to close");
//close the frame
ClosingFrame.this.processWindowEvent(
new WindowEvent(
ClosingFrame.this, WindowEvent.WINDOW_CLOSED));
}
}
//instantiate the Frame
public static void main(String args[]){
new ClosingFrame();
}
}
As you can see, the processWindowEvent() method causes the WindowClosed event to be fired where you have an oportunity to do some clean up code if you require before closing the application.
Take a look at the Oracle Documentation.
Starting from JDK 1.4 an Application terminates if:
There are no displayable AWT or Swing components.
There are no native events in the native event queue.
There are no AWT events in java EventQueues.
Cornercases:
The document states that some packages create displayable components without releasing them.A program which calls Toolkit.getDefaultToolkit() won't terminate. is among others given as an example.
Also other Processes can keep AWT alive when they, for what ever reason, are sending events into the native event queue.
Also I noticed that on some Systems it takes a coupple of seconds before the Application actually terminates.
I think, the idea is here the WindowListener - you can add any code there that you'd like to run before the thing shuts down
In response to other comments, DISPOSE_ON_CLOSE does not seem to properly exit the application - it only destroys the window, but the application will continue running. If you want to terminate the application use EXIT_ON_CLOSE.