Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (576)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [Java2D] How would I go for making buttons?  (Read 2311 times)
0 Members and 1 Guest are viewing this topic.
Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Posted 2013-09-09 22:32:50 »

Hello all.

I've been looking everywhere for resources on how to create your own GUI system, and I can't find anything good or helpful, nor can I find anything I can understand.

I'm working on a title menu for my game, and I need help writing a decent button class that can detect the mouse's coordinates.

I have mouse input working, but I am having issues simply detecting an area of the screen. I have a point called msl (mouse location) that is controlled by my Input class. I then check for the point by doing something like this:
if (msl == new Point(12, 12)) hover = true;
. That would only detect one pixel, how would I go for detecting a large area on the screen, similar to what I'd do with an array?

Sorry if this question sounds dumb or if my English isn't spot on, but I really want help with this. I'm tired of text-based GUIs Sad.

-Jev.

Offline Several Kilo-Bytes

Senior Duke


Medals: 11



« Reply #1 - Posted 2013-09-09 23:37:03 »

The mouse location is a point. The button [is/should be] a rectangle. Search for point-rectangle intersection tests. A button can (but likely shouldn't) be any other shape, so infer what word you would change in the search terms if the button wasn't a rectangle.
Offline philfrei
« Reply #2 - Posted 2013-09-09 23:44:19 »

If you use a JButton for your button, you can put a MouseListener and/or MouseMotionListener within it. That listener will work purely locally for that component.

"It's after the end of the world! Don't you know that yet?"
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Agro
« Reply #3 - Posted 2013-09-09 23:47:13 »

You can just set an image on the JButton or something like that. I remember I extended the JButton and overloaded or something the paint method? That works right? I forgot

Offline jonnyzGaming
« Reply #4 - Posted 2013-09-09 23:50:56 »

Easiest way: First create a rectangle for the button area and then use the rectangles contains method.
Eg: if(rect.contains(msg)hover = true;

JButtons are messy in games Tongue.


Offline Agro
« Reply #5 - Posted 2013-09-09 23:52:40 »

Well its the title screen so it can't hurt

Offline Slyth2727
« Reply #6 - Posted 2013-09-09 23:59:33 »

From what I remembered from my java2d tower defence game what I did was have a button class (duh Tongue ) and inside of it have a rectangle object for mouse collision. In the constructor I set the width and height and x and y. Then I added this to an arraylist in my main class which then, every update or repaint, iterates through that list and checks if the mouse is on it. If so, set the (there is a button image which is slightly transparent) whiteish rectangle behind the button to look like it is lighting up. Then, if clicked inside the rectangle, call the button's click method which is overridden in the class the button is implemented in. I know that is very confusing but that is kinda how I remember it. Just try and do what Agro said instead of hard coding the buttons like I did. Unless you want a challenge Wink

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #7 - Posted 2013-09-10 00:31:29 »

Wow, I never even considered doing a Rectangle.

I'll try that here in a few guys.

Thanks,
Jev.

Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #8 - Posted 2013-09-10 02:13:51 »

Still not working.

Here's my code.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
package net.kemoy.G581G.gui;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import net.kemoy.G581G.Art;
import net.kemoy.G581G.Core;

public class Button extends Rectangle {
   public static final long serialVersionUID = 1L;
   
   public Point mse = new Point(0, 0);
   BufferedImage button;
   
   public Button(String msg, int x, int y) {
      setBounds(x, y, Art.b1.getWidth(), Art.b1.getHeight());
      System.out.println(getBounds());
      button = Art.b1;
      String mval = msg;
      Graphics g = Core.display.getGraphics();
     
      g.drawImage(button, x, y, null);
      Fonts.drawString(mval, x + 20, y + 20);
   }

   public Button() {
     
   }
   
   public void tick() {
      if (contains(new Point(mse))) {
         button = Art.b2;
         System.out.println("Woohoo!");
      }
   }
}


It can detect the location and size now, but now I'm having issues with the mouse coordinates.

Offline wessles

JGO Wizard


Medals: 67
Projects: 4
Exp: 3 years


Profile picture isn't relevant.


« Reply #9 - Posted 2013-09-10 02:29:21 »

Is mse the mouse coords? B/c You never modify it...

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #10 - Posted 2013-09-10 03:20:25 »

'mse' is the point of the mouse coordinates that are collected in my input class.

Online BurntPizza
« Reply #11 - Posted 2013-09-10 03:24:54 »

Make sure that your mse and the rectangle you test for intersection are using the same coordinate system, i.e. J2D's upper-left corner being 0,0 and y increasing downwards.

Also, I don't see why you need to copy mse each tick(), unless you are trying to do some kind of thread safety, which if that is the case, you are going about it wrong.
Offline Agro
« Reply #12 - Posted 2013-09-10 03:27:46 »

Instead of extending rectangle i would rather just keep a field that contains rectangle

Offline CodeHead

JGO Knight


Medals: 41


From rags to riches...to rags.


« Reply #13 - Posted 2013-09-10 05:38:11 »

Is mse the mouse coords? B/c You never modify it...

^This^

'mse' is the point of the mouse coordinates that are collected in my input class.

As Wesley said, your 'mse' variable is never updated (at least not in the code you posted). Your tick function is referencing the class level variable which is stuck at [0,0].

My approach to doing something like this is to create a base control class that contains the basic properties (visible, dimension, render point, etc) a "contains" function to check for mouse events, and an abstract render method then just extend/override the base class for your more specific classes. It may be a bit of an overkill if you're just looking to add a couple of buttons to your main menu, but it makes implementing other controls such as progress bars, input controls, check boxes, and the like a lot easier (and more fun) in the long run. Your mileage may vary, but this approach has been serving me well while I've been developing my GUI library over the past couple of months. Cool

Edit: Just realized that your 'mse' variable is public. Are you updating this variable directly from outside of the button class? Shocked If that's the case, have you tried tracing what value it's set to on each tick? One other note, since 'mse' is already a Point, there's really no need to create a new point in your tick method for the contains check. Just use the 'mse' variable directly.

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #14 - Posted 2013-09-10 07:48:50 »

It's updated in my input class only when the mouse moves. It's not being constantly set.

1  
2  
3  
4  
5  
6  
7  
8  
9  
   public void mouseMoved(MouseEvent e) {
      if (game.state == 1) {
         butt.mse.x = e.getX();
         butt.mse.y = e.getY();
      } else if (game.state == 0) {

      }
   }
}

Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #15 - Posted 2013-09-10 11:40:01 »

Oh wow, that was a huge mess-up.
I wasn't modifying it, I thought I was.

I got everthing down, now I just need the detection going.

Here's the current code I have. It's not working.

1  
2  
3  
4  
   if (butt.contains(Button.mse)) {
      Button.button = Art.b2;
      System.out.println("Woohoo!");
   }

*Note, I moved the detection to the input class.

Offline CodeHead

JGO Knight


Medals: 41


From rags to riches...to rags.


« Reply #16 - Posted 2013-09-10 14:16:28 »

Why are you having "butt" do the bounds checking, and why are you suddenly referencing the member variables of your button class as if they're static? Assuming "butt" is a globally referenced object (it's hard to tell because your posted code doesn't seem to contain all the important bits), shouldn't the code be more along the lines of:

1  
2  
3  
4  
5  
6  
public void tick() {
    if (butt.contains(mse)) {
        button = Art.b2;
        System.out.println("Woohoo!");
    }
}


This would still appear to be incorrect since "butt" would have to have it's bounds altered in creative ways each time it wanted to do a contains check with a control. In this scenario, you really want the button to determine whether the mouse point is currently inside of it instead of the input class being responsible for the contains check (like your earlier code had it):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public class Button extends Rectangle { 
   public Point mse = new Point(0, 0);
   BufferedImage button;
 
   /* ... SNIP ... */
   
   public void tick() {
      if (contains(butt.mse)) {
         button = Art.b2;
         System.out.println("Woohoo!");
      }
   }
}


Posting your input class would probably help to net some better answers.

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #17 - Posted 2013-09-10 18:14:22 »

It extends rectangle, and the contains method isn't static.

Online BurntPizza
« Reply #18 - Posted 2013-09-10 18:53:05 »

Is tick() getting called? That's the next thing to check if that code isn't running.


Really, I think you should use the model that most gui systems use (including Swing names here, as you are probably familiar with them):

Component/Container - If you make the distinction, Container is a Component that can have child Components. Or you can just make all Components able to have children.

Components implement EventListeners - the EventListener methods do the handling of events

If there is a tick() or render() method on Component, it will call tick() or render() on all its children, and so on until the the whole scene graph is updated/rendered.


Might take a half hour to setup, and another to transfer, but I think you will have less headaches later, esp. if you go much further than buttons.
Offline CodeHead

JGO Knight


Medals: 41


From rags to riches...to rags.


« Reply #19 - Posted 2013-09-10 19:02:51 »

It extends rectangle, and the contains method isn't static.

I'm assuming we're talking about your input handler. The "static" comment was referring to this part of your code:

1  
if (butt.contains(Button.mse))


"mse" would have to be a static member of the Button class for the above to make sense. Ideally, your Button class would look something like:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
public class Button extends Rectangle {
    public static final long serialVersionUID = 1L;
    BufferedImage button;

    public Button(String msg, int x, int y) {
        setBounds(x, y, Art.b1.getWidth(), Art.b1.getHeight());
        System.out.println(getBounds());
        button = Art.b1;
        String mval = msg;
    }

    public render(Graphics g) {
        g.drawImage(button, x, y, null);
        Fonts.drawString(mval, x + 20, y + 20);
    }

    public boolean tick(Point mse) {
        if (contains(mse)) {
            // Change to the hovered
            button = Art.b2;
            System.out.println("Woohoo!");
            return true;
        }
        button = Art.b1;
        return false;
    }
}

Then your input handlers mouse move event would look something like this:

1  
2  
3  
4  
5  
6  
7  
8  
public void mouseMoved(MouseEvent e) {
    if (game.state == 1) {
        // Get a reference to your button here...we'll call it theButton in this case.
        theButton.tick(e.getPoint());
    } else if (game.state == 0) {
        // Do something else...
    }
}


The boolean on the tick event can be omitted if you're only using one button. If you're using more, then it becomes useful when iterating over multiple button objects (as in Slyth2727's scenario) to determine if the event has been processed by a particular button thus ending the iteration loop.

BurntPizza's recommendations are also solid and pretty much how my GUI controls are implemented as well. It adds a bit of complexity in the short term, but makes things far easier in the long term. Delving into the source for Java's Component class may also provide some enlightenment/ideas for how to implement your controls.

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Offline 65K
« Reply #20 - Posted 2013-09-10 20:54:00 »

For better design and flexibility, a UI button should not inherit from a rectangle class, but use it.
A button is not a rectangle but can have the shape of a rectangle.

Offline kpars

JGO Wizard


Medals: 91
Projects: 4
Exp: 3 years


Extreme Typist.


« Reply #21 - Posted 2013-09-11 00:01:15 »

Alright, I got that down.

The detection still won't work.

Also, I feel like the tick method should constantly be running. If I only use it when the mouse is moved, there can be a delay so the coordinates aren't exact.

Offline Slyth2727
« Reply #22 - Posted 2013-09-11 00:35:33 »

The tick method should definitely be constantly checked. However if you have a million buttons (which I have a hard time imagining why you would but still) that will be bad. What I had was a Gui class which basically held and array of all of that gui's buttons. Then in my main class I had a Gui displayedGui that, in the update loop, called displayedGui.drawGui() which drew and updated (tick()) the buttons.

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
Offline philfrei
« Reply #23 - Posted 2013-09-11 00:36:57 »

Here's what I did for my game, though I used a polygon (hexagonal) rather than a rectangle.

1) put a Rectangle variable in your Button object. No need to extend the Rectangle class. Instantiate the Rectangle in terms relative to the X, Y location of the button on the screen, e.g.:
1  
   Rectangle rectangle = new Rectangle(xLoc, yLoc, width, height);


2) put a "contains(Point p)" method in your Button object.
1  
2  
3  
4  
5  
   public boolean contains(Point point)
   {
      if (rectangle.contains(point)) return true;
      return false;
   }


3) put a "hover" boolean in your Button object. I'd probably make this instance variable 'volatile'.

4) have your MouseMotionListener include the following code:
1  
2  
3  
4  
   public void mouseMoved(MouseEvent arg0) 
   {
      button.setHover(button.contains(arg0.getPoint());
   }

You may have to do same for mouseDragged(). This should keep the state of the button current.

5) have the update() or render() method for the button look at the "hover" boolean before deciding what to do or draw.

Maybe a setup like the above will work for your game.

"It's after the end of the world! Don't you know that yet?"
Offline StumpyStrust
« Reply #24 - Posted 2013-09-11 05:38:19 »

Hey. I did a whole UI system I did in java2D if you want to look. Here is a just the button class.

http://www.java-gaming.org/?action=pastebin&id=709

Stop writing code for a second and think of what a button needs.

Is the button active? can it test for events?

Is the mouse over the button?

Is the mouse pressed?

Is the mouse released when it is still over the button?

How do we know when the mouse is over the button?

You probably already thought of these but now think of how you will code them. Once you have an idea, hop to it and make some buttons.

Offline tdegroot96

Junior Duke


Projects: 1



« Reply #25 - Posted 2013-09-12 15:00:06 »

1  
2  
3  
4  
5  
Rectangle rect = new Rectangle(0, 0, 50, 50);

if (mx > rect.x && my > rect.y && mx < (rect.x + rect.width) && my < (rect.y + rect.height)) {
do stuff
}
Offline CodeHead

JGO Knight


Medals: 41


From rags to riches...to rags.


« Reply #26 - Posted 2013-09-12 18:50:34 »

1  
2  
3  
4  
5  
Rectangle rect = new Rectangle(0, 0, 50, 50);

if (mx > rect.x && my > rect.y && mx < (rect.x + rect.width) && my < (rect.y + rect.height)) {
    // do stuff
}


You do realize that your example re-invents the wheel. The Rectangle's contains method does pretty much the same thing.

1  
2  
3  
4  
5  
Rectangle rect = new Rectangle(0, 0, 50, 50);

if (rect.contains(mx, my) {
    // do stuff
}


Other than that, the checks should be ">=" and "<=" otherwise you miss intersections with the border pixels.

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (38 views)
2014-10-17 03:59:02

Norakomi (29 views)
2014-10-16 15:22:06

Norakomi (24 views)
2014-10-16 15:20:20

lcass (28 views)
2014-10-15 16:18:58

TehJavaDev (56 views)
2014-10-14 00:39:48

TehJavaDev (55 views)
2014-10-14 00:35:47

TehJavaDev (46 views)
2014-10-14 00:32:37

BurntPizza (64 views)
2014-10-11 23:24:42

BurntPizza (36 views)
2014-10-11 23:10:45

BurntPizza (78 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!