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) {
}
}
}
Related
I'm trying to add a 2 second delay between each letter that is typed in one textarea before it is printed/displayed on another textarea.
I've used two classes:
One for a GUI called Printdelay
One for the thread, called TwoSecondDelay
Everything works fine except for the execution of the thread.
Here's the code for the GUI:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class PrintDelay extends javax.swing.JFrame implements KeyListener{
int name;
JTextArea server = new JTextArea (10, 20);
JTextArea client = new JTextArea (10, 20);
public PrintDelay () {
super ("Typing...");
setSize (650, 220);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel ();
server.addKeyListener (this);
panel.add (server);
panel.add (client);
add(panel);
setVisible (true);
}
public static void main (String... args) {
new PrintDelay ();
}
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
#Override
public void keyReleased(KeyEvent e)
{
new TwoSecondDelay (Integer.toString(name));
name++;
client.setText(server.getText());
}
}
Here's the code for the TwoSecondDelay:
public class TwoSecondDelay implements Runnable{
String name;
Thread t;
TwoSecondDelay (String threadname) {
name = threadname;
t = new Thread (this, name);
t.start();
}
#Override
public void run() {
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
}
}
}
Also the classes are in their own separate files.
No need to use TwoSecondDelay
#Override
public void keyReleased(KeyEvent e)
{
typeText();
/*new TwoSecondDelay (Integer.toString(name));
name++;
client.setText(server.getText());*/
}
public void typeText(){
ActionListener listener = new ActionListener(){
public void actionPerformed(ActionEvent event){
client.setText(server.getText());
}
};
Timer timer = new Timer(2000, listener);
timer.setRepeats(false);
timer.start();
}
I have a desktop application in which I am showing one Frame as notification but I want to stop that thread when mouse hover to the notification frame. Then how could I can do that?
Here current code:
final Notification not = new Notification();
Notification.notification_name.setText(msg[1]);
final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
s.schedule(new Runnable() {
public void run() {
not.setVisible(false); //should be invoked on the EDT
not.dispose();
}
}, 6, TimeUnit.SECONDS);
It's showing and Exit in 6 sec.
The code that I am trying.
final Notification not = new Notification();
not.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
try {
super.mouseEntered(e);
System.out.println("Mouse Entered");
//s.wait();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception x) {
x.printStackTrace();
}
}
#Override
public void mouseExited(MouseEvent e) {
try {
super.mouseExited(e);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
s.schedule(new Runnable() {
public void run() {
not.setVisible(false); //should be invoked on the EDT
not.dispose();
}
}, 6, TimeUnit.SECONDS);
In this code Notification frame is showing till 6 sec but if user hover that frame then it should be Show till user mouse exit from that Frame.
Whenever you deal with anything that might affect the UI in some way, you need to be careful and ensure that everything is done within the context of the EDT.
javax.swing.Timer allows you to setup a callback at some time in the future that when triggered, will be called within the context of the EDT
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class TimeExample {
public static void main(String[] args) {
new TimeExample();
}
public TimeExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new TestPane());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer timer;
public TestPane() {
setBorder(new LineBorder(Color.BLACK));
timer = new Timer(6000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setBackground(Color.RED);
}
});
timer.setRepeats(false);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
if (timer.isRunning()) {
timer.stop();
setBackground(Color.BLUE);
}
}
#Override
public void mouseExited(MouseEvent e) {
if (!timer.isRunning()) {
timer.restart();
setBackground(UIManager.getColor("Panel.background"));
}
}
/**
* Testing purposes only!!
*
* #param e
*/
#Override
public void mouseClicked(MouseEvent e) {
setBackground(UIManager.getColor("Panel.background"));
timer.restart();
}
};
addMouseListener(ma);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
}
}
Have a look at How to Use Swing Timers for more details
I'm trying to capture the screen without including my application's window. To do this I first call setVisible(false), then I call the createScreenCapture method, and finally I call setVisible(true). This isn't working however and I'm still getting my applications window in the screen capture. If I add a call to sleep this seems to resolve the issue, but I know this is bad practice. What is the right way to do this?
Code:
setVisible(false);
BufferedImage screen = robot.createScreenCapture(rectScreenSize);
setVisible(true);
Have you tried to use SwingUtilities.invokeLater() and run the capture inside of the runnable passed as an argument? My guess is that the repaint performed to remove your application is performed right after the end of the current event in the AWT-EventQueue and thus invoking the call immediately still captures your window. Invoking the createCapture in a delayed event through invokeLater should fix this.
you have to delay this action by implements Swing Timer, for example
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class CaptureScreen implements ActionListener {
private JFrame f = new JFrame("Screen Capture");
private JPanel pane = new JPanel();
private JButton capture = new JButton("Capture");
private JDialog d = new JDialog();
private JScrollPane scrollPane = new JScrollPane();
private JLabel l = new JLabel();
private Point location;
private Timer timer1;
public CaptureScreen() {
capture.setActionCommand("CaptureScreen");
capture.setFocusPainted(false);
capture.addActionListener(this);
capture.setPreferredSize(new Dimension(300, 50));
pane.add(capture);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pane);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
createPicContainer();
startTimer();
}
private void createPicContainer() {
l.setPreferredSize(new Dimension(700, 500));
scrollPane = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.white);
scrollPane.getViewport().setBackground(Color.white);
d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
d.add(scrollPane);
d.pack();
d.setVisible(false);
d.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
f.setVisible(true);
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
});
}
private void startTimer() {
timer1 = new Timer(1000, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
capture.doClick();
f.setVisible(false);
}
});
}
});
timer1.setDelay(500);
timer1.setRepeats(false);
timer1.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CaptureScreen")) {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
Robot r;
BufferedImage bI;
try {
r = new Robot(); // creates robot not sure exactly how it works
Thread.sleep(1000); // waits 1 second before capture
bI = r.createScreenCapture(new Rectangle(dim)); // tells robot to capture the screen
showPic(bI);
saveImage(bI);
} catch (AWTException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
private void saveImage(BufferedImage bI) {
try {
ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
private void showPic(BufferedImage bI) {
ImageIcon pic = new ImageIcon(bI);
l.setIcon(pic);
l.revalidate();
l.repaint();
d.setVisible(false);
//location = f.getLocationOnScreen();
//int x = location.x;
//int y = location.y;
//d.setLocation(x, y + f.getHeight());
d.setLocation(150, 150);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
d.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CaptureScreen cs = new CaptureScreen();
}
});
}
}
I'm not a Java programmer and I'm not sure if what I'm doing is correct or not, or if exist a better way to do this.
I'm making a swing Java app with multi-threading.
I have many swing component (textfield, texarea, label, list, ...) which are set and refresh with many threads.
For all my component I use something like the code below (it's just a tiny example) for set/refresh it.
Is Main.mainUI.setThumbLbl(image); for set/refresh my component a good way or not ? (I use something like this in other threads for all component)
And is there another better way to do this ?
Main :
public class Main {
public static MyMainUI mainUI;
public static void main(String args[]) {
mainUI = new mainUI();
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
mainUI.setVisible(true);
}
});
}
}
Jframe :
public class MyMainUI extends JFrame {
private JLabel thumbLbl;
private JButton thumbBtn;
public MyMainUI(){
// add thumbLbl, thumBtn
...
thumBtn.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent evt) {
new MyThread().start();
}
});
}
public void setThumbLbl(final Image image) {
SwingUtilities.invokeLater(new Thread() {
#Override
public void run() {
thumbLbl.setIcon(new ImageIcon(image.getScaledInstance(thumbLblDim.width,
thumbLblDim.height, Image.SCALE_DEFAULT)));
}
});
}
}
Thread :
public class MyThread extends Thread {
#Override
public void run() {
//Get image from web server
...
Main.mainUI.setThumbLbl(image);
}
}
NB: I wrote this sample code in a text editor very quickly, maybe there are some mistakes but it's not what I'm asking for ^^.
NB2: Sorry for my bad English.
An example of what I meant is something like this:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Main {
private static void createAndShowGui() {
JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMainUI());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyMainUI extends JPanel {
public static final String IMG_URL_PATH = "http://duke.kenai.com/Oracle/OracleStrat.png";
private static final int PREF_W = 900;
private static final int PREF_H = 650;
private JLabel thumbLbl = new JLabel();
private JButton thumbBtn = new JButton("Get Image");
public MyMainUI() {
thumbBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
thumbBtn.setEnabled(false);
final ImageDownloader imgDownLoader = new ImageDownloader(IMG_URL_PATH);
imgDownLoader.execute();
imgDownLoader.addPropertyChangeListener(new ImgDownLoaderListener(imgDownLoader));
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(thumbBtn);
setLayout(new BorderLayout());
add(new JScrollPane(thumbLbl), BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class ImgDownLoaderListener implements PropertyChangeListener {
ImageDownloader imgDownLoader;
public ImgDownLoaderListener(ImageDownloader imgDownLoader) {
this.imgDownLoader = imgDownLoader;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// swing worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
thumbBtn.setEnabled(true);
try {
ImageIcon icon = imgDownLoader.get();
if (icon != null) {
thumbLbl.setIcon(icon);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
class ImageDownloader extends SwingWorker<ImageIcon, Void> {
private String imageUrlPath;
public ImageDownloader(String imageUrlPath) {
this.imageUrlPath = imageUrlPath;
}
#Override
protected ImageIcon doInBackground() throws Exception {
try {
URL imgUrl = new URL(imageUrlPath);
BufferedImage img = ImageIO.read(imgUrl);
return new ImageIcon(img); // return the ImageIcon
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null; // or return null if an error occurs
}
}
The background worker thread in this example has no knowledge about the structure of the GUI. All it does is download an image -- that's it, and then the GUI which listens for completion with a PropertyChangeListener gets the image by calling get() on the worker, and decides what it wants to do with it.
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.