Timer isn't working correctly in my code - java

So the plan of the program I am making is to have an object move from one point to another. The catch is the path is drawn. I am able to draw and place a shape to move through the path from start to finish. The problem I am having is that the object is appearing at the end of the path. Even with timer set at the end of the for loop. All it does is simply wait for the timer to finish then the shape is at the end of the path.
I've gone through the code, even printed out each point that has been stored and I am getting points, not just the last point. The object's path is based on a for loop going through each point and placing the object at said point. It's crude atm and uses absolute position (just for the object).
What am I missing?
Here's the code:
JButton add = new JButton("add");
add(add);
//new Timer(50, updateTask).start();
updateTask = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
repaint(); // Refresh the JFrame, callback paintComponent()
}
};
add.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
for (int i = 0; i < path.size(); i++) {
update(i); // update the (x, y) position
new Timer(1000, updateTask).start();
}
}
});
}
public void update(int i) {
if (released == 1) {
Point p = path.get(i);
System.out.println("position at: " + (int) p.getX() + " " + (int) p.getY());
xPos = (int) p.getX();
yPos = (int) p.getY();
System.out.println(i);
}
}

You can't write your loop within an ActionListener, since that would block the EventDispatchThread (EDT) and therefore block your UI.
Instead you can use the updateTask ActionListener to step through your path each time it is called from the Timer:
final Timer timer = new Timer(1000, null);
updateTask = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (pathIndex < path.size()) {
update(pathIndex++);
} else {
timer.stop();
}
repaint(); // Refresh the JFrame, callback paintComponent()
}
};
timer.addActionListener(updateTask);
add.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
pathIndex = 0;
timer.start();
}
});
For this to work your class needs an additional int field pathIndex

Related

Movement through a timer

I am trying to make several small boxes move around a page based on several properties. The movement itself is handled by the method private void direction_move_creature(){. which i then call in as:
public class Listener implements ActionListener {
public void actionPerformed(ActionEvent e){
//Looping 200 time steps, each time updating the coordinates of the creatures.
for(int i = 0; i < 20; i++){
direction_move_creature();
repaint();
}
System.out.println("HERE");
}
}
and my main method is:
public static void main(String[] args){
JFrame frame = new JFrame("Draw");
frame.setSize(550, 550);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new Draw());
frame.setVisible(true);
System.out.println("final");
}
}
new Draw just fills the structures that hold the coordinates for the moving shapes. When i try to run the program i get no movement what so ever. I knwo these are only fragments of code but any help would be greatly appreciated.
You're misunderstanding how a Swing Timer works. The Timer replaces the for loop. Get rid of the loop and increment a counter within the timer's ActionListener.
e.g.,
class MyActionListener implements ActionListener {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// assuming MAX_COUNTER is 20
if (counter < MAX_COUNTER) {
direction_move_creature();
repaint();
counter++;
} else {
// stop the Timer
((Timer) e.getSource()).stop();
}
}
}

Java GUI/Swing, stopping the thread, passing integers between classes

I'm trying to make a simulation of a roulette game using GUI/Swing for my upcoming exam. I have two classes, one is called GUI and is actually the code used for the components, such as JFrame, JOptionPane, JButtons etc. The other one extends Thread and is supposed to show random numbers on a small JLabel, and the run method goes something like this:
public void run() {
int k = 0;
for (int i = 0; i < 50; i++) {
k = (new Random().nextInt(37));
label.setText(k + " ");
label.setFont(new Font("Tahoma", Font.BOLD, 56));
label.setForeground(Color.yellow);
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And in the GUI class I just want to TAKE the number from the last iteration of the above loop, and then pass it to a new int, which I'm going to use later in the GUI class.
Any ideas?
Use Swing Timer instead of Thread.sleep that sometime hangs the whole swing application.
Please have a look at How to Use Swing Timers
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//next call from here
}
});
timer.setRepeats(false);
timer.start();
I just want to TAKE the number from the last iteration of the above loop, and then pass it to a new int, which I'm going to use later in the GUI class.
Just create a method (setter) in another class that accepts int and call it from this class for last call.
Sample code:
private int counter = 0;
private Timer timer;
...
final JLabel label = new JLabel();
label.setFont(new Font("Tahoma", Font.BOLD, 56));
label.setForeground(Color.yellow);
Thread thread = new Thread(new Runnable() {
public void run() {
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (counter++ < 50) {
int k = (new Random().nextInt(37));
label.setText(k + " ");
} else {
timer.stop();
label.setText("next call");
}
}
});
timer.setRepeats(true);
timer.start();
}
});
thread.start();
snapshot:

Java Swing - Add leniency when selecting items in submenus

When attempting to click on an item in a submenu, it is natural to quickly draw your mouse across the menu items below it. Both Windows and Mac natively handle this by putting a small delay before the a menu is opened. Swing JMenus do not handle this, and the menu the mouse briefly hovers over would be opened before the mouse reaches the intended menu item.
For example, in the image below, if I tried to select Item 3, but in the process my mouse briefly slid across Menu 2, the Menu 1 submenu would disappear before I got to it.
Does anyone have any tips or suggestions for getting around this? My idea was to define a custom MenuUI that added a timer to its mouse handler.
Here is some simple example code that illustrates my problem:
public class Thing extends JFrame {
public Thing()
{
super();
this.setSize(new Dimension(500, 500));
final JPopupMenu pMenu = new JPopupMenu();
for (int i = 0; i < 5; i++)
{
JMenu menu = new JMenu("Menu " + i);
pMenu.add(menu);
for (int j = 0; j < 10; j++)
{
menu.add(new JMenuItem("Item " + j));
}
}
this.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
pMenu.show(Thing.this, e.getX(), e.getY());
}
});
}
public static void main(String[] args)
{
Thing t = new Thing();
t.setVisible(true);
}
}
Call setDelay(delay) on your menu variable, where the delay parameter is the amount of milliseconds to wait for the menu to show, as an int.
This following line of code will set the delay to 1 second, so the user has to mouseover the menu item "Menu n" 1 second, before the submenu is displayed: menu.setDelay(1000);
Here's a snippet of the edited code:
for (int i = 0; i < 5; i++)
{
JMenu menu = new JMenu("Menu " + i);
pMenu.add(menu);
for (int j = 0; j < 10; j++)
{
menu.add(new JMenuItem("Item " + j));
}
menu.setDelay(1000);
}
I came up with a very hacky solution.
I made a UI class that extends BasicMenuUI. I override the createMouseInputListener method to return a custom MouseInputListener instead of the private handler object inside BasicMenuUI.
I then got the code for the MouseInputListener implementation in handler from GrepCode[1], and copied it into my custom listener. I made one change, putting a timer in mouseEntered. My final code for mouseEntered looks like this:
public void mouseEntered(MouseEvent e) {
timer.schedule(new TimerTask() {
#Override
public void run() {
if (menuItem.isShowing())
{
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
Point menuLoc = menuItem.getLocationOnScreen();
if (mouseLoc.x >= menuLoc.x && mouseLoc.x <= menuLoc.x + menuItem.getWidth() &&
mouseLoc.y >= menuLoc.y && mouseLoc.y <= menuLoc.y + menuItem.getHeight())
{
originalMouseEnteredStuff();
}
}
}
}, 100);
}
Before calling the the original code that was in mouseEntered, I check to make sure the mouse is still within this menu's area. I don't want all the menus my mouse brushes over to pop up after 100 ms.
Please let me know if anyone has discovered a better solution for this.
[1] http://www.grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/7-b147/javax/swing/plaf/basic/BasicMenuUI.java/?v=source
Thank you very much, you saved my day! The solution works as expected but I recommend using the Swing timer to ensure the code is executed by the EDT.
Additionally you should temporary set the menus delay to zero before calling the original stuff. Otherwise the user has to wait twice the delay time.
#Override
public void mouseEntered(MouseEvent e) {
if (menu.isTopLevelMenu() || menu.getDelay() == 0) {
originalMouseEnteredStuff(e);
} else {
final javax.swing.Timer timer = new javax.swing.Timer(menu.getDelay(), new DelayedMouseEnteredAction(e));
timer.setRepeats(false);
timer.start();
}
}
class DelayedMouseEnteredAction implements ActionListener
{
private final MouseEvent mouseEnteredEvent;
private DelayedMouseEnteredAction(MouseEvent mouseEnteredEvent) {
this.mouseEnteredEvent = mouseEnteredEvent;
}
#Override
public void actionPerformed(ActionEvent actionEvent) {
if (menu.isShowing()) {
final Point mouseLocationOnScreen = MouseInfo.getPointerInfo().getLocation();
final Rectangle menuBoundsOnScreen = new Rectangle(menu.getLocationOnScreen(), menu.getSize());
if (menuBoundsOnScreen.contains(mouseLocationOnScreen)) {
/*
* forward the mouse event only if the mouse cursor is yet
* located in the menus area.
*/
int menuDelay = menu.getDelay();
try {
/*
* Temporary remove the delay. Otherwise the delegate would wait the
* delay a second time e.g. before highlighting the menu item.
*/
menu.setDelay(0);
originalMouseEnteredStuff(mouseEnteredEvent);
} finally {
// reset the delay
menu.setDelay(menuDelay);
}
}
}
}
}

Is there a way to animate an entire Jframe in Java so that it moves?

I would like to create a program where the Jframe is able to move freely on it's own. Kind of like a translation / transition.
For example,
Click on program to begin.
Jframe spawns at location (0,0).
Automatically move (animate) 100 pixels to the right so that the new coordinates are (100,0).
I know there's the setLocation(x,y) method that sets the initial position once the program runs but is there a way to move the entire Jframe after the program starts?
The basic concept would look something like this...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
public MoveMe01() {
EventQueue.invokeLater(
new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point location = frame.getLocation();
Point to = new Point(location);
if (to.x < 100) {
to.x += 4;
if (to.x > 100) {
to.x = 100;
}
}
if (to.y < 100) {
to.y += 4;
if (to.y > 100) {
to.y = 100;
}
}
frame.setLocation(to);
if (to.equals(location)) {
((Timer)e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}
This is a pretty straight, linear animation. You'd be better of investigating one of the many animation engines available for Swing, this will provide you with the ability to change the speed of the animation based on the current frame (doing things like slow-in and slow-out for example)
I would take a look at
Timing Framework
Trident
Universla Tween Engine
Updated with a "variable time" solution
This is basically an example of how you might do a variable time animation. That is, rather then having a fixed movement, you can adjust the time and allow the animation to calculate the movement requirements based on the run time of the animation...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
// How long the animation should run for in milliseconds
private int runTime = 500;
// The start time of the animation...
private long startTime = -1;
public MoveMe01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
// Start time of the animation...
startTime = System.currentTimeMillis();
}
// The current time
long now = System.currentTimeMillis();
// The difference in time
long dif = now - startTime;
// If we've moved beyond the run time, stop the animation
if (dif > runTime) {
dif = runTime;
((Timer)e.getSource()).stop();
}
// The percentage of time we've been playing...
double progress = (double)dif / (double)runTime;
Point location = frame.getLocation();
Point to = new Point(location);
// Calculate the position as perctange over time...
to.x = (int)Math.round(100 * progress);
to.y = (int)Math.round(100 * progress);
// nb - if the start position wasn't 0x0, then you would need to
// add these to the x/y position above...
System.out.println(to);
frame.setLocation(to);
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}

How to implement actionlistener inside a Timer program?

I need this timer program to run indefinately, until someone presses the reset button. This timer program would increment or decrement with a single click of a button. For example, click once, and it will increment UNTIL someone says it to stop, or to decrement. Problem is, I think i've made the correct codes for this, but it simply wont run. There must be a logical error in it, can't seem to pinpoint where exactly, though. Can you tell whats wrong with my code?
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class TimerTutorial extends JFrame {
JLabel timerLabel;
JButton buttonAdd, buttonMin, buttonReset;
Timer timer;
Timer timer2;
public TimerTutorial() {
setLayout(new GridLayout(2, 2, 5, 5));
buttonReset = new JButton("Press to reset");
add(buttonReset);
buttonAdd = new JButton("Press to Add");
add(buttonAdd);
buttonMin = new JButton("Press to Minus");
add(buttonMin);
timerLabel = new JLabel("Waiting...");
add(timerLabel);
event e = new event();
buttonAdd.addActionListener(e);
buttonMin.addActionListener(e);
buttonReset.addActionListener(e);
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
while (true) {
TimeClassAdd tcAdd = new TimeClassAdd();
timer = new Timer(1000, tcAdd);
timer.start();
timerLabel.setText("IT HAS BEGUN");
}
}
public class TimeClassAdd implements ActionListener {
int counter = 0;
public void actionPerformed(ActionEvent e) {
String status_symbol[] = new String[4];
status_symbol[0] = "Unused";
status_symbol[1] = "Green";
status_symbol[2] = "Yellow";
status_symbol[3] = "Red";
if (e.getSource() == buttonAdd) {
if (counter < 3) {
counter++;
timerLabel.setText("Time left: " + status_symbol[counter]);
} else {
timerLabel.setText("Time left: " + status_symbol[counter]);
}
} else if (e.getSource() == buttonMin) {
if (counter >= 3) {
counter = 3;
timerLabel.setText("Time left: " + status_symbol[counter]);
counter--;
} else if (counter == 2) {
timerLabel.setText("Time left: " + status_symbol[counter]);
counter--;
} else if (counter == 1) {
timerLabel.setText("Time left: " + status_symbol[counter]);
}
}
}
}
}
public static void main(String args[]) {
TimerTutorial gui = new TimerTutorial();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(500, 250);
gui.setTitle("Timer Tutorial");
gui.setVisible(true);
}
}
This while (true) will put your whole application to sleep:
while (true) {
TimeClassAdd tcAdd = new TimeClassAdd();
timer = new Timer(1000, tcAdd);
timer.start();
timerLabel.setText("IT HAS BEGUN");
}
Simply don't do this in a Swing application, at least not on the main Swing event thread since it ties up the event thread, allowing no other actions to take place. Besides since you are using a Timer, there's absolutely no need for the while loop in the first place.
Edit 1
Other problems:
Your TimeClassAdd is the ActionListener used by the Timer. The getSource returned from ActionEvent object that is passed into its actionPerformed method will be the object whose event triggered the event, here the timer not a button. So you cannot retrieve which button was pressed from this ActionEvent object.
Instead you will need to retrieve that information from the getSource() returned by the ActionEvent object passed into the the "event" class's actionPerformed method.

Categories

Resources