0022: Building a Grid with a GTK… Grid

Taking the subject of the last blog post a bit further, we’re going to look at Labels again, but in another type of container, the Grid.

How many rows and/or columns are in a grid? It depends on how many cells you stuff in there. You don’t pre-define the number of rows and columns. Instead, the Grid redefines its layout as cells are added. Put a cell into position 0, 0 and you’ve got one row, one column. Follow this with another cell at position 0, 1 and you’ve got two rows, but still only one column. And you should be able to extrapolate from there… 1, 0 gives you two rows, two columns with cell 1, 1 empty, etc.

The Basic Grid

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

In this example, we stuff cells into the Grid “longhand” by defining each one and sticking it into a specific position within the Grid. I did this example this way because the second one—which pushes the cells in using a pair of for loops—gets a bit cryptic, not making it clear how cells within the Grid are numbered.

Let’s dive in, shall we?

A New Type of MainWindow

This time around, I dropped the TestRigWindow class and cut right to the chase, defining a GridWindow class derived from the MainWindow superclass. From there, it was just a matter of setting up a Grid, sticking things into each cell of the Grid, and then tossing that into the GridWindow. Easy.

And the cell stuffing was done, as mentioned earlier, by hand. Here are the first two rows:

// row 0
RedLabel zeroZero = new RedLabel("cell 0, 0");
grid.attach(zeroZero, 0, 0, 1, 1);
BlueLabel oneZero = new BlueLabel("cell 1, 0");
grid.attach(oneZero, 1, 0, 1, 1);
RedLabel twoZero = new RedLabel("cell 2, 0");
grid.attach(twoZero, 2, 0, 1, 1);
BlueLabel threeZero = new BlueLabel("cell 3, 0");
grid.attach(threeZero, 3, 0, 1, 1);

// row 1
BlueLabel zeroOne = new BlueLabel("cell 0, 1");
grid.attach(zeroOne, 0, 1, 1, 1);
RedLabel oneOne = new RedLabel("cell 1, 1");
grid.attach(oneOne, 1, 1, 1, 1);
BlueLabel twoOne = new BlueLabel("cell 2, 1");
grid.attach(twoOne, 2, 1, 1, 1);
RedLabel threeOne = new RedLabel("cell 3, 1");
grid.attach(threeOne, 3, 1, 1, 1);

And as I implied in the last post, we now have a BlueLabel as well as a RedLabel (shades of that whisky everyone raves about). Here’s the super-class they’re derived from:

class WideLabel : EventBox
{
	Label label;
	
	this(string text)
	{
			super();
			
			label = new Label(text);
			label.setSizeRequest(60, 60);
			add(label);
			
	} // this()
	
} // class WideLabel

I suppose I should have called it ColorLabel, but the code’s written now and I’m tired, so WideLabel it is. What sets this class apart from the RedLabel of yore (and made me think to call it Wide) is that I hard-coded the Label size. Rather than using extra space on either side of the text and blank lines above and below, I got all sophisticated and called setSizeRequest() to make all the Labels (and therefore the cells) a specific, uniform size.

The RedLabel looks very much the same as before—other than its size—and BlueLabel is the same except… well, it’s blue.

And don’t overlook the extra imports at the top of the file, some of which we used last time, too:

import gtk.Grid;
import gtk.EventBox;
import gtk.RGBA;
  • The Grid import is self-explanatory.
  • But the EventBox, which one might think would be imported from GDK rather than GTK, in fact, bucks the trend.
  • RGBA lets us define a colour, and
  • the comment below the import statements mentions that StateFlags are found in c.types.

Defining a Grid the Shorthand Way

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

Now let’s look at some of the bits and bobs in there. The results of all this code are the same as with our first example, but getting there via a different route. Here’s the constructor, which is the essence of things:

this()
{
	int x, y; // positions within the grid
	int xOddEven, yOddEven;
	string labelText;
	
	super(title);
	
	grid = new Grid();
	
	foreach(int x; 0..4)
	{
		foreach(int y; 0..4)
		{
			xOddEven = x % 2; // row # odd or even?
			yOddEven = y % 2; // column # odd or even?
			labelText = format("cell %d, %d", x, y);
			
			if((xOddEven == 0 && yOddEven == 0) || (xOddEven != 0 && yOddEven != 0 ))
			{
				RedLabel label = new RedLabel(labelText);
				labels ~= label; // add in scope
				grid.attach(label, x, y, 1, 1); // use in scope
			}
			else
			{
				BlueLabel label = new BlueLabel(labelText);
				labels ~= label;
				grid.attach(label, x, y, 1, 1);
			}
		}
	}

	add(grid);
	
} // this()

It’s a bit of a mind-bender to follow, but the long and short of it is:

  • where the row and column numbers are both odd or both even, squares are red (that’s the if statement)
  • where one is odd and the other even, squares are blue (that’s the else)
  • x = rows
  • y = columns

And, in case you’ve never come across the D-style foreach(), it’s kind of cool because you can replace for(int x; x < 4; x++) with foreach(int x; 0..4). It’s less typing and, IMO, rather elegant. You can still use the for() construct if you want, though, so it’s up to you which you pick.

And that wraps up another adventure in GtkD coding-land. Bye for now.

Comments? Questions? Observations?

Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.

You can also subscribe via RSS so you won't miss anything. Thank you very much for dropping by.

© Copyright 2023 Ron Tarrant