manipulating time in java swing - java

I was trying to manipulate an amateur animation using Swing in Java. The goal was to start an animation if I hover over a certain button. That was easy. But the problem is, I want to manipulate the speed of the timer of the animation according to the coordinates of the button.
For example, the more right I go on the button the more speedy the animation gets (delay time decreases) and vice-versa. The code I wrote works if I move the arrow out of the button then enter again. Then the delay changes according to co-ordinates. But not if I move the arrow within the region of the button. I used mouseEntered here. That may cause cause the problem. But the mouseMove function seems not to work too.
Here's my code:
private void jButton1MouseEntered(java.awt.event.MouseEvent evt)
{
// TODO add your handling code here:
PointerInfo inf = MouseInfo.getPointerInfo();
Point a = inf.getLocation();
double x = a.getX();
final int n = (int) (x - 161);
//String str=""+x;
//Output.setText(str);
ActionListener taskPerformer = null;
taskPerformer = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
//...Perform a task...
//if(t>0)timer.setDelay(1000);
if (t > 0)
{
timer.setDelay(500 + 50 * n);
}
if (label1 == 0)
{
jTextField1.setText(" A");
}
else if (label1 == 1)
{
jTextField1.setText(" B");
}
else if (label1 == 2)
{
jTextField1.setText(" C");
}
else if (label1 == 3)
{
jTextField1.setText(" D");
}
else if (label1 == 4)
{
jTextField1.setText(" E");
}
else if (label1 == 5)
{
jTextField1.setText(" F");
}
else if (label1 == 6)
{
jTextField1.setText(" G");
}
if (label1 >= 7)
{
label1 = 0;
}
else
{
label1++;
}
t++;
//System.out.printf("Reading SMTP Info. %d\n",x);
//System.out.printf("Reading SMTP Info. %d\n",label1t);
//jLabel3.setText("fsd");
}
private Object getContentPane()
{
throw new UnsupportedOperationException("Not supported yet.");
}
};
timer = new Timer(500, taskPerformer);
timer.start();
//timer.setRepeats(false);
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Logger.getLogger(Keyboard_Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}

But the mouseMove function seems not to work too.
The mouseMoved event is generated by a MouseMotionListener (not a MouseListener) so you will also need to implement that listener to manipulate the Timer interval.

Related

My JPanel is unable to listen for keyEvents?

I have built a snake game where a JPanel that implements a card layout manager is placed onto the JFrame. Three other JPanels are added to the card layout.
public void init () {
JOptionPane.showMessageDialog (this, "Don't let the snake hit the borders or you lose!", "Introduction to the Snake Game", JOptionPane.INFORMATION_MESSAGE);
appleCounter.label.setBorder (new LineBorder (Color.yellow, 1));
mainPanel.setLayout (card);//CHANGING THE LAYOUT MANAGER FOR THE JPANEL TO CARDLAYOUT
Screens [0] = new Screen ();//CREATING AN INSTANCE OF A JPANEL
mainPanel.add (Screens [0], "one");//ADDING THE JPANEL TO THE CARD LAYOUT
add (mainPanel, BorderLayout.CENTER);//ADDING THE JPANEL TO THE JFRAME
add (appleCounter.label, BorderLayout.SOUTH);
pack ();
setLocationRelativeTo (null);
setVisible (true);
}
This is so that after the snake collides with the border of the frame, a JDialog appears asking if they'd like to try again. If the player clicks 'yes' the next JPanel from the card layout will appear.
if (xCoor < 0 || xCoor > 80 || yCoor < 0 || yCoor > 60) {//IF THE SNAKE COLLIDES WITH THE BORDER OF THE FRAME
number = 1;
collide = true;
createApples ();
stop ();//CALLING THE METHOD THAT I AM HAVING PROBLEMS WITH
}
However, I am having issues with the stop method because when the snake collides with the border & the player clicks "yes" the next JPanel from the card layout appears. But the JPanel doesn't listen for any key inputs from the player, as a result, the snake cannot change directions.
public void stop () {
running = false;
try {
int response = JOptionPane.showConfirmDialog (this, "Do you want to play again?", "Opps looks like you lost", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (response == JOptionPane.YES_OPTION) {
if (digit < 3) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
digit++;
Frame.Screens [digit] = new Screen ();
if (digit == 1) {
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
Frame.Screens [digit] = null;
Frame.mainPanel.add (Frame.Screens [digit], "two");
Frame.card.removeLayoutComponent (Frame.Screens [digit]);
} else if (digit == 2) {
Frame.mainPanel.add (Frame.Screens [digit], "three");
}
} else if (response == JOptionPane.NO_OPTION) {
System.exit (0);
} else if (response == JOptionPane.CLOSED_OPTION) {
System.exit (0);
}
thread.join ();
} catch (InterruptedException e) {
e.printStackTrace ();
}//CLOSE CATCH
}
The JPanel instances are created using the Screen class which extends from JPanel class, even though the two JPanels in the card layout setFocusable to true so it should throw keyEvents.
public Screen () {
setFocusable (true);//THE JPANEL COMPONENT WILL BE AN EVENT SOURCE, THROWING KEY EVENTS TO THE KEY INSTANCE
addKeyListener (new Key ());//REGISTER THE KEY INSTANCE TO LISTEN TO KEY EVENTS
setPreferredSize (new Dimension (WIDTH, HEIGHT));
r = new Random ();
apples = new ArrayList <Apple> ();
start ();
}
Here is the inner class which has the keyPressed () that is called when the player clicks a directional key:
public class Key implements KeyListener {
public void keyPressed (KeyEvent e) {
int key = e.getKeyCode ();
if (key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if (key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if (key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if (key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
public void keyReleased (KeyEvent e) {}
public void keyTyped (KeyEvent e) {}
I am a beginner at Java so I would appreciate it if when answering this question there is a minimal amount of technical language or that the answer is explained in a way a beginner can understand. To clarify only the first Screen instance created in the init () listens for key inputs, the other two Screen instances cannot.

How to decrease number by 1 and when it hits 0 goes back to the starting point?

I have an array with a length of 3 so indexes 0,1,and 2. Then I have a counter(int c) and a rollover limit(int rollover = array.length) and two buttons that listen for when they are click will determine to go ahead one or go back one.
prev.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(c!=0) {
c--;
updateLabel(pokemons[c]);
} else if(c==0) {
c = rollover;
updateLabel(pokemons[c]);
}
}
});
next.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
c = (c+1) % rollover; //increase c until the limit
if(c==rollover) {
updateLabel(pokemons[c]);
}
else if(c<rollover) {
updateLabel(pokemons[c]);
}
}
});
The "next" button works, but my "prev" button encounters an error when you are at index 0, but works again when you click it again. Basically I have a JLabel that shows pictures of pokemon and when I click next or prev it calls the updateLabel method to change the JLabel and shows the next or previous pokemon in the array. Any ideas on how to fix the prev button?
I think it should be c = rollover-1; here:
if(c!=0) {
c--;
updateLabel(pokemons[c]);
} else if(c==0) {
c = rollover-1; // <-- here
updateLabel(pokemons[c]);
}

No Suitable Method Found

This is the method im trying to invoke.
public void update(int status) {
if (status == 1)
{
setBorder(new LineBorder(Color.YELLOW, BORDERSIZE+1));
}
else if (status == 2)
{
setBorder(new LineBorder(Color.CYAN, BORDERSIZE+1));
}
else if (status == 3)
{
setBorder(new LineBorder(Color.BLACK, BORDERSIZE));
}
revalidate();
}
This is the code trying to use it.
private void handleMouseClick(int x, int y, int button) {
try {
// This is called by the board squares when they are clicked
// Handle the logic of updates to the client/game here
if(button == 1){
if(x != -1 && y != -1){
update(1);
x = -1;
y = -1;
updateGrids();
}
else{
update(3);
}
}
else if(button == 3){
}
}
catch (IOException ex) {
System.err.println(ex);
}
The update method is inside a class called GridLayout, I've tried to just simply use GridLayout.update(aninteger); but it didn't work for me.
You need an instance of GridLayout object in order to call the update function.
Withouth knowning how GridLayout is related to your existing code I cannot advice further. However if GridLayout is a temporary object you could try:
GridLayout worker = new GridLayout(... whatever ...);
worker.update(aninteger);
Otherwise, you might need to get it from the framework involved, or something along these lines:
this.getGridLayout().update(aninteger);

KeyListener wont focus

I'm new to Java so please forgive me asking for help, but after 4 hours of searching for a solution I'm really getting desperate.
I'm currently setting up a game and want to implement key controls. I tried to do this via KeyListener and KeyEventDispatcher but I just can't get it to work.
The KeyListener just won't react. I think that the method that is supposed to use it has the focus.
Here's the code:
public class Sins extends JFrame implements KeyEventDispatcher {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED ) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
if(KeyEvent.VK_UP == e.getID()){
System.exit(0);
}
}
return false;
}
and here is the method where it is supposed to be working at:
public void run() {
setFocusable(true);
backgroundGraphics = (Graphics2D) background.getGraphics();
long fpsWait = (long) (1.0 / 30 * 1000);
requestFocusInWindow();
main: while (isRunning==true) {
long renderStart = System.nanoTime();
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(this);
x++;
requestFocusInWindow();
// Update Graphics
do {
Graphics2D bg = getBuffer();
if (isRunning == false) {
break main;
}
renderGame(backgroundGraphics); // this calls your draw method
if (scale != 1) {
bg.drawImage(background, 0, 0, width * scale, height
* scale, 0, 0, width, height, null);
} else {
bg.drawImage(background, 0, 0, null);
}
bg.dispose();
requestFocusInWindow();
this.requestFocus();
if(x ==5000){
isRunning=false;
}
} while (!updateScreen());
// Better do some FPS limiting here
long renderTime = (System.nanoTime() - renderStart) / 10000;
try {
Thread.sleep(Math.max(0, fpsWait - renderTime));
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
renderTime = (System.nanoTime() - renderStart) / 10000;
}
this.dispose();
System.exit(0);
}
The program is currently closing itself after counting up to 5000. For test purposes I'm trying to close it via the up button but it just won't close that way.
I would really appreciate some help, as I said I'm new to Java.
The first problem you were facing with KeyListener is a well know and well documented (here on SO especially). KeyListener will only on respond if the component they are attached to is focusable and has keyboard focus. Think of a text field, when it doesn't have focus, it won't update.
Your second problem is using the KeyBoardFocusManager, which is simply overkill for this problem.
Instead, you should make use of the [Key Bindings] API, which is simpler the having to monitor the KeyBoardFocusManager and more robust then KeyListeners

Java : detect triple-click without firing double-click

I have a JTable in which I want to call a function when a cell is double-clicked and call another function when the cell is triple-clicked.
When the cell is triple-clicked I do not want to call the double-click-function.
What I have right now is (mgrdAlarm is the JTable) :
mgrdAlarm.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("getClickCount() = " + e.getClickCount());
if (e.getClickCount()==2)
{
doubleClick();
System.out.println("Completed : doubleClick()");
}
if (e.getClickCount()==3)
{
tripleClick();
System.out.println("Completed : tripleClick()");
}
}
});
When double-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
When triple-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
getClickCount() = 3
Completed : tripleClick()
When triple-clicked I want the console to show :
getClickCount() = 1
getClickCount() = 2
getClickCount() = 3
Completed : tripleClick()
So I do not want to call the function doubleClick() when the cell is triple-clicked, but I do want to call the function doubleClick() when the cell is double-clicked.
[EDIT]
As all replies suggest the solution seems to be to delay the double-click-action and wait a certain time for the triple-click.
But as discussed here that might lead to a different type of problem :
The user might have set his double-click-time quite long, which might overlap with the timeout of my triple-click.
It is no real disaster if my double-click-action is executed before my triple-click-action, but it does generate some extra overhead, and especially some extra data traffic which I would like to prevent.
As the only solution so far might lead to other problems, which might actually be worse than the original problem, I will leave it as it is right now.
public class TestMouseListener implements MouseListener {
private boolean leftClick;
private int clickCount;
private boolean doubleClick;
private boolean tripleClick;
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
if(evt.getClickCount() == 3){
doubleClick = false;
tripleClick = true;
}
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
Timer timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
clickCount++;
if(clickCount == 2){
doubleClick(); //your doubleClick method
clickCount=0;
doubleClick = false;
leftClick = false;
}
}else if (tripleClick) {
System.out.println("Triple Click.");
clickCount++;
if(clickCount == 3) {
tripleClick(); //your tripleClick method
clickCount=0;
tripleClick = false;
leftClick = false;
}
} else if(leftClick) {
System.out.println("single click.");
leftClick = false;
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}
}
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new TestMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new TestMouseListener());
}
}
The previous answers are correct: you have to account for the timing and delay recognizing it as a double click until a certain amount of time has passed. The challenge is that, as you have noticed, the user could have a very long or very short double click threshold. So you need to know what the user's setting is. This other Stack Overflow thread ( Distinguish between a single click and a double click in Java ) mentions the awt.multiClickInterval desktop property. Try using that for your threshold.
You can do something like that, varying delay time:
public class ClickForm extends JFrame {
final static long CLICK_FREQUENTY = 300;
static class ClickProcessor implements Runnable {
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor) {
this.eventProcessor = eventProcessor;
}
#Override
public void run() {
try {
Thread.sleep(CLICK_FREQUENTY);
eventProcessor.call();
} catch (InterruptedException e) {
// do nothing
} catch (Exception e) {
// do logging
}
}
}
public static void main(String[] args) {
ClickForm f = new ClickForm();
f.setSize(400, 300);
f.addMouseListener(new MouseAdapter() {
Thread cp = null;
public void mouseClicked(MouseEvent e) {
System.out.println("getClickCount() = " + e.getClickCount() + ", e: " + e.toString());
if (cp != null && cp.isAlive()) cp.interrupt();
if (e.getClickCount() == 2) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Double click processed");
return null;
}
}));
cp.start();
}
if (e.getClickCount() == 3) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Triple click processed");
return null;
}
}));
cp.start();
}
}
});
f.setVisible(true);
}
}
You need to delay the execution of double click to check if its a tripple click.
Hint.
if getClickCount()==2 then put it to wait.. for say like 200ms?
It's exactly the same problem as detecting double-click without firing single click. You have to delay firing an event until you're sure there isn't a following click.
There's a tutorial for this
here
Edit: It fires click events individually though, so you would get:
Single Click THEN
Double Click THEN
Triple Click. So you would still have to do some timing trickery.
The code is:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Main {
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new MyMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new MyMouseListener());
}
}
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 3) {
System.out.println("triple-click");
} else if (evt.getClickCount() == 2) {
System.out.println("double-click");
}
}
}
Here is what i have done to achieve this, this actually worked fine for me. A delay is necessary to detect the type of click. You can choose it. The following delays if a triple click can be happened within 400ms. You can decrease it to the extent till a consecutive click is not possible. If you are only worrying about the delay, then this is a highly negligible delay which must be essential to carry this out.
Here flag and t1 are global variables.
public void mouseClicked(MouseEvent e)
{
int count=e.getClickCount();
if(count==3)
{
flag=true;
System.out.println("Triple click");
}
else if(count==2)
{
try
{
t1=new Timer(1,new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
if(!flag)
System.out.println("Double click");
flag=false;
t1.stop();
}
});
t1.setInitialDelay(400);
t1.start();
}catch(Exception ex){}
}
}

Categories