I have Java Swing code that process user's input as follows:
public class UserEntryPane extends JPanel implements DocumentListener {
…
#Override
public void insertUpdate(DocumentEvent e) {
try {
String c = a.getText(...);
if (c.equals("\n")) {
System.out.println(...);
...
}
else {
...
}
} catch (Exception e) {
e.printStackTrace();
}
}
The issue is that this method is not invoked when Backspace is pressed. How can I detect user's Backspace to process it correctly?
Seems you use DocumentListener.
Look at method removeUpdate. It called, when you use backspace.
#Override
public void removeUpdate(DocumentEvent arg0) {
}
import java.awt.FlowLayout;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class UseBackSPace extends JFrame
{
Robot r;
void start()
{
try
{
JFrame f = new JFrame("UseBackSPace");
JTextField txt = new JTextField(20);
f.add(txt);
f.setSize(500, 200);
f.setVisible(true);
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
// f.setLocation(400, 400);
r = new Robot();
r.setAutoDelay(900);
r.keyPress(KeyEvent.VK_T);
r.keyPress(KeyEvent.VK_H);
r.keyPress(KeyEvent.VK_I);
r.keyPress(KeyEvent.VK_S);
r.keyPress(KeyEvent.VK_SPACE);
r.keyPress(KeyEvent.VK_I);
r.keyPress(KeyEvent.VK_S);
r.keyPress(KeyEvent.VK_SPACE);
r.keyPress(KeyEvent.VK_F);
r.keyPress(KeyEvent.VK_U);
r.keyPress(KeyEvent.VK_N);
r.keyPress(KeyEvent.VK_BACK_SPACE);
} catch (Exception e)
{
}
}
public static void main(String args[])
{
new UseBackSPace().start();
}
}
Related
I want to change the color of JTextField to red after typing something in it, and then after a second return to a default white background. I tried this outside the listener, and it worked, but when it comes to being a part of a listener, it doesn't (it just skips setting the red color). This is weird for me..
public class Test {
JFrame frame;
JTextField field;
public Test() {
frame = new JFrame();
field = new JTextField("A");
field.addKeyListener(new KeyBListener());
frame.getContentPane().add(field);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) { new Test(); }
private class KeyBListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
try {
field.setBackground(Color.RED);
Thread.sleep(1000);
field.setBackground(Color.WHITE);
} catch (InterruptedException es) { es.printStackTrace(); }
}
#Override
public void keyPressed(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
}
}
Try creating a separate Thread that listens to color change on the JTextField then changes it back. In this case at least you will not block the main Thread, although I'm not sure it's the most efficient way.
public Main() {
frame = new JFrame();
frame.setSize(800, 600);
field = new JTextField("A");
field.addKeyListener(new KeyBListener());
frame.getContentPane().add(field);
frame.pack();
frame.setVisible(true);
new Thread(() -> {
while(true) {
if(field.getBackground().equals(Color.RED))
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
field.setBackground(Color.WHITE);
}
}).start();
}
Your previous solution was working because it was executed from the AWT itself.
The keyTyped() method is executed on the Event dispatch thead (EDT), so you have to move the painting actions back to the AWT.
Have a look on SwingUtilities.invokeLater() (non-blocking) or SwingUtilities.invokeAndWait() (blocking), see
Oracle Doc
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
field.setBackground(Color.RED);
Thread.sleep(1000);
field.setBackground(Color.WHITE);
} catch (InterruptedException es) {
es.printStackTrace();
}
}
});
You can spawn a different thread in which you do the color manipulation. That ensures that the color manipulation is not happening inside EDT.
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class Test {
JFrame frame;
JTextField field;
AtomicBoolean isColorChangeOn = new AtomicBoolean();
public Test() {
frame = new JFrame();
field = new JTextField("A");
field.addKeyListener(new KeyBListener());
frame.getContentPane().add(field);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
isColorChangeOn.set(false);
}
public static void main(String[] args) {
new Test();
}
private class KeyBListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
if(!isColorChangeOn.get()) {
isColorChangeOn.set(true);
Runnable setcolor = ()->{
try {
System.out.println("color changing");
field.setBackground(Color.RED);
Thread.sleep(1000);
field.setBackground(Color.WHITE);
isColorChangeOn.set(false);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
};
new Thread(setcolor).start();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
}
I'm trying to check a JFormattedTextField after a value has been entered to make sure it does not match any other values entered in the other similar fields. It becomes a real pain if this check happens repeatedly while the user is typing because I want to provide an error message and I need to implement a number of changes if the value changes. But inputs like 123 will match 12 before the 3 is typed even though no error has really been made yet. Thus the need for a delay. So I'm trying to use a document listener but delay it until the user has validated (as accepted by the text field, by action or shifting focus) the entry.
I thought I had a good method, and it nearly works. My plan was to use a document listener to set up focus and action listeners. Unfortunately, I seem to end up with tons of focus and action listeners since the document listener keeps adding them. That means the error message and subsequent processing happen a ridiculous number of times instead of once. I've tried two work-arounds: 1) remove focus and action listeners before adding new ones, and 2) use a boolean to mark the existence of the focus and action listeners to avoid creating them again.
sscce (I'm new here, should I leave out all the includes?):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField = new JTextField("Change this.");
textField.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
trigger();
}
public void removeUpdate(DocumentEvent e) {
trigger();
}
public void changedUpdate(DocumentEvent e) {
trigger();
}
public void trigger() {
textField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField.getText());
}
});
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField.getText());
}
});
}
});
frame.add(textField);
}
}
So attempted fix 1 was to place textField.removeFocusListener(null) and textField.removeActionListener(null) just before the two textField.add... lines. Nothing changed from attempted fix 1. Attempted fix 2 was to create a boolean triggeringEvent outside of trigger() and then start trigger() with if(triggeringEvent == false) { triggeringEvent = true; ... all the focus and action listener lines. Attempted fix 2 just left me with nothing triggering at all.
Thank you for any insight anyone can provide!!!
Edit: I had tried Boann's addChangeListener, but that triggers incessantly, too, and it even triggers when the value hasn't been changed.
Edit: I thought I found a solution by adjusting attempted fix 2, but it fails with more than one JTextField:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JTextField textField;
private boolean eventTrigger = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField = new JTextField("Change this.");
textField.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField.getText());
eventTrigger = false;
}
});
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField.getText());
eventTrigger = false;
}
});
}
});
frame.add(textField);
}
}
You can see in this. If you start hopping between fields there are a whole bunch of extra times it triggers. It works fine for the first one you try adjusting, but then it fails.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Tester {
private JFrame frame;
private JPanel panel;
private JTextField textField1;
private JTextField textField2;
private boolean eventTrigger = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Tester window = new Tester();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Tester() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(50, 50, 200, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new GridLayout(0,1,0,0));
textField1 = new JTextField("Change the first.");
textField2 = new JTextField("Change the second.");
textField1.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField1.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField1.getText());
eventTrigger = false;
}
});
textField1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField1.getText());
eventTrigger = false;
}
});
}
});
textField2.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void removeUpdate(DocumentEvent e) {
if(eventTrigger == false) {
trigger();
}
}
public void changedUpdate(DocumentEvent e) {
}
public void trigger() {
eventTrigger = true;
textField2.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
System.out.println("You changed the text to: " + textField2.getText());
eventTrigger = false;
}
});
textField2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("You changed the text to: " + textField2.getText());
eventTrigger = false;
}
});
}
});
panel.add(textField1);
panel.add(textField2);
frame.add(panel);
}
}
This is a part of my java code, in this code there are labels which are counting numbers from 0 up to so on, I want to stop labels to count when I click the button 1st time, and I want to restart the labels to count again when I click the button 2nd time, the problem is that the labels are not restarting there counting when I am clicking the button 2nd time, so please tell how should I notify all the labels to restart there counting???
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
public class Main implements ActionListener {
JButton button = new JButton("Click");
JFrame frame = new JFrame();
boolean wait=false;
public static void main(String arg[]) {
new Main();
}
public Main() {
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.BLACK);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
button.addActionListener(this);
frame.add(button);
frame.setVisible(true);
new Producer().execute();
}
public class Producer extends SwingWorker<Void, Void> {
public Void doInBackground() {
for(int infinite=0; infinite!=-1; infinite++) {
new Counter().execute();
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
}
return null;
}
}
public class Counter extends SwingWorker<Void, Void> {
JLabel label = new JLabel();
public Counter() {
label.setForeground(Color.WHITE);
frame.add(label);
}
public Void doInBackground() {
synchronized (this) {
for(int i=0; i!=-1; i++) {
if(wait==true)
try {this.wait();} catch(Exception exp) {exp.printStackTrace();}
label.setText(""+i);
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
}
}
return null;
}
}
public void actionPerformed(ActionEvent clicked) {
if(wait==false)
wait=true;
else if(wait==true) {
synchronized (this) {
this.notifyAll();
}
}
}
}
I don't see a place where you ever reset wait to false. Try this and see if it gets you unstuck:
public void actionPerformed(ActionEvent clicked) {
if(wait==false) {
wait=true;
} else {
wait=false;
synchronized (this) {
this.notifyAll();
}
}
}
I want to have the user press a button to kick off a background thread.
While the thread is processing, I want two things to happen:
1) A WAIT_CURSOR should be displayed.
2) The application should not respond to mouse events.
As per the setCursor documentation "This cursor image is displayed when the contains method for this component returns true for the current cursor location, and this Component is visible, displayable, and enabled. ".
I want my application to be disabled while this background thread is processing.
Any ideas how to get the functionality I want?
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static final long serialVersionUID = 1L;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// Change to WAIT_CURSOR
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
root.setEnabled(false);
new Thread(new TimeKiller(root)).start();
}
}
}
private class TimeKiller implements Runnable
{
Component _root;
public TimeKiller(Component root)
{
_root = root;
}
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
// Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(_root, "Done waiting");
_root.setCursor(Cursor.getDefaultCursor());
_root.setEnabled(true);
}
}
private static void createAndShowGUI()
{
// Create and set up the window.
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}
One way to disable it is to use the glass pane to block mouse input.
For example:
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import javax.swing.*;
#SuppressWarnings("serial")
public class WaitCursor2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private JComponent glassPane;
private JButton runBackgroundProcBtn;
private JTextArea textarea = new JTextArea(15, 30);
public WaitCursor2(JComponent glassPane) {
this.glassPane = glassPane;
glassPane.setFocusable(true);
glassPane.addMouseListener(new MouseAdapter() {
}); // so it will trap mouse events.
add(new JTextField(10));
add(runBackgroundProcBtn = new JButton(new AbstractAction(
"Run Background Process") {
#Override
public void actionPerformed(ActionEvent arg0) {
runBackgroundProcessAction();
}
}));
add(new JScrollPane(textarea));
}
private void runBackgroundProcessAction() {
disableSystem(true);
glassPane.setVisible(true);
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
long sleepTime = 5000;
Thread.sleep(sleepTime);
return null;
}
#Override
protected void done() {
disableSystem(false);
}
}.execute();
}
public void disableSystem(boolean disable) {
glassPane.setVisible(disable);
runBackgroundProcBtn.setEnabled(!disable);
if (disable) {
System.out.println("started");
glassPane.requestFocusInWindow(); // so can't add text to text components
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
} else {
System.out.println("done");
glassPane.setCursor(Cursor.getDefaultCursor());
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("WaitCursor2");
WaitCursor2 mainPanel = new WaitCursor2((JComponent) frame.getGlassPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
The glass pane will trap mouse events if it set visible and given a MouseListener. It will lose t his ability if it is set invisible. Likewise it will pull the caret from text components if you make it focusable and give it focus.
added a field current_active and at method actionPerformed, do a simple check. Albeit it is not perfect but for simple app, i think this do the trick. A crude way of solving your two requirement. :-) Hope it works for you too.
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static boolean current_active = false;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
// change to wait_cursor
public void actionPerformed(ActionEvent e)
{
if (!current_active)
{
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
//root.setEnabled(false);
current_active = true;
new Thread(new TimeKiller(root)).start();
}
}
}
}
private class TimeKiller implements Runnable
{
Component m_root;
public TimeKiller(Component p_root)
{
m_root = p_root;
}
#Override
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
//Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(m_root, "Done waiting");
m_root.setCursor(Cursor.getDefaultCursor());
current_active = false;
}
}
// create and setup the window.
public static void createAndShowGUI()
{
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}
I'm trying to get a SwingWorker to work.
I've the following code at the moment:
public class ImageWorker extends SwingWorker<Void, Void> implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch(IOException ex)
{
ex.getMessage();
}
this.execute();
}
#Override
protected Void doInBackground()
{
try
{
while (true)
{
displayImage(basicImage);
Thread.sleep(1000L);
if(isCancelled())
return null;
}
}
catch(InterruptedException e)
{
e.getMessage();
}
return null;
}
private void displayImage(final Icon image)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
imageLabel.setIcon(image);
}
});
}
I was expecting the images to appear in the JLabel, but I only see the JFrame popping up. The files are loaded correctly Ive tested that in another setup.
Any pointers?
Here is an example using a Timer rather than using the SwingWorker which really isn't appropriate to your situation. Note that it's not too different from your existing code.
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class ImageWorker implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
private boolean isBasic = true;
private int delay = 1000; //milliseconds
private Timer timer;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch (IOException ex)
{
ex.getMessage();
ex.printStackTrace();
}
frame.addKeyListener(this);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(isBasic) {
//display basic image
imageLabel.setIcon(basicImage);
}
else {
//display white image
imageLabel.setIcon(whiteImage);
}
//toggle the flag
isBasic = !isBasic;
}
};
//use a timer instead of SwingWorker
timer = new Timer(delay, taskPerformer);
timer.start();
}
#Override
public void keyPressed(KeyEvent e)
{
//key pressed, we want to stop toggling so stop the timer
timer.stop();
//do whatever else you were doing to set the value for isCancelled();
}
#Override
public void keyReleased(KeyEvent e)
{
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e)
{
// TODO Auto-generated method stub
}
}
A SwingWorker is not appropriate for your situation look into a Timer in the swing package. Here is a link to the API: http://download.oracle.com/javase/6/docs/api/javax/swing/Timer.html
You have the timer run and change an image every second since that is what you need.
Also, whenever you have exceptions, print out a stacktrace or the message at least. Otherwise you won't know if an exception occurs and is caught.