Calling one JFrame from another using Timer without any buttons - java

Calling one JFrame from another using Timer without any buttons: time is decreased then open another JFrame without any buttons. Please help. Used in netbeans

Your question is very unclear, but the use of multiple frames is not recommended. As an alternative, consider a modeless dialog, shown below. The dialog's enclosed JOptionPane listens for a PropertyChangeEvent, while counting down from TIME_OUT using javax.swing.Timer. The JOptionPane button is convenient but not required.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.Timer;
/**
* #see https://stackoverflow.com/a/12451673/230513
*/
public class JOptionTimeTest implements ActionListener, PropertyChangeListener {
private static final int TIME_OUT = 10;
private int count = TIME_OUT;
private final Timer timer = new Timer(1000, this);
private JDialog dialog = new JDialog();
private final JOptionPane optPane = new JOptionPane();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new JOptionTimeTest().createGUI();
}
});
}
private void createGUI() {
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
timer.setCoalesce(false);
optPane.setMessage(message());
optPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
optPane.setOptionType(JOptionPane.DEFAULT_OPTION);
optPane.addPropertyChangeListener(this);
dialog.add(optPane);
dialog.pack();
frame.add(new JLabel(frame.getTitle(), JLabel.CENTER));
frame.pack();
frame.setVisible(true);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
timer.start();
}
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (JOptionPane.VALUE_PROPERTY.equals(prop)) {
thatsAllFolks();
}
}
public void actionPerformed(ActionEvent e) {
count--;
optPane.setMessage(message());
if (count == 0) {
thatsAllFolks();
}
timer.restart();
}
private String message() {
return "Closing in " + count + " seconds.";
}
private void thatsAllFolks() {
dialog.setVisible(false);
dialog.dispatchEvent(new WindowEvent(
dialog, WindowEvent.WINDOW_CLOSING));
}
}

Related

JOptionPane.showInputDialog auto exit

With this,
JOptionPane.showInputDialog(null,"Enter Your Name");
I'd like the user input dialog box to auto exit. I mean within 2 or 3 seconds only show that JOptionPane user input dialog and close after that. It should automatically close that input dialog box only, not the whole program. The System.exit(0) method causes the full program to exit, but I want only close that input dialog box not full program. Then I want only Swing input dialog not message box and confirm box.
As shown in How to Make Dialogs, you can add intercept Automatic Dialog Closing in a PropertyChangeListener. Based on this example, the variation below adds a label, prompt, and text field to the option pane. A Swing Timer counts down from TIME_OUT, updating the label each time. The PropertyChangeListener dispatches a WINDOW_CLOSING event when the OK button is pressed or time runs out.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.Timer;
/**
* #see https://stackoverflow.com/a/44417958/230513
* #see https://stackoverflow.com/a/12451673/230513
*/
public class JOptionTimeTest implements ActionListener, PropertyChangeListener {
private static final int TIME_OUT = 10;
private int count = TIME_OUT;
private final Timer timer = new Timer(1000, this);
private final JDialog dialog = new JDialog();
private final JOptionPane optPane = new JOptionPane();
private final JLabel label = new JLabel(message());
private final JLabel prompt = new JLabel("Enter Your Name:");
private final JTextField text = new JTextField("Name");
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new JOptionTimeTest().createGUI();
}
});
}
private void createGUI() {
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
timer.setCoalesce(false);
text.selectAll();
Object[] array = {label, prompt, text};
optPane.setMessage(array);
optPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
optPane.setOptionType(JOptionPane.DEFAULT_OPTION);
optPane.addPropertyChangeListener(this);
dialog.add(optPane);
dialog.pack();
frame.add(new JLabel(frame.getTitle(), JLabel.CENTER));
frame.pack();
frame.setVisible(true);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
timer.start();
}
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (JOptionPane.VALUE_PROPERTY.equals(prop)) {
thatsAllFolks();
}
}
public void actionPerformed(ActionEvent e) {
count--;
label.setText(message());
if (count == 0) {
thatsAllFolks();
}
timer.restart();
}
private String message() {
return "Closing in " + count + " seconds.";
}
private void thatsAllFolks() {
dialog.setVisible(false);
dialog.dispatchEvent(new WindowEvent(
dialog, WindowEvent.WINDOW_CLOSING));
}
}

Use windowFocusListener on a countdown timer

I'm trying to make a countdown timer that only run when the window is on top of my screen.
I tried with this :
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class TimerVisible extends JFrame implements WindowFocusListener{
static TimerVisible frame = new TimerVisible("chrono",2,1,3);//I set a random time
JTextArea display;
private Counter counter;
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addComponentsToPane();
frame.pack();
frame.setVisible(true);
}
private void addComponentsToPane() {
display = new JTextArea();
display.setEditable(true);
JScrollPane scrollPane = new JScrollPane(display);
scrollPane.setPreferredSize(new Dimension(500, 450));
getContentPane().add(scrollPane, BorderLayout.CENTER);
addWindowFocusListener(this);
}
public TimerVisible(String name, int hours, int minutes, int secondes) {
super(name);
counter=new Counter(hours, minutes, secondes); //Counter is in secondes but is created with hours, minutes and seconds
}
public void windowGainedFocus(WindowEvent e) {
displayMessage("WindowFocusListener method called: windowGainFocus.");
try{
while(counter.getCounter()!=0){
Thread.sleep(1000);
displayMessage(counter.toString());
counter.decrement();
}
}
catch(InterruptedException exc){
System.exit(-1);
}
}
public void windowLostFocus(WindowEvent e) {
displayMessage("WindowFocusListener method called: windowLostFocus.");
}
private void displayMessage(String msg) {
display.append(msg+"\n");
System.out.println(msg);
}
}
When I run this program, it display the messages and the countdown on my terminal and not the window, but if I set the while loop under comment, it display correctly the message on the window. Is anybody got an idea why I got this difference?
Thank you
Your while loop is running on the Swing event thread, blocking it and preventing it from painting to the GUI or interacting with the user. Use a Swing Timer instead. Note that with a Swing Timer you won't have a while loop, but instead the actionPerformed will be called repeatedly until you stop the Timer.
Something like this could be close to working (code not tested)
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class TimerVisible extends JFrame implements WindowFocusListener{
private static final int TIMER_DELAY = 1000;
static TimerVisible frame = new TimerVisible("chrono",2,1,3);//I set a random time
JTextArea display;
private Counter counter;
Timer timer = null;
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addComponentsToPane();
frame.pack();
frame.setVisible(true);
}
private void addComponentsToPane() {
display = new JTextArea();
display.setEditable(true);
JScrollPane scrollPane = new JScrollPane(display);
scrollPane.setPreferredSize(new Dimension(500, 450));
getContentPane().add(scrollPane, BorderLayout.CENTER);
addWindowFocusListener(this);
}
public TimerVisible(String name, int hours, int minutes, int secondes) {
super(name);
counter=new Counter(hours, minutes, secondes); //Counter is in secondes but is created with hours, minutes and seconds
}
public void windowGainedFocus(WindowEvent e) {
displayMessage("WindowFocusListener method called: windowGainFocus.");
if (timer != null && timer.isRunning()) {
return;
}
timer = new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (counter.getCounter() <= 0) {
timer.stop();
} else {
displayMessage(counter.toString());
counter.decrement();
}
}
});
timer.start();
}
public void windowLostFocus(WindowEvent e) {
displayMessage("WindowFocusListener method called: windowLostFocus.");
}
private void displayMessage(String msg) {
display.append(msg+"\n");
System.out.println(msg);
}
}

JProgressBar instantiate it self multiple time

I'm trying to add a JProgressBar to a simple program just to learn. So far i can display it, but it adds multiple instance while i want just one to show.
Here's the code :
package package1;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
public class Opening extends JPanel {
private JProgressBar loadingBar;
private Thread t;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
//Loading bar
bar();
}
private void bar()
{
loadingBar = new JProgressBar();
t = new Thread(new LoadMyBar());
this.add(loadingBar).setLocation(25, 600);
loadingBar.setSize(625, 25);
loadingBar.setStringPainted(true);
loadingBar.setValue(0);
loadingBar.setMinimum(0);
loadingBar.setMaximum(100);
t.start();
}
class LoadMyBar implements Runnable
{
public void run(){
for(int i = loadingBar.getMinimum(); i <= loadingBar.getMaximum(); i++)
{
loadingBar.setValue(i);
try
{
t.sleep(1000);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
Any idea on what i'm doing wrong?
You're calling bar() inside of the paintComponent(Graphics g) method. This method is responsible for drawing the component and can be called potentially many times and not in your control. Don't do that, but rather call it once in a constructor or some other location where it can be called just once.
You're also setting the JProgressBar's value off of the Swing event thread, something that can be dangerous to do. Use a Swing Timer instead or use a SwingWorker's progress property together with a PropertyChangeListener.
e.g.,
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class Opening extends JPanel {
private static final int TIMER_DELAY = 1000;
private JProgressBar loadingBar;
private Timer t = new Timer(TIMER_DELAY, new TimerListener());
public Opening() {
bar();
}
private void bar() {
loadingBar = new JProgressBar();
this.add(loadingBar);
loadingBar.setStringPainted(true);
loadingBar.setValue(0);
loadingBar.setMinimum(0);
loadingBar.setMaximum(100);
t.start();
}
private class TimerListener implements ActionListener {
int value = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (value <= 100) {
loadingBar.setValue(value);
value++;
} else {
// value > 100
((Timer) e.getSource()).stop(); // stop timer
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Opening");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new Opening());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You are creating the JProgressBar and adding it to your class Opening in the method paintComponent().
paintComponent() is called every time, the component needs to draw itself.
This can be after resizing the window (JFrame) or some other application overlapping your application.
You should move the initialization to the constructor of Opening.
See http://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html

Using SwingWorker to update the progress of a thread from another class

Value is updated by the end, but not during the process. I guess the reason is that the publish method locates outside the loop.
As to invoke PropertyChangeListener, can it be achieved by defining the class without extends SwingWorker<Void, Void> ?
To address the question in another way, I have two threads locate in two different classes. Is it possible to build communication between the two using SwingWorker?
Class Application
import javax.swing.JFrame;
public class Application {
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
JFrame frame = new Progress();
frame.setSize(200, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Class Progress
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
#SuppressWarnings("serial")
public class Progress extends JFrame{
private JProgressBar progressbar;
public Progress(){
JButton button = new JButton("Run");
progressbar = new JProgressBar(0, 100);
progressbar.setValue(0);
progressbar.setStringPainted(true);
JPanel panel = new JPanel();
panel.add(button);
panel.add(progressbar);
add(panel, BorderLayout.PAGE_START);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
start();
}
});
}
private void start(){
progressbar.setValue(0);
SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>(){
#Override
protected Void doInBackground() throws Exception {
Simulation sim = new Simulation();
publish(sim.getCount());
return null;
}
#Override
protected void process(List<Integer> chunks) {
Integer progress = chunks.get(chunks.size()-1);
progressbar.setValue(progress);
progressbar.repaint();
progressbar.update(progressbar.getGraphics());
}
#Override
protected void done() {
Toolkit.getDefaultToolkit().beep();
}
};
worker.execute();
}
}
Class Simulation
public class Simulation {
private int count;
public Simulation(){
for(int i=0; i<100; i++){
count++;
System.out.println(count);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public int getCount(){
return count;
}
}
How can I update the value during the process?
You need to implement PropertyChangeListener on your SwingWorker and listen to the Progress property changes and then from overridden propertChange() method update your JProgressBar.
Here is what you are looking.
Hope this helps.

SwingWorker Process() warning

I tried to write a simple test program using Swing, all I want to do is load a text file and display the path of the chosen text file in a text area. I keep getting a warning on the process method "never used locally" and it is not appending any text to the textbox. Maybe I'm misunderstanding something, I hope someone can help me.
code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyPanel3 extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextArea jcomp;
private JButton btn;
private String testfile;
public MyPanel3() {
//construct components
jcomp = new JTextArea (1, 1);
jcomp.setBorder(BorderFactory.createDashedBorder(Color.BLACK));
btn = new JButton ("open");
//adjust size and set layout
setPreferredSize (new Dimension (944, 575));
BoxLayout layout = new BoxLayout (this, BoxLayout.Y_AXIS);
setLayout(layout);
//add main components
add (jcomp);
add (btn);
new SwingWorker<Void, String>(){
protected Void doInBackground(){
//do processes...
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
final JFileChooser chooseFile = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(".txt","txt");
chooseFile.setFileFilter(filter);
chooseFile.setAcceptAllFileFilterUsed(false);
chooseFile.setMultiSelectionEnabled(true);
if(ae.getSource().equals(btn))
{
System.out.println("do in background running");
int returnVal = chooseFile.showOpenDialog(MyPanel3.this);
if(returnVal == JFileChooser.APPROVE_OPTION)
{
File[] files = chooseFile.getSelectedFiles();
testfile = files[0].getPath();
publish(testfile);
}
}
}
});
return null;
}
protected void process(String s) {
jcomp.append(s);
}
protected void done() {
try
{
//System.out.println("The operation was completed");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.execute();
}
public static void main(String[] args){
JFrame frame = new JFrame ("MyTest");
frame.getContentPane();
frame.add(new MyPanel3());
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible (true);
}
}
warning reads:
The method process(String) from the type new
SwingWorker(){} is never used locally
EDIT:
with help from MadProgrammer, program is now working (selecting 3 files and printing the paths as strings in the text box)
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyPanel4 extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextArea jcomp;
private JButton btn;
public MyPanel4() {
//construct components
jcomp = new JTextArea(1, 1);
jcomp.setBorder(BorderFactory.createDashedBorder(Color.BLACK));
btn = new JButton("open");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
final JFileChooser chooseFile = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(".txt", "txt");
chooseFile.setFileFilter(filter);
chooseFile.setAcceptAllFileFilterUsed(false);
chooseFile.setMultiSelectionEnabled(true);
int returnVal = chooseFile.showOpenDialog(MyPanel4.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
final File[] files = chooseFile.getSelectedFiles();
new SwingWorker<Void, String>() {
private String testfile1 = files[0].getPath();
private String testfile2 = files[1].getPath();
private String testfile3 = files[2].getPath();
protected Void doInBackground() {
List<String> b = new ArrayList<String>();
b.add(testfile1);
b.add(testfile2);
b.add(testfile3);
publish(b.get(0));
publish(b.get(1));
publish(b.get(2));
return null;
}
#Override
protected void process(List<String> chunks) {
for (String pathname : chunks)
{
jcomp.append(pathname + "\n");
}
}
protected void done() {
try
{
System.out.println("Opration Completed");
} catch (Exception e) {
e.printStackTrace();
}
}
}.execute();
}
}
});
//adjust size and set layout
setPreferredSize(new Dimension(944, 575));
BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
setLayout(layout);
//add main components
add(jcomp);
add(btn);
}
public static void main(String[] args) {
JFrame frame = new JFrame("MyTest");
frame.getContentPane();
frame.add(new MyPanel4());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
The SwingWorker should be created inside the buttons actionPerformed method, so that when you click the button, it will run the SwingWorker
You should, also, make sure that all interactions with user interface are fine from within the context of the Event Dispatching Thread. This means you should ask the user to select the file fro within the context of the actionPerformed method and pass the result to the SwingWorked
Updated
Two additional things...
You're not actually reading the file, but simply passing the name of the file to the publish method
SwingWorker defines process as protected void process(List<V> chunks) but you've defined it as protected void process(String s)...mean that you are actually not overriding the SwingWorker's process method, but creating your own...
Take a look at this example to see how you might be able to use a SwingWorker to read a file...
And, update your process to have the corrected method signature...
#Override
protected void process(List<String> chunks) {
for (String line : chunks) {
output.append(line);
}
}
Remember, you should, as much as possible, use the #Override annotation when you think you are overriding a method, the compiler will tell you when you are mistaken, saving you a lot of head scratching...
It should be like this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyPanel3 extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextArea jcomp;
private JButton btn;
private String testfile;
public MyPanel3() {
//construct components
jcomp = new JTextArea(1, 1);
jcomp.setBorder(BorderFactory.createDashedBorder(Color.BLACK));
btn = new JButton("open");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
final JFileChooser chooseFile = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(".txt", "txt");
chooseFile.setFileFilter(filter);
chooseFile.setAcceptAllFileFilterUsed(false);
chooseFile.setMultiSelectionEnabled(true);
int returnVal = chooseFile.showOpenDialog(MyPanel3.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File[] files = chooseFile.getSelectedFiles();
testfile = files[0].getPath();
new SwingWorker<Void, String>() {
protected Void doInBackground() {
publish(testfile);
return null;
}
protected void process(String s) {
jcomp.append(s);
}
protected void done() {
try {
//System.out.println("The operation was completed");
} catch (Exception e) {
e.printStackTrace();
}
}
}.execute();
}
}
});
//adjust size and set layout
setPreferredSize(new Dimension(944, 575));
BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
setLayout(layout);
//add main components
add(jcomp);
add(btn);
}
public static void main(String[] args) {
JFrame frame = new JFrame("MyTest");
frame.getContentPane();
frame.add(new MyPanel3());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
You are running worker when you are creating panel. But you should run it when button is clicked.

Categories

Resources