When you use the method
public boolean mouseDown(Event e, int x, int y)
in Java, what does the Event object do or what is it used for? I am trying to write a program that involves someone clicking on a rectangle created by
g.fillRect(horizontal position,vertical position,height,width);
I presume you use event handling to pick up the click on the rectangle with the mousedown method, but how can u do this? Please provide examples in your answers. I did my research on Google, and found nothing, even with really specific searches. Help greatly appreciated!
mouseDown is a mouse event. What you need to do is add an event listener to your program, so when the mouse is clicked an event handler calls a method. In this method you want to see if the x,y position of the mouse is within the rectangle.
You will need to implement MouseListener "implements MouseListener"
// import an extra class for the MouseListener
import java.awt.event.*;
public class YourClassName extends Applet implements MouseListener
{
int x = horizontal position;
int y = vertical position;
g.fillRect(x,y,width,height);
addMouseListener(this);
// These methods always have to present when you implement MouseListener
public void mouseClicked (MouseEvent mouseEvent) {}
public void mouseEntered (MouseEvent mouseEvent) {}
public void mousePressed (MouseEvent mouseEvent) {}
public void mouseReleased (MouseEvent mouseEvent) {}
public void mouseExited (MouseEvent mouseEvent) {}
public void mouseClicked (MouseEvent mouseEvent) {
mouseX = mouseEvent.getX();
mouseY = mouseEvent.getY();
if(mouseX > x && mouseY > y && mouseX < x+width && mouseY < y+height){
//
// do whatever
//
}
}
for more...
http://docs.oracle.com/javase/6/docs/api/java/awt/event/MouseListener.html
The Event object contains information like the
x and y coordinates of the event,
The target component on which the event happened
when the even happened
It provides lot of other information as well.
Note: The method is deprecated in favour of processMouseEvent().
As you have asked this
in Java, what does the Event object do or what is it used for?
- First of all there are Event Source, when any action take place on the Event Source, an Event Object is thrown to the call back method.
- Call Back method is the method inside the Listener (Interface) which is needed to be implemented by the Class that implements this Listener.
- The statements inside this call back method will dictate whats needed to be done, when the action is done on the Event Source.
Eg:
Assume
Event Source - Button
When Clicked - Event object is thrown at the call back method
Call back method - actionPerformed(ActionEvent e) inside ActionListener.
- In your example when the mouse button goes down, the x and y co-ordinate gets noted.
Then the event object it thrown at its call back method, which needs to be handled by the
class that implements this Listener.
- Its better to use mousePressed method of MouseListener Interface.
See this link:
http://docs.oracle.com/javase/6/docs/api/java/awt/event/MouseListener.html#mousePressed%28java.awt.event.MouseEvent%29
Related
I am creating a simple event-driven GUI for a video game I am making with LibGDX. It only needs to support buttons (rectangular) with a single act() function called when they are clicked. I would appreciate some advice on structuring because the solution I've thought of so far seems to be far from ideal.
My current implementation involves all buttons extending a Button class. Each button has a Rectangle with its bounds and an abstract act() method.
Each game screen (e.g. main menu, character select, pause menu, the in-game screen) has a HashMap of Buttons. When clicked, the game screen iterates through everything in the HashMap, and calls act() on any button that was clicked.
The problem I'm having is that Buttons have to have their act() overridden from their superclass in order to perform their action, and that the Buttons aren't a member of the Screen class which contains all the game code. I am subclassing Button for each button in the game. My main menu alone has a ButtonPlay, ButtonMapDesigner, ButtonMute, ButtonQuit, etc. This is going to get messy fast, but I can't think of any better way to do it while keeping a separate act() method for each button.
Since my mute button isn't a part of the main menu screen and can't access game logic, it's act() is nothing more than mainMenuScreen.mute();. So effectively, for every button in my game, I have to create a class class that does nothing more than <currentGameScreen>.doThisAction();, since the code to actually do stuff must be in the game screen class.
I considered having a big if/then to check the coordinates of each click and call the appropriate action if necessary. For example,
if (clickWithinTheseCoords)
beginGame();
else if(clickWithinTheseOtherCoords)
muteGame();
...
However, I need to be able to add/remove buttons on the fly. When a unit is clicked from the game screen, a button to move it needs to appear, and then disappear when the unit is actually moved. With a HashMap, I can just map.add("buttonMove", new ButtonMove()) and map.remove("buttonMove") in the code called when a unit is clicked or moved. With the if/else method, I won't need a separate class for every button, but I would need to keep track of whether each clickable area tested is visible and clickable by the user at this point in the game, which seems like an even bigger headache that what I have right now.
I would provide a runnable to all the buttons which u will run in the act method. To give u a simple example.
private final Map<String, Button> buttons = new HashMap<>();
public void initialiseSomeExampleButtons() {
buttons.put("changeScreenBytton", new Button(new Runnable() {
#Override
public void run() {
//Put a change screen action here.
}
}));
buttons.put("muteButton", new Button(new Runnable() {
#Override
public void run() {
//Do a mute Action here
}
}));
}
public class Button {
//Your other stuff like rectangle
private final Runnable runnable;
protected Button(Runnable runnable) {
this.runnable = runnable;
}
public void act() {
runnable.run();
}
}
You keep track of your buttons via the map and just need to pass a runnable action to every button in the constructor. I intentionally skipped some code so that you can try yourself. If you have any questions, let me know.
Sneh's response reminded me of a fairly major oversight - instead of having to create a separate class for every button, I could use anonymous inner classes whenever I created a button, specifying its coordinates and act() method every time. I explored lambda syntax as a possible shorter method to do this, but ran into limitations with it. I ended up with a flexible solution, but ended up reducing it a bit further to fit my needs. Both ways are presented below.
Each game screen in my game is subclassed from a MyScreen class, which extends LibGDX's Screen but adds universal features like updating the viewport on resize, having a HashMap of Buttons, etc. I added to the MyScreen class a buttonPressed() method, which takes in as its one parameter an enum. I have ButtonValues enum which contains all the possible buttons (such as MAINMENU_PLAY, MAINMENU_MAPDESIGNER, etc.). In each game screen, buttonPressed() is overriden and a switch is used to perform the correct action:
public void buttonPressed(ButtonValues b) {
switch(b) {
case MAINMENU_PLAY:
beginGame();
case MAINMENU_MAPDESIGNER:
switchToMapDesigner();
}
}
The other solution has the button store a lambda expression so that it can perform actions on its own, instead of requiring buttonPressed() to act as an intermediary that performs the correct action based on what button was pressed.
To add a button, it is created with its coordinates and type (enum), and added to the HashMap of buttons:
Button b = new Button(this,
new Rectangle(300 - t.getRegionWidth() / 2, 1.9f * 60, t.getRegionWidth(), t.getRegionHeight()),
tex, ButtonValues.MAINMENU_PLAY);
buttons.put("buttonPlay", b);
To remove it, just buttons.remove("buttonPlay"). and it'll disappear from the screen and be forgotten by the game.
The arguments are the game screen which owns it (so the button can call buttonPressed() on the game screen), a Rectangle with its coordinates, its texture (used to draw it), and its enum value.
And here's the Button class:
public class Button {
public Rectangle r;
public TextureRegion image;
private MyScreen screen;
private ButtonValues b;
public Button(MyScreen screen, Rectangle r, TextureRegion image, ButtonValues b) {
this.screen = screen;
this.r = r;
this.image = image;
this.b = b;
}
public void act() {
screen.buttonPressed(b);
}
public boolean isClicked(float x, float y) {
return x > r.x && y > r.y && x < r.x + r.width && y < r.y + r.height;
}
}
isClicked() just takes in an (x, y) and checks whether that point is contained within the button. On mouse click, I iterate through all the buttons and call act() if a button isClicked.
The second way I did it was similar, but with a lambda expression instead of the ButtonValues enum. The Button class is similar, but with these changes (it's a lot simpler than it sounds):
The field ButtonValues b is replaced with Runnable r, and this is removed from the constructor. Added is a setAction() method which takes in a Runnable and sets r to the Runnable passed to it. The act() method is just r.run(). Example:
public class Button {
[Rectangle, Texture, Screen]
Runnable r;
public Button(screen, rectangle, texture) {...}
public void setAction(Runnable r) { this.r = r; }
public void act() { r.run(); }
}
To create a button, I do the following:
Button b = new Button(this,
new Rectangle(300 - t.getRegionWidth() / 2, 1.9f * 60, t.getRegionWidth(), t.getRegionHeight()),
tex);
b.setAction(() -> b.screen.doSomething());
buttons.put("buttonPlay", b);
First, a button is created with its containing game screen class, its bounding box, and its texture. Then, in the second command, I set its action - in this case, b.screen.doSomething();. This can't be passed to the constructor, because b and b.screen don't exist at that point. setAction() takes a Runnable and sets it as that Button's Runnable that is called when act() is called. However, Runnables can be created with lambda syntax, so you don't need to create an anonymous Runnable class and can just pass in the function it performs.
This method allows much more flexibility, but with one caveat. The screen field in Button holds a MyScreen, the base screen class from which all of my game screens are extended. The Button's function can only use methods that are part of the MyScreen class (which is why I made buttonPressed() in MyScreen and then realized I could just scrap the lambda expressions completely). The obvious solution is to cast the screen field, but for me it wasn't worth the extra code when I could just use the buttonPressed() method.
If I had a beginGame() method in my MainMenuScreen class (which extends MyScreen), the lambda expression passed to the button would need to involve a cast to MainMenuScreen:
b.setAction(() -> ((MainMenuScreen) b.screen).beginGame());
Unfortunately, even wildcard syntax doesn't help here.
And finally, for completeness, the code in the game loop to operate the buttons:
public abstract class MyScreen implements Screen {
protected HashMap<String, Button> buttons; // initialize this in the constructor
// this is called in every game screen's game loop
protected void handleInput() {
if (Gdx.input.justTouched()) {
Vector2 touchCoords = new Vector2(Gdx.input.getX(), Gdx.input.getY());
g.viewport.unproject(touchCoords);
for (HashMap.Entry<String, Button> b : buttons.entrySet()) {
if (b.getValue().isClicked(touchCoords.x, touchCoords.y))
b.getValue().act();
}
}
}
}
And to draw them, located in a helper class:
public void drawButtons(HashMap<String, Button> buttons) {
for (HashMap.Entry<String, Button> b : buttons.entrySet()) {
sb.draw(b.getValue().image, b.getValue().r.x, b.getValue().r.y);
}
}
I am making a game where you have two buttons to rotate the player, one to left and the other one to right. I'm using a TextButton in LibGDX. My problem is that the method clicked(InputEvent event, float x, float y) in ClickListener is only called once it's clicked. I want an event to be called repeatedly as long as it's held down. Here is my code:
TextButton btnLeft = new TextButton("<", styleButton);
TextButton btnRight = new TextButton(">", styleButton);
btnLeft.setSize(100, 100);
btnRight.setSize(100, 100);
btnLeft.setPosition(25, 25);
btnRight.setPosition(200, 25);
btnLeft.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
player.rotate(-1);
System.out.println("Left");
}
});
btnRight.addListener(new ClickListener() {
Override
public void clicked(InputEvent event, float x, float y) {
player.rotate(1);
System.out.println("Right");
}
});
stage.addActor(btnLeft);
stage.addActor(btnRight);
The listener is not good place to perform continuous actions since it is by definition asynchronous mechanism. The place to perform some action like this is render() method of Screen or act() method of actor.
Although you can use listener to check a state of actor (is it pressed or not) in this way:
//Global instance
ClickListener listenerLeft;
//show() method
...
listenerLeft= new ClickListener();
btnLeft.addListener(listenerLeft);
...
//render() method
...
if(listenerLeft.isPressed())
//perform turning left
...
The second option is to implement ClickListener's touchUp and touchDown methods to change some flag and then check it in render but it would not be doing anything new.
Worth to notice is than both ClickListener and DragListener have touchDragged method that is something about what you want but works only if the mouse/finger is moving when touching actor
listener = new DragListener(){
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer)
{
System.out.println("Left");
}
};
Keeping touching is not an action - no action = nothing to listen
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class AppWindow extends Frame {
String keyMessage = "";
String MouseMsg = "";
int mouseX = 10;
int mouseY = 40;
int locX = 0;
int locY = 0;
public AppWindow() {
addMouseListener(new MyMouseAdaptor(this));
}
public void paint(Graphics g) {
g.drawString(keyMessage, mouseX, mouseY);
g.drawString(MouseMsg, locX, locY);
}
public static void main(String[] args) {
AppWindow appWindow = new AppWindow();
appWindow.setSize(400, 400);
appWindow.setVisible(true);
}
}
class MyMouseAdaptor extends MouseAdapter implements MouseListener {
AppWindow appWindow;
public MyMouseAdaptor(AppWindow appWindow) {
this.appWindow = appWindow;
}
public void mousePressed(MouseEvent e) {
this.appWindow.MouseMsg = "Mouse Pressed at : " + e.getX() + ", "
+ e.getY();
this.appWindow.locX = e.getX();
this.appWindow.locY = e.getY();
this.appWindow.repaint();
}
}
Dear All
I have a weird question. I know everything in the above code yet I am missing something. How Java knows when the mousePressed Event occurred? I need to find the answer for my own logic. Where is the code written that says
when the user press the mouse -- > trigger the method "public void mousePressed(MouseEvent e)" and do what is inside it
Thanks
This is the code that registers to look out for mouse events:
public AppWindow() {
addMouseListener(new MyMouseAdaptor(this));
}
This is your class that extends MouseAdaptor and listens for events:
class MyMouseAdaptor extends MouseAdapter implements MouseListener {
AppWindow appWindow;
public MyMouseAdaptor(AppWindow appWindow) {
this.appWindow = appWindow;
}
public void mousePressed(MouseEvent e) {
this.appWindow.MouseMsg = "Mouse Pressed at : " + e.getX() + ", "
+ e.getY();
this.appWindow.locX = e.getX();
this.appWindow.locY = e.getY();
this.appWindow.repaint();
}
}
MouseAdaptor:
An abstract adapter class for receiving mouse events. The methods in this class are empty. This class exists as convenience for creating listener objects.
Mouse events let you track when a mouse is pressed, released, clicked, moved, dragged, when it enters a component, when it exits and when a mouse wheel is moved.
Extend this class to create a MouseEvent (including drag and motion events) or/and MouseWheelEvent listener and override the methods for the events of interest. (If you implement the MouseListener, MouseMotionListener interface, you have to define all of the methods in it. This abstract class defines null methods for them all, so you can only have to define methods for events you care about.)
Create a listener object using the extended class and then register it with a component using the component's addMouseListener addMouseMotionListener, addMouseWheelListener methods. The relevant method in the listener object is invoked and the MouseEvent or MouseWheelEvent is passed to it in following cases:
when a mouse button is pressed, released, or clicked (pressed and released)
when the mouse cursor enters or exits the component
when the mouse wheel rotated, or mouse moved or dragged
Link
MouseListener:
The listener interface for receiving "interesting" mouse events (press, release, click, enter, and exit) on a component. (To track mouse moves and mouse drags, use the MouseMotionListener.)
The class that is interested in processing a mouse event either implements this interface (and all the methods it contains) or extends the abstract MouseAdapter class (overriding only the methods of interest).
The listener object created from that class is then registered with a component using the component's addMouseListener method. A mouse event is generated when the mouse is pressed, released clicked (pressed and released). A mouse event is also generated when the mouse cursor enters or leaves a component. When a mouse event occurs, the relevant method in the listener object is invoked, and the MouseEvent is passed to it.
Link
Now after you have read this, I think you will be able to make some changes to your program because when you implement MouseListener interface you have to define all of the methods in it..
There are actually two event classes associated with the mouse: MouseEvent and MouseMotionEvent. There are also two listener interfaces, MouseListener and MouseMotionListener. The MouseListener interface declares the methods
public void mousePressed(MouseEvent evt);
public void mouseReleased(MouseEvent evt);
public void mouseClicked(MouseEvent evt);
public void mouseEntered(MouseEvent evt);
public void mouseExited(MouseEvent evt);
and the MouseMotionListener declares
public void mouseMoved(MouseEvent evt);
public void mouseDragged(MouseEvent evt);
Any component can generate mouse events. An object that wants to respond to these events must implement one or both of the listener interfaces. It must also register itself with the component by calling the component's addMouseListener() and/or addMouseMotionListener() methods. Note that an object that implements MouseListener must provide definitions for all five of the methods in that interface, even if a definition consists just of an empty set of braces. Similarly, an object that implements MouseMotionListener must define both the mouseMoved() and the mouseDragged() methods.
A component calls mousePressed() whenever one of the buttons on the mouse is pressed while the mouse cursor is over that component. It will then call the mouseReleased() method when the button is released -- even if the cursor has moved outside of the component by that time. The mouseClicked() method is called if the button is pressed and released at the same point; it is called in addition to mousePressed() and mouseReleased(). If you simply want to respond to mouse clicks, you should probably do so in the mousePressed() routine, and leave the definitions of mouseReleased() and mouseClicked() empty.
Source
I am trying to develop a very basic game and it involves mouse. So what i am trying to do is getting coordinates of mouse to write a integer. I searched internet and find this.
mouse_x=MouseInfo.getPointerInfo().getLocation().getX();
mouse_y=MouseInfo.getPointerInfo().getLocation().getY();
It partially worked and gave me coordinates of mouse on desktop. But what i need is coordinates of mouse on frame. So if only i knew the coordinates of frame's starting (0,0) point (not the window's. the white area without toolbars.) I could calculate mouse's coordinates.
Thanks in advance.
Or if thats not possible i could use how to develop it in fullscreen.
And i need to know location of mouse always. It should refresh position when i run it in a never ending while loop.
I just use e.getPoint() which returns the point of the mouse clicked. You could either have your Frame implement MouseListener of you can register a MouseListener to the frame if it is not the main GUI component.
public class MyFrame extends JFrame implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
int x = (int) p.getX();
int y = (int) p.getY();
// do something withe the x and y points
}
}
If you do the above, you also need to override the other MouseListener methods. Though you don't need to implement any action for them
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
If your GUI class didn't extend JFrame, then you can just register the listener to the Frame, in which case you only need to use the MouseAdapter, which allows you to just implement 0 or more action method (i.e. just mouseClicked)
frame.addMouseListener(new MouseAdapter() {
void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
int x = (int) p.getX();
int y = (int) p.getY();
// do somthing withe the x and y points
}
});
Edit for MouseMotionListener
"I want to know location of mouse always not just when clicked."
If you wan't to know the location of the mouse at any given time, you should implement MouseMotionListener and override the mouseDragged and mouseMoved
public class MyFrame extends JFrame implements MouseMotionListener {
....
public void mouseMoved(MouseEvent e){
Point p = e.getPoint();
int x = (int) p.getX();
int y = (int) p.getY();
// do something withe the x and y points
}
public void mouseDragged(MouseEvent e){
}
}
The mouseMoved will fire an event every time the mouse is moved, and the mouseDragged will fire an event whenever the mouse is dragged
You need to add a MouseListener to your JFrame and then you can just get the relative coordinates with MouseEvent.getPoint
frame.addMouseListener(new MouseAdapter() {
void mouseClicked(MouseEvent e) {
System.out.println(e.getPoint());
}
});
If you, for some obscure reason, need the coordinates in a situation when mouse events are not available (in which case, take a look at the other answers), you can use SwingUtilities.convertPointFromScreen() to convert the coordinates from MouseInfo to the coordinate system of a Component.
essentially I want to run a method whenever the user goes from not moving their mouse at all, to moving it. I have no clue how to go about this.
custom listener:
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class CustomMouseListener implements MouseMotionListener, MouseListener{
//whatever other methods I have (irrelevant for the question)
public void mouseMoved(MouseEvent e){
//code goes here
//but right now it fires every time the mouse is moved, which
//is way too much, I only need one per move
}
}
Plain algorithm
0. Fire mouse listener for every second with (x=x1, y=y1)
1. Store (x,y) of mouse pointer;
2. If (x,y) == (x1,y1) for another 15(or whatever you consider as time interval) sec
3. make account of (x1,y1);
4. Else do nothing;
5. If(x1,y1) changed after 15 sec
6. call mouseMove();
If you're only interested in knowing two things, when the mouse started to move and when the mouse stopped moving, you could use a javax.swing.Timer to insert a delay between events, so that it will only be tiggered when the delay is reached...
public class CustomMouseListener implements MouseMotionListener, MouseListener{
private javax.swing.Timer moveTimer;
private boolean moving = false;
public CustomMouseListener() {
moveTimer = new javax.swing.Timer(25, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
moving = false;
// Method to be called when you want to
// to know when the mouse has stopped moving...
}
});
moveTimer.setRepeats(false);
}
//whatever other methods I have (irrelevant for the question)
public void mouseMoved(MouseEvent e){
if (moving || moveTimer.isRunning()) {
moveTimer.restart();
} else {
moving = true;
moveTimer.start();
// Method to call when you want to know when the mouse
// has started moving...
}
}
}
Basically, when 25 milliseconds pass without mouseMoved being called, the javax.swing.Timer will be triggered....You may want to play with the threshold a little...
One way to do it would be save the last time it moved. If current time - lastMovedTime > x then call your listeners or mouseStartedMoving() method
public class CustomMouseListener implements MouseMotionListener, MouseListener{
public final static long TIME_DIFFERNCE_FOR_IDLE = 800;//milliseconds
long lastMoveTime = -1;
public void mouseMoved(MouseEvent e){
long currentTime = System.currentTimeMillis();
long diff = lastMoveTime - currentTime ;
if(lastMoveTime == -1 || diff > TIME_DIFFERNCE_FOR_IDLE ){
lastMoveTime();
}
lastMoveTime = System.currentTimeMillis();
}
}
void lastMoveTime(){
//do what u need to when mouse starts mooving
}
Another Need to adda polling thread. Can make a default thread pool of size 1. ADd one task (Runnable) in the run method sleep for 1 second (or 2 or 800 milliseconds - depends what you define as pause between moves)
Anyway in your original code keep track of the current mouse position x,y and expose to the runnable.
The runnable keeps track of previous mouse position. Also have a state variable in Runnable that is an enum - {INITIAL, STATIONARY, MOVING}.
Initially its INITIAL, if you get mouse move position and its INITIAL it goes to MOVING
IF MOVING and for X ticks in the Runnable it does not move goes to STATIONARY. Again on Mouse move it goes to MOVING.
When it goes from INITIAL to MOVING OR STATIONARY to MOVING, can have listeners who are called or just a special method - mouseStartedMoving()
And do whatever there.