Wednesday, October 21, 2009

The Matrix Reloaded


In the box color picker project (1st, 2nd, 3rd, 4th), I used a custom control where one might ordinarily use a matrix. At the time, I couldn't remember how to make a matrix. In looking through Hillegass, I found an example to follow.

Following Hillegass: drop a control with a cell (a button in my case) on the window, choose Embed Objects In -> Matrix from the Layout menu. Click on the edge of the button until you see the 'resizing' bar (or whatever its true name is). Then Option-drag until you get the desired number of buttons in each row and column.

Hooking up the matrix as an outlet of the controller seems impossible at first.



When I Control-drag from the Matrix controller on the nib to the matrix in the window, these light up depending on where I'm pointing:

• Button Cell
• Prototype Button Cell
• Content View

The Matrix never shows up! There must be a simple way to do this, but I don't see it. However, I finally found a trick. With the matrix selected, go to the Size Inspector and increase the size of one of its dimensions, say, width. This will give extra space to the right of the cells that you can use as the target for hooking up the outlet. Now resize till it's back to normal. Mission accomplished.

The other detail is assigning identifiers for the buttons. In IB, you can set the title (a string) or the tag (an int). But this is tedious for 25 of them, and one nice thing about a matrix is that we can resize it programmatically. That might be really useful. So, in awakeFromNib I assign letters to each button cell as the title using an NSString method. Also, I hooked up the controller class as the target of all the buttons. We go back to the matrix to find out who's calling.

A simple project for you to try would be to make a sliding tile puzzle. I'm going to go back and read about NSAnimation again sometime. I posted something a long time ago about it on this page of PyObjC stuff. What would be very cool is to animate the tiles sliding into the empty socket! Maybe there is some way I could add another view on top of the matrix and draw in there???

Here is the code for MatrixController.m


#import "MatrixController.h"

@implementation MatrixController

- (void)awakeFromNib {
NSLog(@"awakeFromNib m %@", m);
NSString *alpha = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSRange r;
int x,y,X,Y;
X = [m numberOfRows];
Y = [m numberOfColumns];
for (x = 0; x < X; x++) {
for (y = 0; y < Y; y++) {
r = NSMakeRange(x*Y + y, 1);
id obj = [m cellAtRow:x column:y];
[obj setTitle:[alpha substringWithRange:r]];
}
}
}

- (IBAction)matrixChanged:(id)sender {
NSLog(@"matrixChanged %@ %@",
m, sender);
NSLog(@"%@ %u %u",
[[sender selectedCell] title],
[sender selectedRow],
[sender selectedColumn]);
}


@end


Here is some sample output:


Matrix[3203:a0f] awakeFromNib m <NSMatrix: 0x144810>
Matrix[3203:a0f] matrixChanged <NSMatrix: 0x144810> <NSMatrix: 0x144810>
Matrix[3203:a0f] A 0 0
Matrix[3203:a0f] matrixChanged <NSMatrix: 0x144810> <NSMatrix: 0x144810>
Matrix[3203:a0f] Y 4 4