May 16

Gwt-Ext and Number Madness

Tag: Ext,Gwt,Java,Javascript,Programming,WebAbhijeet Maharana @ 11:52 pm

Gwt-Ext Number Madness screenshotThis is the 3rd form of my game Number madness. I had first written it using TurboC during the vacation after junior college. And then as a Firefox extension. Both are available in the projects section.

Using Gwt-Ext for writing something like this sounds a bit silly. But it did make me learn something new: button templates; thanks to gwtext+ and sjivan. I have described the program below in brief. You can download Eclipse project from the link at the end of this post.

An Ext button is made up of a table with 3 columns. All three columns have parts of the button sprite as their background image and the center TD holds a <button> element. You can see this template in Button.java above the setTemplate() method definition:

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

We can override this template to make the button look as we want it to. My modified template looks as shown below. There is only one extra CSS class for the table (see notes at end):

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap mybutton">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

This enables us to use CSS nesting to define x-btn-left, x-btn-center, x-btn-right and x-btn-text with the attributes we want while preventing the normal buttons from being affected. Thus we can use both Ext’s buttons and out custom buttons at the same time. I have defined them as:

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
.mybutton .x-btn-right {
	background: transparent url('button_right_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-left {
	background: transparent url('button_left_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-center {
	background: transparent url('button_06.png') repeat-x center; 
	height:150px;
	width:80px;
	text-align:center;
}
 
.mybutton .x-btn-text {
	line-height: 150px;
	font-family: Arial, Helvetica, sans-serif;
	font-size:60px;
	font-weight:bold;
}

I have used custom images that make up the button’s left, center and right components. I have also changed the appearance of the text displayed on the button.

Now that we have the buttons which make up the game board, lets take a brief look at the rest of the game. An integer array holds the numbers that map to each button on the board. This array is populated randomly at start. Although the board is 2D, I decided to use a 1D array as it turned out to be slightly simpler while populating the random numbers. So arr2D[i][j] becomes arr1D[i * numcols + j] where numcols is the number of columns in each row.

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
private void generateRandomNumbers()
{
	int i,j;
	int temp;
	boolean suitable;
	int total = numRows*numCols-1;
 
	for(i=0;i<=total;i++)
	{
		do
		{
			suitable = true;
			temp = (int) Math.round(Math.random() * total);
			for(j=0;j<i;j++)
			{
				if(numbers[j] == temp)
				{
					suitable = false;
					break;
				}
			}
		}while(!suitable);
 
		numbers[i] = temp;
	}
}

Once the array is ready, I set the Panel’s layout to TableLayout with 3 columns and call createGrid() to create buttons that make up the grid. Every button knows its (row,column) position and the blank square is made up of an invisible button.

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
private void createGrid()
{
	for(int i=0; i<numRows; ++i)
	{
		for(int j=0; j<numCols; ++j)
		{
			int index = i*numCols + j;
 
			String label = String.valueOf(numbers[i*numCols + j]);
			final Button btn = new Button(label);
			btn.setTemplate(buttonTemplate);
 
			// listener is an instance of SquareListener
			btn.addListener(listener);
 
			// every button keeps track of its row and column number
			final int finali = i, finalj=j;
			btn.addListener("render", new Function(){
				public void execute() {
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "row", finali);
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "col", finalj);
				}
			});
 
			// empty square = invisible button
			// maintain a class-level reference to the empty square
			if (numbers[index] == 0)
			{
				emptyButton = btn;
				btn.setVisible(false);
			}
 
			add(btn);
		}
	}
}

The button listener checks if the clicked button is adjacent to the empty square. If it is, it swaps numbers in the array and on the buttons. The invisible button is now made visible and clicked button becomes invisible. I have added a fade in and fade out effect. However, this is shaky and sometimes the button doesn’t fade in for too long. It does irritate a bit. After this, the endgame is checked i.e. if numbers in the array are in ascending order.

I have left out some code to keep the post short. You can download the complete project from Gwt-Ext.com or Rapidshare.

Note:

  1. Since our new template just has an extra CSS class, the whole template thing could be avoided by calling btn.setCls(“mybutton”). This was an after-thought when I was done playing with the template.
  2. When you change the template, keep the <button> element otherwise you will get an exception at load time
    1
    2
    3
    4
    5
    
    [ERROR] Unable to load module entry point class com.maharana.gwtextnumbermadness.client.MainModule (see associated exception for details)
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: btnEl has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeHandle(ModuleSpace.java:225)
    	...
  3. Also keep the x-btn-center CSS class name otherwise you will get an exception when the button is clicked
    1
    2
    3
    4
    5
    
    [WARN] Exception thrown into JavaScript
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: this.el.child("td.x-btn-center " + this.buttonSelector) has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:270)
    	...

References:

  1. Images for new button template: http://www.jankoatwarpspeed.com/post/2008/04/30/make-fancy-buttons-using-css-sliding-doors-technique.aspx
  2. CSS nesting: http://webdesignfromscratch.com/css-inheritance-cascade.cfm
  3. Centering block level elements: http://dorward.me.uk/www/centre/#content

Do let me know if you have any corrections or suggestions.

2 Responses to “Gwt-Ext and Number Madness”

  1. Mafer says:

    I have problems with the x-bnt-over class.. because I made my buttons with a diferent height(not the standard one). Witch css class do I have to override for the over??

  2. Abhijeet Maharana says:

    Hi Mafer, this should answer your query: http://gwt-ext.com/forum/viewtopic.php?f=7&t=1573

    Regards,
    Abhijeet.

Leave a Reply