Reputation: 161
I'm trying to create a column of clickable URL-type text (NOT URLs like this, but essentially a borderless, title button or text field cell with a tracking area for a hover effect) within an NSTableView
.
1.) When the user hovers over a particular cell the text in that cell should draw an underline below the text (hover/trackable area effect).
2.) When the user clicks the text it should perform an action.
I've subclassed NSCell
and NSTableView
and added a tracking area within the custom tableview to try and track the mouse location of the individual cell of the table to notify the cell when to redraw itself. I can get the current row and column of the mouse location, but can't seem to get the right cell in my custom tableview's mouseMoved:
method
-(void)mouseMoved:(NSEvent *)theEvent {
[super mouseMoved:theEvent];
NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];
long column = [self columnAtPoint:p];
long row = [self rowAtPoint:p];
id cell = [[self.tableColumns objectAtIndex:column] dataCellForRow:row];
}
It gets the cell for the column, but doesn't get the right cell for that particular row. Perhaps I'm not fully understanding the dataCellForRow:
function for NSTableColumn
?
I know you can't quite add a tracking area for cells, but instead you must create the hit test for mouse clicks and then begin tracking once the hit test is successful (meaning the mouse is already down) and then use startTracking:
, continueTracking:
, and stopTracking:
to get the mouse's position. The idea though is that it has a hover effect before any mouseDown:
action.
Also, I can't just use a view-based tableview (which would be incredible) because my app must be 10.6 compatible.
Upvotes: 1
Views: 2281
Reputation: 104092
I'm not sure what's wrong with your method of getting the cell, but you don't really need to get that to do what you want. I tested a way to do this that entailed creating a table view subclass to do the tracking in the mouse moved method. Here is the code for that subclass:
-(void)awakeFromNib {
NSTrackingArea *tracker = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveInActiveApp owner:self userInfo:nil];
[self addTrackingArea:tracker];
self.rowNum = -1;
}
-(void)mouseMoved:(NSEvent *)theEvent {
NSPoint p = theEvent.locationInWindow;
NSPoint tablePoint = [self convertPoint:p fromView:nil];
NSInteger newRowNum = [self rowAtPoint:tablePoint];
NSInteger newColNum = [self columnAtPoint:tablePoint];
if (newColNum != self.colNum || newRowNum != self.rowNum) {
self.rowNum = newRowNum;
self.colNum = newColNum;
[self reloadData];
}
}
-(void)mouseEntered:(NSEvent *)theEvent {
[self reloadData];
}
-(void)mouseExited:(NSEvent *)theEvent {
self.rowNum = -1;
[self reloadData];
}
I put the array and table delegate and data source code in the app delegate (probably not the best place, but ok for testing).
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.theData = @[@{@"name":@"Tom",@"age":@"47"},@{@"name":@"Dick",@"age":@"21"},@{@"name":@"Harry",@"age":@"27"}];
[self.table reloadData];
self.dict = [NSDictionary dictionaryWithObjectsAndKeys:@2,NSUnderlineStyleAttributeName,[NSColor redColor],NSForegroundColorAttributeName,nil];
}
- (NSInteger)numberOfRowsInTableView:(RDTableView *)aTableView {
return self.theData.count;
}
- (id)tableView:(RDTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
if (self.table.colNum == 0 && rowIndex == self.table.rowNum && [aTableColumn.identifier isEqualToString:@"Link"]) {
NSString *theName = [[self.theData objectAtIndex:rowIndex] valueForKey:@"name"];
return [[NSAttributedString alloc] initWithString:theName attributes:self.dict];
}else if ([aTableColumn.identifier isEqualToString:@"Link"]){
return [[self.theData objectAtIndex:rowIndex] valueForKey:@"name"];
}else{
return [[self.theData objectAtIndex:rowIndex] valueForKey:@"age"];
}
}
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
if (self.table.colNum == 0)
NSLog(@"%ld",[aNotification.object selectedRow]);
}
I use the delegate method tableViewSelectionDidChange: to implement the action if you click on a cell in the first column (which has the identifier "Link" set in IB).
Upvotes: 5