I have a java application and i want to wait for a key to be pressed to perform another action. Till now i have found:
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
//Right arrow key code
}
}
but i want this to be inside a loop or something that waits until the key matches.
Please help.
UPDATE:
I want the program to be waiting until the key is pressed and when it is pressed i want to trigger another action. For example:
public void something(){
//do something
wait until a key is pressed
if( key pressed is a arrow key){
something();
}else{
wait for the key to be pressed
}
}
public void dootherthing(){
//do other thing
}
I am working in swing and i don't want the GUI to be irresponsible. i.e. when i call the dootherthing by click of a button. It should do it and the waiting should be over.
Swing (and most GUIs) are event driven environments. That is, something happens, you react to it.
Having a loop waiting for some kind of action is kind of counter intuitive (IMHO).
Generally speaking, you should avoid KeyListeners if you can. They have issues with key focus. The key bindings API has ways to over come this limitation.
It allows you to register a KeyStroke against an Action and allows your program to sit back and wait till something happens...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class KeyBindings {
public static void main(String[] args) {
new KeyBindings();
}
public KeyBindings() {
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 BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
add(new KeyPane(KeyEvent.VK_UP, 0), gbc);
gbc.gridy = 2;
add(new KeyPane(KeyEvent.VK_DOWN, 0), gbc);
gbc.gridx = 0;
gbc.gridy = 1;
add(new KeyPane(KeyEvent.VK_LEFT, 0), gbc);
gbc.gridx = 2;
add(new KeyPane(KeyEvent.VK_RIGHT, 0), gbc);
}
}
public class KeyPane extends JPanel {
public KeyPane(int keyCode, int modifier) {
setBorder(new LineBorder(Color.DARK_GRAY));
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(keyCode, modifier, false), "keyPressed");
im.put(KeyStroke.getKeyStroke(keyCode, modifier, true), "keyReleased");
am.put("keyPressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
setBackground(Color.RED);
}
});
am.put("keyReleased", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
setBackground(UIManager.getColor("Panel.background"));
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
}
}
You can write a key listener
I found a Java tutorial that includes a Java WebStart sample and the source code. Looks like the winner is KeyEvent.getKeyLocation()
KeyEvent.KEY_LOCATION_STANDARD
KeyEvent.KEY_LOCATION_LEFT
KeyEvent.KEY_LOCATION_RIGHT
KeyEvent.KEY_LOCATION_NUMPAD
KeyEvent.KEY_LOCATION_UNKNOWN
References:
How to tell which SHIFT key was pressed?
keyPressed method will always be invoked whenever a key is pressed then why do you need it to be inside a loop?
From description it seems you are developing a typing game if it is so you can use Timeline class in JavaFX.
I have developed a very simple typing game in JavaFX have a look at it (code not properly organized).
Related
I have got a set of nodes in my program, each have a specific x,y location.
and each have a set of image icons.
I want to draw image animation for each nodes at its specific location.
Here is my code: (this only shows the last image which i know why!.)
public void showPicture() {
//nodes :
for(int i=0;i<thisGraph.getNode().size();i++){
if(thisGraph.getNode().get(i).getImageIcon()!=(null)){
for(int j=0;j<thisGraph.getNode().get(i).getImageIcon().size();j++){
if(j>0)
lables.get(lables.size()-1).setVisible(false);
JLabel jLabel1 = new JLabel();
lables.add(jLabel1);
jLabel1.setLayout(new GridBagLayout());
jLabel1.setIcon(thisGraph.getNode().get(i).getImageIcon().get(j));
jLabel1.setVisible(true);
jLabel1.setBounds((int)thisGraph.getNode().get(i).getX(),(int)thisGraph.getNode().get(i).getY(),195,163);
jPanel1.add(jLabel1);
}
}
}
}
This method showPicture() is called in a buttonActionListener.
And I also have another button which I want it to stop the image animations for all labels.
What I have tried:
Thread.sleep() -> it freezes the button and it only shows the last image
I figured I had to use timer, but through all the topics I went they only used it on one label, not multiple labels.
Edit
->
i read those examples given in the comments . and here is what i have resolved but it still is freezes the button and doesn't works :
int j = 0;
public void showPicture(){
//nodes :
for(int i=0;i<thisGraph.getNode().size();i++){
if(thisGraph.getNode().get(i).getImageIcon()!=(null)){
j=0;
while( j<thisGraph.getNode().get(i).getImageIcon().size()){
if(j>0)
lables.get(lables.size()-1).setVisible(false);
JLabel jLabel1 = new JLabel();
lables.add(jLabel1);
jLabel1.setLayout(new GridBagLayout());
jLabel1.setIcon(thisGraph.getNode().get(i).getImageIcon().get(j));
jLabel1.setVisible(true);
jLabel1.setBounds((int)thisGraph.getNode().get(i).getX(),(int)thisGraph.getNode().get(i).getY(),195,163);
jPanel1.add(jLabel1);
//
ActionListener act;
act = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jLabel1.setVisible(true);
j++;
}
};
Timer timer = new Timer(1000, act );
timer.start();
timer.stop();
//
}
}
}}
Swing is single threaded and not thread safe. This means that you shouldn't block the Event Dispatching Thread with long running or blocking operations, like Thread.sleep. You should also, only ever update the UI (or anything it relies on) from within the context of the Event Dispatching Thread.
See Concurrency in Swing for more details.
Probably the simplest solution to your problem is to use a Swing Timer.
The idea is a you use a single Timer to act as the "main animation loop", changing the properties of ALL the objects you need updated within it.
The following is pretty basic example, it animates 100 JLabels, simply changing their background color with a randomly picked color
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<JLabel> nodes = new ArrayList<>(100);
private Random random = new Random();
private Color[] colors = new Color[] { Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, Color.MAGENTA};
public TestPane() {
setLayout(new GridLayout(0, 10));
for (int index = 0; index < 100; index++) {
JLabel label = new JLabel();
label.setBorder(new EmptyBorder(5, 5, 5, 5));
label.setOpaque(true);
label.setBackground(pickColor());
nodes.add(label);
add(label);
}
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (JLabel label : nodes) {
label.setBackground(pickColor());
}
}
});
timer.start();
}
protected Color pickColor() {
return colors[random.nextInt(colors.length)];
}
}
}
See How to Use Swing Timers for more details
I currently have a very simple game, where you move a black rectangle from side to side using the arrows keys. My problem is that whenever the alt key is being pressed (mostly by accident), the game window loses focus and doesn't reply to the arrow keys anymore. The focus is regained if I press alt again, but if the rectangle is already in motion it will keep going non stop.
I'm using these render and update methods btw.
Is there a way to prevent the alt key from doing its job - focusing on the UI's menu?
Is there a way to prevent the alt key from doing its job - focusing on the UI's menu?
Strictly speaking, no - or more to the point, that's the wrong approach.
What you should be doing is using the Key Bindings API which will overcome the focus related issues of KeyListener, this way, you don't "have" to care
This is a really simple test which binds actions to the ALT and other keys and seems to work for me, but immediately, I'm testing on MacOS. I also found that you can only bind to the "key released" event of the meta keys
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
JMenuBar mb= new JMenuBar();
JMenu menu = new JMenu("Menu");
menu.add("This is test item");
mb.add(menu);
frame.setJMenuBar(mb);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel("...");
add(label);
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "A");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "W");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "S");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "D");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true), "ALT");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, 0, true), "CTRL");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_META, 0, true), "META");
ActionMap actionMap = getActionMap();
actionMap.put("A", new TextAction("A"));
actionMap.put("W", new TextAction("W"));
actionMap.put("S", new TextAction("S"));
actionMap.put("D", new TextAction("D"));
actionMap.put("ALT", new TextAction("ALT"));
actionMap.put("CTRL", new TextAction("CTRL"));
actionMap.put("META", new TextAction("META"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected class TextAction extends AbstractAction {
private String text;
public TextAction(String text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
label.setText(text);
}
}
}
}
As an alternative, you could also look at KeyboardFocusManager.addKeyEventDispatcher and/or Toolkit.addAWTEventListener to see if you can determine when the ALT key is pressed and either force focus back to the component OR, better, pause the game - as there might be a legitimate reason the user wants access to the system menu.
To that end, a FocusListener might be a simpler solution all round, as you can simply determine when focus is lost or gained and pause/resume the game appropriately
This is my code:
panel2.add(question1);
panel2.add(true1);
panel2.add(false1);
panel2.add(labelAnswer1);
panel2.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
if(true1.isSelected()) {
labelAnswer1.setText("You are CORRECT!");
}
else if(false1.isSelected()) {
labelAnswer1.setText("You are wrong. The correct answer is " + true1.getText());
}
else if(true1.isSelected() && false1.isSelected()) {
labelAnswer1.setText("You cannot select two answers!");
}
Not really sure what I'm doing wrong. Might just be too late at night, haha. Any help would be appreciated. Thanks and best regards!
Swing, like most GUI frameworks is event driven, that is, something happens and then you respond to it. You don't known when or in what order those events might occur.
Instead, you use "listeners" (aka a Observer Pattern) to register interest with your components, which tell you when something happens and you take appropriate action based on the current state of your program
Take a look at How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners for more details
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.WEST;
add(new JLabel("Is a banna:"), gbc);
ButtonGroup bg = new ButtonGroup();
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
System.out.println("You guessed " + cmd);
if ("Yellow".equalsIgnoreCase(cmd)) {
JOptionPane.showMessageDialog(TestPane.this, cmd + " is the answer");
} else {
JOptionPane.showMessageDialog(TestPane.this, cmd + " is not the answer");
}
}
};
add(createGuess("Red", listener, bg), gbc);
add(createGuess("Green", listener, bg), gbc);
add(createGuess("Blue", listener, bg), gbc);
add(createGuess("Yellow", listener, bg), gbc);
}
protected JRadioButton createGuess(String guess, ActionListener listener, ButtonGroup bg) {
JRadioButton btn = new JRadioButton(guess);
btn.addActionListener(listener);
bg.add(btn);
return btn;
}
}
}
You should add more code so we can see where your listeners are, other components, etc.
Your if statements should be in a listener. Right now, the code executes right after you add in the elements to the page, and no other time. So, this code only happens right after elements are added, before the user has time to select an element. Also, what if no elements are selected? Then no if statement is hit, and for that reason you may need to add an else statement.
This setup should be that you have two radio buttons, a question, and a button the user hits when they have selected their answer. That button should have a listener that runs the above if statements.
Got it figured out.
Added this:
true1.addMouseListener(this);
And this:
#Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() == true1) {
labelAnswer1.setText("You are CORRECT!");
}
}
Thanks for all the help!
I need a one-time pause in this program for what I'm trying to do. I display some text in a Java Swing JFrame, repaint shows it, I wait 1.5 sec, then I change the text.
Basically, I started with this:
statusLabel.setText(s);
appFrame.repaint();
Thread.sleep(1500);
statusLabel.setText(y);
appFrame.repaint();
But this wasn't working. Thread.sleep() would invoke before repaint had finished, meaning s would never be shown. I read a lot of places that you're not supposed to use Thread.sleep() in swing applications because it pauses all threads, even the threads trying to repaint, and that to pause something triggered by actionPerformed() you need to use a Java Swing Timer.
Which is all well and fine, except I can't find a single place that offers a decent explanation on how they work. Since, as far as I can tell, timers are specifically used for repeating events on a timer. I just want a 1.5 second delay between 2 repaints.
I tried doing this...
statusLabel.setText(s);
appFrame.repaint();
Timer timer = new Timer(1500, new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
}
});
timer.setInitialDelay(1500);
timer.setRepeats(false);
timer.start();
statusLabel.setText(y);
appFrame.repaint();
...adding a timer with a 1.5 sec initial delay, no repeating, and no body to its actionPerformed event, so that it literally does nothing but wait that 1.5 sec, but it didn't work.
As coded in your example, it looks like the timer would "work", it just doesn't do anything because the actionPerformed method is empty. You might be thinking that timer.start() blocks and waits for the timer to trigger, but it fact it returns immediately. The way timers work is that the timer's actionPerformed method will be invoked from the UI thread when it is supposed to be. Placing code inside the actionPerformed method of a timer is a good way to update the UI state periodically.
Have you tried placing statusLabel.setText(y); inside the actionPerformed method of your ActionListener?
statusLabel.setText(s);
Timer timer = new Timer(1500, new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
statusLabel.setText(y);
}
});
timer.setRepeats(false);
timer.start();
If that's still not working, then consider providing a runnable example which demonstrates your problem. This will result in less confusion and better responses
Updated
What you "seem" to be wanting to do, is set up a series of events which get trigger at different times...Rather then using separate Timers, you should be using a single Timer like a loop, each time it ticks, you check it's state and make some decisions about what should be done, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Flashy {
public static void main(String[] args) {
new Flashy();
}
public Flashy() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
private JLabel flash;
private JButton makeFlash;
protected static final Color[] FLASH_COLORS = new Color[]{Color.BLUE, Color.RED, Color.GREEN, Color.YELLOW};
protected static final int[] FLASH_DELAY = new int[]{1000, 2000, 3000, 4000};
private int flashPoint;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
flash = new JLabel("Flash");
flash.setOpaque(true);
makeFlash = new JButton("Make Flash");
add(flash, gbc);
add(makeFlash, gbc);
makeFlash.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
flashPoint = -1;
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = ((Timer)e.getSource());
flashPoint++;
if (flashPoint < FLASH_COLORS.length) {
flash.setBackground(FLASH_COLORS[flashPoint]);
System.out.println(FLASH_DELAY[flashPoint]);
timer.setDelay(FLASH_DELAY[flashPoint]);
} else {
flash.setBackground(null);
timer.stop();
makeFlash.setEnabled(true);
}
}
});
timer.setInitialDelay(0);
timer.start();
makeFlash.setEnabled(false);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Now, if you wanted to do something really fancy, you could devise a series of key frames over a given period of time.
This means that you could change the duration of the animation, without needing to change any other piece of code, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Flashy {
public static void main(String[] args) {
new Flashy();
}
public Flashy() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
private JLabel flash;
private JButton makeFlash;
protected static final Color[] FLASH_COLORS = new Color[]{Color.BLUE, Color.RED, Color.GREEN, Color.YELLOW};
protected static final double[] FLASH_DELAY = new double[]{0, 0.2, 0.4, 0.6};
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
flash = new JLabel("Flash");
flash.setOpaque(true);
makeFlash = new JButton("Make Flash");
add(flash, gbc);
add(makeFlash, gbc);
makeFlash.addActionListener(new ActionListener() {
private int playTime = 10000;
private long startTime;
private int currentFrame = -1;
#Override
public void actionPerformed(ActionEvent e) {
startTime = System.currentTimeMillis();
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = ((Timer) e.getSource());
long now = System.currentTimeMillis();
long duration = now - startTime;
double progress = (double) duration / (double) playTime;
int keyFrame = 0;
for (keyFrame = 0; keyFrame < FLASH_DELAY.length; keyFrame++) {
double current = FLASH_DELAY[keyFrame];
double next = 1d;
if (keyFrame + 1 < FLASH_DELAY.length) {
next = FLASH_DELAY[keyFrame + 1];
}
if (progress >= current && progress < next) {
break;
}
}
if (keyFrame < FLASH_COLORS.length) {
flash.setBackground(FLASH_COLORS[keyFrame]);
}
if (duration >= playTime) {
timer.stop();
makeFlash.setEnabled(true);
flash.setBackground(null);
}
}
});
timer.setInitialDelay(0);
timer.start();
makeFlash.setEnabled(false);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
A much more advanced concept, which is demonstrated in this answer
I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ?
Should I share events or listeners ?
Thank you
This would be so much easier if JTextComponent supported a selection model...
Basically, what you can do is attach a ChangeListener to the JTextArea's Caret and monitor for changes to the Caret, changing the selection of the other JTextArea in response...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
public class MirrorTextSelection {
public static void main(String[] args) {
new MirrorTextSelection();
}
public MirrorTextSelection() {
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 BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea left;
private JTextArea right;
private DefaultHighlighter.DefaultHighlightPainter highlightPainter;
public TestPane() {
highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(UIManager.getColor("TextArea.selectionBackground"));
left = new JTextArea(20, 20);
left.setWrapStyleWord(true);
left.setLineWrap(true);
right = new JTextArea(20, 20);
right.setWrapStyleWord(true);
right.setLineWrap(true);
left.setText("I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ? Should I share events or listeners ? Thank you");
right.setText("I am trying to do a small app that compares two similar texts contained in 2 JTextarea. I am wondering if it's possible to select text from the first JTextarea and automatically select the text on the second JTeaxtarea (lets consider that it's guarantee that the 2 JTextarea will have the same text for now) ? Should I share events or listeners ? Thank you");
setLayout(new GridLayout(0, 2));
add(new JScrollPane(left));
add(new JScrollPane(right));
left.getCaret().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int dot = left.getCaret().getDot();
int mark = left.getCaret().getMark();
right.setCaretPosition(mark);
right.moveCaretPosition(dot);
}
});
}
}
}
Now, when you run this, you will find that the right side doesn't seem to get highlighted...what?!
The selection is changing, it's just not been rendered because the component doesn't have focus...
Instead, you could use a Highlighter to highlight the text...
private DefaultHighlighter.DefaultHighlightPainter highlightPainter;
//...
highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(UIManager.getColor("TextArea.selectionBackground"));
left.getCaret().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int dot = left.getCaret().getDot();
int mark = left.getCaret().getMark();
right.getHighlighter().removeAllHighlights();
try {
int start = Math.min(dot, mark);
int end = Math.max(dot, mark);
right.getHighlighter().addHighlight(start, end, highlightPainter);
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
});
Okay, this is now working and you can control the background color of the highlight...
There is another alternative...We can replace the Caret of the right JTextArea with one that doesn't hide the selection when focus is lost...
public class HighlightCaret extends DefaultCaret {
#Override
public void install(JTextComponent c) {
super.install(c);
setSelectionVisible(true);
}
#Override
public void focusGained(FocusEvent e) {
JTextComponent component = getComponent();
if (component.isEnabled()) {
if (component.isEditable()) {
setVisible(true);
}
setSelectionVisible(true);
}
}
#Override
public void focusLost(FocusEvent e) {
setVisible(false);
}
}
Then we set the Caret to right...
right.setCaret(nwe HighlightCaret());
This means we don't need the Highlighter code, we can stick with the original and we get control over not only the background selection color but also the foreground selection color as well...