Making my GUI right

So, I’m building a GUI for my game from scratch and the further I’ve progressed, the harder it gets.

So far, I’ve used the following method:

I’ve got a button class, which represents a button. It can be hovered, clicked and rendered to the screen. My strategy has been to assign an integer to each button and when I click it, if it’s hovered, it returns this integer. I then use the integer in the parent class and perform actions in regards to it (like a switch statement with different methods, or assigning the index to arrays and such).


	private final int PLAY = 100;
	private final int SETTINGS = 101;
	private final int INFO = 102;
	private final int EXIT = 103;
	private final int SAVE = 104;
	private final int RESET = 105;
	private final int MAIN = 106;
	private final int SETTINGS2 = 107;
	private final int MESSAGE = 108;

… construct the buttons, passing a particular int from above. Once a mouse event occurs I then iterate through the buttons and get the code from that which was pressed. I then do something like:


		switch(code){
		case -1:
			break;
		case PLAY: exit(true);
			break;
		case SETTINGS: resetSetts(); pageNr = 1;
			break;
		case INFO:
			break;
		case EXIT: exit(false);
			break;
		case SAVE: uSure = false; saveSetts(); pageNr = 0;
			break;
		case RESET: uSure = false; resetSetts();
			break;
		case MAIN: pageNr = 0; resetSetts();
			break;
		case SETTINGS2:
			break;
		case MESSAGE: uSure = true;
		}

Now, to say the least, this is messy and I feel I can’t do the advanced stuff I want without confusing myself. I’ve now figured out another solution:


	button.addClickAction(new CLICK_ACTION() {
			@Override
			public void action() {
				exit(false);
			}
		});


This way I don’t need to keep track of all the integers and what they do, but the logic of the button is encapsulated in the button itself. My only question is whether this is good design?

E.g. Let’s say I have the gamecore - class. This class controls whether the game runs or not, obviously. Now, the gamecore is the root of the class hierarchy and imagine that at the end of the hierarchy three, there is a guiclass, which holds a button which is supposed to exit the game. With my new method, I’ll be able to call the exit method directly in that button, as in apposed to before when I had to return a particular int back to the core. But I feel like I’m violating something… I want to keep to a MVC model as much as I can. What are your thoughts on it?

If I understand you correctly, my advice would be to load all the possible actions/‘event ids’ into a hashmap<Integer, Button/ButtonEvent> and go through that everytime instead of a switch…

Just my ramblings ;D

Yes, I apologize for not being too clear. Been coding all day and a bit mushy in the head.

I get your meaning, but how can I map an integer to a method? I haven’t used hashmaps at all, but from what I know they map a key to a value. Can the value be a function that is called?

Anyway, I would very much like to move away from integers all togeather and use my CLICK_ACTION interface, which lets me specify which fucntion/action to take in the construction phase. However, my main concern is the hierarchy. Before, all my communication was

PARENT calls methods in ->CHILD-> that calls methods in GRANDCHILD.

If the grandchild had to say something to the PARENT, it had to convey this as a return value. So, if the GRANDCHILD had an exit-button and the button was clicked, it returned the code of the button to the PARENT when the click()-method was called.

Now I can let the GRANDCHILD-button call methods in the PARENT directly, yielding a circle in communication, and that’s not good, or is it? That is basically my question…

Essentially what you’re talking about is a scene graph. Your “another solution” that uses callbacks is the way I approach GUI interaction in my applications. It has its disadvantages, but it’s a fairly sane approach. You’re still in good shape in regards to the MVC pattern if you consider your visual element as your view and your callback as your controller. At worst you’ve created a loose coupling.

When it comes to games, if it works for you and you can grep what’s going on, it’s good enough. It’s a far different beast than writing libraries for others or “mission critical” systems. :wink:

Can I just ask you, if you got the hierarchy:

PARENT -> CHILD -> GRANDCHILD -> BUTTON

And you need the BUTTON to call a function in the PARENT. Do you do like me:

PARENT has a nested class, which holds the methods that the button will need, e.g.


class PARENT{

//parent code

class CONTROLLER{

public void stopGame(){
//stops the game. 
}
}
}


Then, in the constructing phase, the PARENT creates the CHILD, sending a CONTROLLER as a parameter. The CHILD passes the CONTROLLER along to the GRANDCHILD and finally, the button is created.



button.addClickAction(
new CLICK_ACTION{ void action(){PARENT.CONTROLLER.stopGame();  }}
);


Sorry about the late reply. It was the wife’s birthday this weekend, so I didn’t have much of a chance to get online.

My controls all inherit off of a “BaseControl” class that holds common information/functionality that all controls need. In cases where a control needs special functionality, I just add the new methods/variables into a class that inherits from the base control without any sort of nested class. The “BaseControl” class contains a reference to a parent “BaseControl”, so in your scenario, my approach is as follows:

  1. The input event is routed down the graph and dispatched to the appropriate control.
  2. From the control’s handler for the event, I reference the “parent” variable. If I need a “grandparent”, “great grandparent”, etc, I can keep calling the get parent method on the returned reference to walk up the graph.
  3. The parent (or grandparent) can then be cast to a specific control class allowing the handler to call the methods of the parent class directly.

The downside to this is that you have to be aware of where a control is in your tree structure or do some extra checking when walking the tree. In practice, I have some helper methods in the base control class that allow me to reference controls by name, so if I need a specific ancestor control, I can grab a direct reference to it without much hassle.

For an apples to apples comparison, my method to accomplish the task that your code does would look like the following:


MyControl.addExtendedInputListener(new ExtendedInputListener() {
    @Override
    public void mouseClicked(int button, int x, int y, int clickCount) {
	// getParent called multiple times to get to the appropriate level.
        ((SpecificClass)MyControl.getParent().getParent().getParent()).stopGame();
    }
});

There’s nothing inherently wrong with your approach, it’s just different than the way I chose to tackle the issue. In certain scenarios, your approach has advantages over mine, and vice versa. I would say keep going with the way you’ve been doing it and don’t worry too much about the “circle of communication” issue. I can’t think of a sane scenario where it would present any sort of real hurdle. :slight_smile:

Much obliged!