Making A Slider Component Problem

If I understand the issue you’re having correctly, then try changing this line (line 114 from my previous code post):


this.value = Math.round(this.percentage * 100);

To:


this.value = this.minValue + Math.round((this.maxValue - this.MinValue)*percentage);

The will ensure that the values returned are between the min and max values that you set.

If I misunderstood the problem, let me know and we can have another crack at it. :slight_smile:

There it is, that’s the right way to compute, you made it :). It was so simple, that I forgot the basic math…

I just made a little change, in order to get the correct percentage between 0.0-100.0%, not 0.0-1.0.

this.percentage = (float) (mxRelative / this.lineWidth) * 100;
this.value = this.minValue + Math.round((this.maxValue - this.minValue) * percentage) / 100; 

So that I don’t have to multiply in the getPercentage method, I think that’s better. Anyway, thanks!

    public float getPercentage() {
        return Float.parseFloat(decimalFormat.format(percentage));
    }

p.s. This will be a nice resource for those who want to make a nice basic slider component.

Phew, glad I understood correctly. LOL I was about to break the test version from yesterday to see what I’d missed if I didn’t. I’m just happy that you’re back on track again.

Indeed. Between the back and forth of working out what was going on, and the code provided by you and ctomni, there are a lot of good ideas. I think that the interesting question rightfully earns you your first medal. Don’t go spending it all in one place now. :wink:

Have a great one. ;D

Hi again, I was adding a new feature, so it has some connections with slider.
I assume that you have tried already TextField component that comes together with Slick2D. However, I want to share value between TextField & Slider, which means that for a value which is shown in TextField, also and Slider should have, or vice verse.

So far I have only one problem with a slider, to compute tempSliderBoxX variable based on a newValue.


        if (this.newValue != this.value) {
            float tempSliderBoxX = 0;

            if (tempSliderBoxX >= 0 && tempSliderBoxX <= this.lineWidth) {
                if (this.newValue > this.maxValue) {
                    this.newValue = this.maxValue;
                    this.value = this.newValue;
                    this.percentage = 100.0f;
                    this.sliderBoxX = this.lineX + this.lineWidth + Math.round(this.sliderBoxWidth / 2);
                }
                else if (this.newValue < this.minValue) {
                    this.newValue = this.minValue;
                    this.value = this.newValue;
                    this.percentage = 0.0f;
                    this.sliderBoxX = this.lineX - Math.round(this.sliderBoxWidth / 2);
                } 
                else {
                    this.value = this.newValue;
                    this.percentage = (float) (tempSliderBoxX / this.lineWidth) * 100;
                    this.sliderBoxX = tempSliderBoxX;
                } 
            }
        }

And a second problem is about, to re-write (inside a textfield) the value after calling the method setValue().
Right now, I can get a value from the slider and use setText method on the textfield component, in order to show current slider value, and it well performs actions.
But the problem is, when we set that value to text field from a slider, it blocks me to re-write again some value in the textfield.
I can only move the cursor position with left & right arrows or backspace or delete button, but not and to remove characters from it and then write.
So I’m not sure if I’m missing some additional conditions for this or the problem is order of performing the actions.

    @Override
    public void update(GameContainer gc, StateBasedGame sg, int delta) throws SlickException {
        Input input = gc.getInput();
        int mx = input.getMouseX();
        int my = input.getMouseY();

        setupTable.setTableStake((String) tableStakesCB.getSelectedItem());
        setupTable.setGameSpeed((String) gameSpeedCB.getSelectedItem());
        setupTable.setTableTheme((String) tableThemeCB.getSelectedItem());
       
        if (!this.hasFocus) return;

        float minValue = 500;
        float maxValue = 1000;
        // sets min & max values to slider component
        tempSlider.setInitialValues(minValue, maxValue);
        // performs actions
        tempSlider.performAction(gc, mx, my);

        // sets a slider value on the text field
        tempField.setText(String.valueOf(tempSlider.getValue()));
        System.out.println("Text field: " + tempField.getText() + " \t Slider: " + tempSlider.getValue());
        
        tableStakesCB.performAction(gc, mx, my);
        gameSpeedCB.performAction(gc, mx, my);
        tableThemeCB.performAction(gc, mx, my);
    }

        @Override
    public void componentActivated(AbstractComponent source) {
        if (!this.hasFocus) return;
        
        if (source == nameField) {
            setupTable.setPlayerName(nameField.getText());
        }
        if (source == totalPlayersField) {
            setupTable.setTotalPlayers(totalPlayersField.getText());
        }
        if (source == tempField) {
            if (tempField.getText() != null && tempField.getText().matches("[0-9]+")) {
                tempSlider.setValue(Float.parseFloat(tempField.getText()));
            }
        }
    }


I apologize for bad english, so please tell me if something was not clear.

From the looks of what you posted, I can see a couple of potential problems. “newValue” shouldn’t be a member of your Slider class. It should only exist within the scope of a setter function. You’re also making things a bit more complex than they need to be. The following function should do what you need. I don’t have the test harness around at the moment, so I haven’t had a chance to test it, but it should work (faulty hardware aside).:wink:


public void setValue(float newValue) {
	if(this.value != newValue) {
		float multiplier;
		this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);
		multiplier = (this.value/this.maxValue); 
		this.percentage = multiplier * 100.0f;
		this.sliderBoxX = Math.round(this.lineX + (this.lineWidth * multiplier) - (this.sliderBoxWidth/2));
		// sets a slider value on the text field
		tempField.setText(String.valueOf(getValue()));
	}
}

Then just replace any calls to “this.value = …” with a call to “this.setValue(…)”. and move your “tempField.setText(String.valueOf(tempSlider.getValue()));” call out of the update method. Your values will be guaranteed to always be between minValue and maxValue, your slider box position will only be calculated when needed, and your text box value will only be changed when the value of the slider changes.

Now you’ll need to add a key listener to your text box that will cast the String value of the text box to a float value and call your PSlider’s “setValue(…)” function when the enter key is pressed. This keeps the slider value from changing before the user is finished typing in a value. If you want to get fancy, filter the key input, and only append the key values to the text box’s value if the key typed is between 0 and 9. Doing it this way has the added benefit of setting the value of the text box to a valid value if the entered value is outside of the sliders minValue/maxValue range (remember that "setValue(…) takes care of this for us).

Theoretically this should work, but as the old saying goes: “In theory, there is no difference between theory and practice; in practice, there is”.:slight_smile: Let me know if you have any questions or if this isn’t making sense and I’ll try to get another test harness built so I can quit theorizing and start practicing.:wink:

Definitely agree with your idea after I read your code, that a newValue should not be part of the class PSlider.
But the 9 line in your code, which I don’t understand, how I’m going to use the instance tempField,
as it’s not the member of the PSlider class?

Hmmm, I must have misread your code. I was assuming the second code snippet you posted was part of the same class as the first code snippet. Can you post a bit of information on what the class that the second snippet of code is from does/is? I’m thinking it’s probably a game manager class?

Off the top of my head, one way to do this would be to create a custom “slider listener” class which could be used to perform the updates outside of the actual controls.

First define a new interface in your program:


// Define a new interface...
interface PSliderListener {
	public void valueUpdated(float newValue);
}

Now add a way for a PSlider to keep track of any interested listeners:


public class PSlider extends PAbstractComponent {
	// Keep track of all subscribed listeners in an array list.
	private ArrayList<PSliderListener> Listeners = new ArrayList<PSliderListener>(0);
	
	// Snip...

	// Function to add listeners...
	public void addPSliderListener(PSliderListener psl) {
		// Don't add the same listener multiple times.
		if(!Listeners.contains(psl)) {
			Listeners.add(psl);
		}
	}

	// Function to remove listeners...
	public void removePSliderListener(PSliderListener psl) {
		// Don't remove non-existant listeners.
		if(Listeners.contains(psl)) {
			Listeners.remove(psl);
		}
	}

	// Tweak the existing setValue function to notify the listeners when the value is updated.
	public void setValue(float newValue) {
		if(this.value != newValue) {
			float multiplier;
			this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);
			multiplier = (this.value/this.maxValue); 
			this.percentage = multiplier * 100.0f;
			this.sliderBoxX = Math.round(this.lineX + (this.lineWidth * multiplier) - (this.sliderBoxWidth/2));
			// Notify all listeners that the value of the PSlider has changed.
			for(PSliderListener psl : Listeners) {
				psl.valueUpdated(this.Value);
			}
		}
	}
}

Now you’ll have to define a PSliderListener somewhere in your code that shares scope with the TextBox component (I’ll just stick with the name “tempField” since I’m not sure what your actual control name is):


TextField tempField = ...;

PSliderListener valueListener = new PSliderListener() {
	@Override
	public void valueUpdated(float newValue) {
		tempField.setText(String.valueOf(newValue()));
	}
};

And finally add your listener to the PSlider (I’ll refer to the slider as “tempSlider” since, again, I’m not sure of the actual control name):


tempSlider.addPSliderListener(valueListener);

Doing it this way removes the “hard link” between controls and adds flexibility. You could for instance update multiple controls by sticking the needed code all within the same listener, or you could add a different listener for each control to be updated. A similar approach could be taken with the TextField as well. One thing you want to try and avoid is hard coded dependencies between your components.

Again, the above is off the top of my head and makes a lot of assumptions about how your application is structured at one level above the controls so let me know if something isn’t clear or if there is a reason you can think of which might prevent you from taking that approach. If so, we can look at the problem from a different angle.:slight_smile:

Sorry for late response, I was doing some other work.
I was afraid that you misunderstood me, my english…
But anyway, this is how the things are.

The first snippet, is written in actionPerform method at the end, and that method is inside PSlider class.


    public void performAction(GameContainer gc, int mx, int my) throws SlickException {
        Input input = gc.getInput();

        this.sliderBoxWidth = Math.round(this.height / 2);
        this.sliderBoxHeight = Math.round(this.height / 2);
        this.sliderBoxY = Math.round(this.y + ((this.y + this.height) - this.y) / 2
                                 - (this.sliderBoxHeight / 2));
        
        this.lineWidth = Math.round(this.width - this.sliderBoxWidth);
        this.lineHeight = 1;
        this.lineX = Math.round(this.x + (this.sliderBoxWidth / 2));
        this.lineY = Math.round(this.y + ((this.y + this.height) - this.y) / 2);
        
        if (this.sliderBoxX < this.lineX - Math.round(this.sliderBoxWidth / 2)) {
            this.sliderBoxX = this.lineX - Math.round(this.sliderBoxWidth / 2);
            
            if (this.value != this.minValue) {
                this.value = this.minValue;
                this.newValue = this.value;
            }
        } 
        else if (this.sliderBoxX > this.lineX + this.lineWidth + Math.round(this.sliderBoxWidth / 2)) {
            this.sliderBoxX = this.lineX + this.lineWidth + Math.round(this.sliderBoxWidth / 2);
            
            if (this.value != this.maxValue) {
                this.value = this.maxValue;
                this.newValue = this.value;
            }
        }
        
        float mxRelative = mx - this.lineX;
        
        if (my >= this.y && my <= this.y + this.height) {
            if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)) {
                if ((mxRelative >= 0) && (mxRelative <= this.lineWidth)) {
                    this.percentage = (float) (mxRelative / this.lineWidth) * 100;
                    this.value = this.minValue + ((this.maxValue - this.minValue) * percentage) / 100;
                    this.sliderBoxX = mxRelative + this.lineX - Math.round(sliderBoxWidth / 2);
                    
                    this.newValue = this.value;
                }
            }
        }
        
        float minSliderBoxX = this.sliderBoxX;
        float minSliderBoxY = this.sliderBoxY;
        float maxSliderBoxX = this.sliderBoxX + this.sliderBoxWidth;
        float maxSliderBoxY = this.sliderBoxY + this.sliderBoxHeight;
        if ((mx > minSliderBoxX && mx < maxSliderBoxX) && (my > minSliderBoxY && my < maxSliderBoxY)) {
            if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
                wasSliderBoxDown = true;
            }
        }

        if (wasSliderBoxDown) {
            if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
                if (mxRelative >= 0 && mxRelative <= this.lineWidth) {
                    this.percentage = (float) (mxRelative / this.lineWidth) * 100;
                    this.value = this.minValue + ((this.maxValue - this.minValue) * percentage) / 100;
                    this.sliderBoxX = mxRelative + this.lineX - Math.round(sliderBoxWidth / 2);
                    
                    this.newValue = this.value;
                }
            } else {
                wasSliderBoxDown = false;
            }
        }

        
        if (this.newValue != this.value) {
            float tempSliderBoxX = 0;

            if (tempSliderBoxX >= 0 && tempSliderBoxX <= this.lineWidth) {
                if (this.newValue > this.maxValue) {
                    this.newValue = this.maxValue;
                    this.value = this.newValue;
                    this.percentage = 100.0f;
                    this.sliderBoxX = this.lineX + this.lineWidth + Math.round(this.sliderBoxWidth / 2);
                }
                else if (this.newValue < this.minValue) {
                    this.newValue = this.minValue;
                    this.value = this.newValue;
                    this.percentage = 0.0f;
                    this.sliderBoxX = this.lineX - Math.round(this.sliderBoxWidth / 2);
                } 
                else {
                    this.value = this.newValue;
                    this.percentage = (float) (tempSliderBoxX / this.lineWidth) * 100;
                    this.sliderBoxX = tempSliderBoxX;
                } 
            }
        }
    }

Second snippet, the method update, is part of the state class which extends BasicGameState. The class contains update, render, init methods…


    @Override
    public void update(GameContainer gc, StateBasedGame sg, int delta) throws SlickException {
        Input input = gc.getInput();
        int mx = input.getMouseX();
        int my = input.getMouseY();

        setupTable.setTableStake((String) tableStakesCB.getSelectedItem());
        setupTable.setGameSpeed((String) gameSpeedCB.getSelectedItem());
        setupTable.setTableTheme((String) tableThemeCB.getSelectedItem());
       
        if (!this.hasFocus) return;

        float minValue = 500;
        float maxValue = 1000;
        // sets min & max values to slider component
        tempSlider.setInitialValues(minValue, maxValue);
        // performs actions
        tempSlider.performAction(gc, mx, my);

        // sets a slider value on the text field, if enter is pressed
        tempField.setText(String.valueOf(tempSlider.getValue()));
        System.out.println("Text field: " + tempField.getText() + " \t Slider: " + tempSlider.getValue());
        
        tableStakesCB.performAction(gc, mx, my);
        gameSpeedCB.performAction(gc, mx, my);
        tableThemeCB.performAction(gc, mx, my);
    }

One of the problems, which I was worried, when I was about to start to create these components, was listener.
I am familiar with it, and I had the opportunity to use an anonymous class listener, back when I made my first Swing project, but the problem is that I hadn’t the opportunity to create the functionality to interface on the simpler examples, that will produce the listener system for the component.
So my idea was that (and since this is my first slick2d project), to make the simple components with out listener interfaces, which will use the basic functions update / render, literally acting as an entity, and I succeeded in that.
The only component that I have not still made, is a TextField, but I hope to the already existing one from Slick2D, that I will be able to do something with it.
So I can finally go to the most fun part, which is to create a game logic, which I have already had made, but as a console game.

Your English is better than a lot of native English speakers I know.:wink:

I’ll be honest; trying to get this to work via game states is a little bit of a challenge, but after your explanation of how the previous code fit into the grand scheme of things, I think I may have a serviceable solution.


public class YourStateClass extends BasicGameState {    

	// Snip ...

	@Override
	public void update(GameContainer gc, StateBasedGame sg, int delta) throws SlickException {
		Input input = gc.getInput();
		int mx = input.getMouseX();
		int my = input.getMouseY();
	
		setupTable.setTableStake((String) tableStakesCB.getSelectedItem());
		setupTable.setGameSpeed((String) gameSpeedCB.getSelectedItem());
		setupTable.setTableTheme((String) tableThemeCB.getSelectedItem());
	       
		if (!this.hasFocus) return;
	
		float minValue = 500;
		float maxValue = 1000;
		// sets min & max values to slider component
		tempSlider.setInitialValues(minValue, maxValue);
		// performs actions
		tempSlider.performAction(gc, mx, my);
	
		// sets a slider value on the text field, if the TextField doesn't have the focus.
		if(tempField.hasFocus()) {
			try {
				tempSlider.setValue(Float.valueOf(tempField.getText().trim()));
			}
			catch(NumberFormatException(nfe) {
				tempSlider.setValue(0.0f);
			}
		}
		else {
			tempField.setValue(String.valueOf(tempSlider.getValue()));
		}

		tableStakesCB.performAction(gc, mx, my);
		gameSpeedCB.performAction(gc, mx, my);
		tableThemeCB.performAction(gc, mx, my);
	}
}

The above change to your code basically checks to see if the TextField currently has the focus. If it does, then the PSlider gets it’s value updated to whatever is in the text field. I’ve wrapped the call to setValue(…) in a try catch block to account for any possible NumberFormatExceptions that would be thrown if an un-parsable value was entered in the TextField, but I’d still advise you to filter the input. The catch block will simply cause the PSlider to be set to its minValue. If the TextField doesn’t have the focus, its value will be set to the PSlider’s current value. The only possible snag I can think of would be if Slick doesn’t automatically set the focus to the TextField when the mouse is clicked on it, but I’m assuming that it should…I’m just hoping that if the TextField gets focus it doesn’t suddenly cause the “if (!this.hasFocus) return;” check to fail. You will have to let me know if this works or not. I haven’t worked with Slick’s controls so I’m not completely sure of how they function within a BasicGameState object.

I hope it works for your needs. I’m in the process of rolling my own TextBox/TextArea controls, and they can get pretty complex depending on the functionality you want to implement. They’re taking a lot longer than any other control I’ve implemented, and I still have to figure out how to handle cursor positioning with mouse input efficiently along with debugging the scroll bar implementation that it uses.:o I’m afraid that figuratively, I have many “miles to go before I sleep”.8)

Here’s hoping that the above gets you closer to “the most fun part”.;D

Edit: I put together a quick StateBasedGame so I could experiment with the BasicGameState and the TextField. After looking over your code again, I realized that “this.hasFocus” must refer to a variable that you’ve defined within your BasicGameState which means that you don’t have to worry about invalidating the check when the TextField gets focus. On the “bad news” side, it doesn’t appear that there is a direct way to filter the input to the TextField, but since the try/catch block handles any invalid input, you should be fine.:smiley:

[quote]I’m just hoping that if the TextField gets focus it doesn’t suddenly cause the “if (!this.hasFocus) return;” check to fail.
[/quote]
Don’t worry. :slight_smile:
I should rename hasFocus into something else.
Anyway, the idea was to block the other components in updating, if any window, for example dialog, pops up.

public abstract class PAbstractState extends BasicGameState {

    protected boolean hasFocus;
    
    protected PAbstractState() {
        this.hasFocus = true;
    }

    public boolean hasFocus() {
        return hasFocus;
    }

    public void enableFocus() {
        this.hasFocus = true;
    }
    
    public void disableFocus() {
        this.hasFocus = false;
    }
    
}

So, function works like pause/unpause. I just set “this” which points to PAbstractState, as a argument to the component method,
for components like a Dialog, in my case for now it’s only PDialog.
So it’s something like this,

String s = JOptionPane.showConfirmDialog(this, "", "", );

But instead of static calling, I’m using the instance of the PDialog…
And simply, when some action occurs, dialog pops up, the method is activated and changes stance of the hasFocus variable for this state…

Anyway, let’s back on the topic.
It seems that it is working. I tested quickly, unfortunately I do not have much time to play with programming now,
but the reason why I’m saying “seems”,
for a min/max value 0/1000 SliderBox X coordinate, moves ok,
but for 500/1000, SliderBox for a min value starts from the center of the slider line, instead at the minX or start X of the slider line.
What is really interesting with this, no matter how it starts from the center of the line,
it still moves (computing)properly for that half line width, until 1000 or a maxX of the line. :smiley:

However, I will leave for tomorrow, this testing, don’t hate me :D, because I have to go tonight to watch a Hobit movie :),
but tommorow I will do test, and try to figure out.
So I will inform you tomorrow, what I assume that cause this.

There’s nothing to test, the problem is in the computation for box, since multiplier returns correct value, 0.5 for 500.

    public void setValue(float newValue) {
        if (this.value != newValue) {
            float multiplier;         
            this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);     
            multiplier = (this.value / this.maxValue);
            this.percentage = multiplier * 100.0f;  
            this.sliderBoxX = this.lineX + (this.lineWidth * ((this.value / (this.maxValue - this.minValue)))) 
                             - Math.round(sliderBoxWidth / 2)
                             - this.lineWidth;
        }
    }

I’m not sure is this correct way to compute slideboxx, but slider box does move now properly.

EDIT:
Just kidding, now it does not compute for case where we have for a minValue/maxValue 0/1000, but works for 500/1000…

It sounds like the line position and width variables might not be set correctly whenthe setValue(…) function is called. ??? Try changing the function to the following"


public void setValue(float newValue) {
   if(this.value != newValue) {
      float multiplier;
      
      System.out.println("Values before recalculation: sliderBoxWidth=" + this.sliderBoxWidth + ", lineWidth=" + this.lineWidth + ", lineX=" + this.lineX);

      // Make sure that these variables are set to the correct value before computing the handle position.
      this.sliderBoxWidth = Math.round(this.height / 2);
      this.lineWidth = Math.round(this.width - this.sliderBoxWidth);
      this.lineX = Math.round(this.x + (this.sliderBoxWidth / 2));
      
      System.out.println("Values after recalculation: sliderBoxWidth=" + this.sliderBoxWidth + ", lineWidth=" + this.lineWidth + ", lineX=" + this.lineX);

      this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);
      multiplier = (this.value/this.maxValue); 
      this.percentage = multiplier * 100.0f;
      this.sliderBoxX = Math.round(this.lineX + (this.lineWidth * multiplier) - (this.sliderBoxWidth/2));
      // sets a slider value on the text field
      tempField.setText(String.valueOf(getValue()));
   }
}

This should dump the values to the console so they can be compared.

Values before recalculation: sliderBoxWidth=13.0, lineWidth=192.0, lineX=262.0
Values after recalculation: sliderBoxWidth=13.0, lineWidth=192.0, lineX=262.0

I could here set the condition before initializing sliderBoxX variable, so if minValue is 0, then subtract sliderBox for lineWidth, else, don’t subtract that lineWidth.
But I think this is dirty way…

Hmm, give me a bit of time to get the test harness set up again, and I will see if I can see what’s going on with the positioning. :smiley:

K, I will be here.

EDIT:

This was the idea.
Now, it works for both cases:


    public void setValue(float newValue) {
        if (this.value != newValue) {
            float multiplier;         
            this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);     
            multiplier = (this.value / this.maxValue);
            this.percentage = multiplier * 100.0f;  
            float sBoxX = this.lineX + (this.lineWidth * ((this.value / Math.abs(this.maxValue - this.minValue)))) 
                                     - Math.round(sliderBoxWidth / 2);
            if (this.minValue != 0) {
                sBoxX = sBoxX - this.lineWidth;
            } 
            this.sliderBoxX = sBoxX;
//            this.sliderBoxX = this.lineX + (this.lineWidth * ((this.value / Math.abs(this.maxValue - this.minValue)))) 
//                             - Math.round(sliderBoxWidth / 2)
//                             - this.lineWidth;
        }
    }

But don’t you think it’s dirty…? :slight_smile:
I believe, now you can maybe see where’s the problem.

Sorry I took a little bit to get back to you. I was getting ready to head out the door to work when I posted my last reply.

Yeah, the problem was an elementary mistake on my end. ::slight_smile: Try changing your “setValue(…)” method to the following and let me know if it helps.


public void setValue(float newValue) {
        if (this.value != newValue) {
            float multiplier;         
            this.value = Math.min(Math.max(this.minValue, newValue), this.maxValue);     
            multiplier = (this.value-this.MinValue)/(this.maxValue-this.minValue);
            this.percentage = multiplier * 100.0f;
            this.sliderBoxX = Math.round(this.lineX + (this.lineWidth * multiplier) - (this.sliderBoxWidth/2));
        }
}

Yep, that works.

This is what I did, when I was trying,


multiplier = (this.value- (this.maxValue / this.minValue));

but, I forgot to subtract and minValue, so that’s why it didn’t want to work first time.

Thank once again!

That was one of those moments when I smacked myself in the head after I figured out the mistake. Glad to know it worked for you. Have a great one, my friend. 8)

Back when I used Slick2d and needed a simple ui I used this: https://code.google.com/p/slick-sui/ its clean(for the most part) and easy to edit to your liking.