When I select a NSTextFieldCell in a NSTableView, the behavior is different depending on the row is selected or not.
If the row is selected the cell is immediately selected, and the cursor is blinking inside the text field
If the row is not selected, the only change after the click is the selection of the row, but the cell doesn't go into edit mode.
I would like to have the cell into edit mode in both cases after 1 click.
Implement this method below, it will edit your cell:-
- (void)editColumn:(NSInteger)columnIndex row:(NSInteger)rowIndex withEvent:(NSEvent *)theEvent select:(BOOL)flag
I think what you want is to edit your cell with one click. For this you need to subclass your tableview and capture its mousedown: event as
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint globalLocation = [theEvent locationInWindow];
NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
NSInteger clickedRow = [self rowAtPoint:localLocation];
NSInteger clickedCol = [self columnAtPoint:localLocation];
[super mouseDown:theEvent];
[self editColumn:clickedCol row:clickedRow withEvent:theEvent select:YES];
}
Related
I have one table view which have four columns, fourth columns is populating with attributes string, I need to call one action whenever click on row of fourth column
In others word whiner i click on fourth column's row at that time only action should call
for entire row i am able to do that but for perticullar column not.
I think you would need to subclass NSTableView and handle mouseDown
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint globalLocation = [theEvent locationInWindow];
NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
NSInteger clickedRow = [self rowAtPoint:localLocation];
NSInteger clickedCol = [self columnAtPoint:localLocation];
if (clickedCol == 3) //... fourth column
//.... do something with clickeRow and clickedCol
}
You could create a custom delegate to inform the class' owner that a particular row-col combination has been clicked.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==3)
{
//DO your action here
}
}
By default, NSTableView allows the user to clear the rows selection by clicking anywhere in the blank area of the table view. This however is not always intuitive and sometimes isn’t even possible (for example, when the table view doesn’t actually have any empty area inside itself).
So how do you allow the user to deselect the row by simply clicking on it again? No regular delegate methods (like -tableView:shouldSelectRow:) are called in this case so you can’t capture the click on a row that is already selected, this way.
You want to define your own subclass of NSTableView and set up -mouseDown: like so:
- (void)mouseDown:(NSEvent *)theEvent {
NSPoint globalLocation = [theEvent locationInWindow];
NSPoint localLocation = [self convertPoint:globalLocation fromView:nil];
NSInteger clickedRow = [self rowAtPoint:localLocation];
BOOL wasPreselected = (self.selectedRow == clickedRow);
[super mouseDown:theEvent];
if (wasPreselected)
[self deselectRow:self.selectedRow];
}
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.
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).
I want to implement an NSTextField where when I click it, it selects all the text. (to give the user easy way to delete all current text)
when I finish editing it, either by pressing enter/tab or moving the mouse outside of it's rect, I will move the focus out of the field, and change it's alpha values to 0.5.
My Code:
H file:
#import <Foundation/Foundation.h>
#interface MoodMsgTextField : NSTextField<NSTextFieldDelegate>
#end
M file:
-(BOOL) becomeFirstResponder
{
NSLog(#"become first responder");
BOOL result = [super becomeFirstResponder];
if(result)
{
[self setAlphaValue:1.0];
[self performSelector:#selector(selectText:) withObject:self afterDelay:0];
}
return result;
}
-(BOOL) refusesFirstResponder
{
return NO;
}
-(BOOL) resignFirstResponder
{
NSLog(#"resigning first responder");
BOOL result = [super resignFirstResponder];
NSText* fieldEditor = [self.window fieldEditor:YES forObject:self];
[fieldEditor setSelectedRange:NSMakeRange(0,0)];
[fieldEditor setNeedsDisplay:YES];
[self setAlphaValue:0.5];
return result;
}
-(void)awakeFromNib
{
self.delegate = self;
[self setAlphaValue:0.5];
[self setBordered:YES];
[self setWantsLayer:YES];
self.layer.borderWidth = 0.5;
self.layer.borderColor = [[NSColor grayColor] CGColor];
}
- (void)controlTextDidChange:(NSNotification *)aNotification
{
NSLog(#"the text is %#",self.stringValue);
}
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
NSLog(#"end editiing : the text is %#",self.stringValue);
[self.window makeFirstResponder:nil];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
[self setWantsLayer:YES];
self.layer.borderWidth = 0.5;
self.layer.borderColor = [[NSColor grayColor] CGColor];
}
- (void)mouseExited:(NSEvent *)theEvent
{
[self setWantsLayer:YES];
self.layer.borderWidth = 0;
}
So, I have a few problem:
1.
When I press inside the NSTextField (when the focus is outside) it instantly becomes and resigns first responder and I get editing end message. Why is that ?
The log I get on click is this :
2011-08-02 18:03:19.044 ooVoo[42415:707] become first responder
2011-08-02 18:03:19.045 ooVoo[42415:707] resigning first responder
2011-08-02 18:03:19.104 ooVoo[42415:707] end editing : the text is
2.
When I press the enter key it just selects all text inside and doesn't move the mouse focus. When I press the tab is does seem to move focus, however neither of the two causes the resignFirstResponder to get called. Why ?
3.
None of the mouse event function are getting called. Do I need to to do something special for that ? I thought that since they are NSResponder's ones, I will get those for free by inheriting from NSTextField. Do I need NSTrackingInfo here as well ?
4.
Last but not least, for some reason, every couple letters, one letter seems to be bold.
I have no idea why.
I'd appreciate any help.
Thanks
I am not sure why this is happening in this case but you should read about the Field Editor concept. Basically a NSTextField does not handle its own input but uses an NSTextView called the field editor to accept input.
You need to react to the Enter key yourself. Take a look at the key handling documentation. Here is an answer with an example.
To get mouse events you can use NSTrackingArea. See the docs for Mouse Tracking.
I do not have any input on this except that sometimes text drawing can look bold when really what is happening is that the text is being drawn multiple times without erasing the background.
How would I use a tableView as a value selector?
So I have a series of input fields and what I want is when you select a cetian field it opens a tableview of options that you can pick from as a value for that field.
Upon selecting an option it returns to the previous View with the selected value filling that field.
This is what I do, similar to the Settings > General > International > Language table view in the iPhone/iPod.
The user can tap a row and a check mark will appear. The view is dismissed when "Done" or "Cancel" is tapped.
First, create a UITableViewController that will display your options. Have a toolbar on the top with a Cancel and Done button. Also have these properties:
SEL selector; // will hold the selector to be invoked when the user taps the Done button
id target; // target for the selector
NSUInteger selectedRow; // hold the last selected row
This view will be presented with the presentModalViewController:animated: method so it appears from the bottom of the screen. You could present it in any other way, but it seems kind of standard across iPhone applications.
Before presenting the view, set target and selector so a method will be called when the user taps the "Done" button.
Now, in your newly created UITableViewController you can implement the thetableView:didSelectRowAtIndexPath:` method as:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark; // show checkmark
[cell setSelected:NO animated:YES]; // deselect row so it doesn't remain selected
cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selectedRow inSection:0]];
cell.accessoryType = UITableViewCellAccessoryNone; // remove check from previously selected row
selectedRow = indexPath.row; // remember the newly selected row
}
Also implement cancel and done methods for the toolbar buttons:
- (IBAction)done:(UIBarButtonItem *)item
{
[target performSelector:selector withObject:[stringArray objectAtIndex:selectedRow]];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)cancel:(UIBarButtonItem *)item
{
[self dismissModalViewControllerAnimated:YES];
}
You should use UITableViewDelegate's tableView:didSelectRowAtIndexPath:, remember the value somewhere in another object (a share instance/singleton maybe? - depending on your architecture) and then dismiss this table view.
I implemented a ViewController for Date pick.
I create a protocol to return the date picked to the previous view.
#protocol DataViewDelegate
#optional
- (void)dataViewControllerDidFinish:(NSDate*)dateSelected;
#end
...
- (void) viewDidDisappear:(BOOL)animated
{
if ([ (id)(self.delegate) respondsToSelector:#selector(dataViewControllerDidFinish:)])
{
[self.delegate dataViewControllerDidFinish:self.data];
}
[super viewDidDisappear:animated];
}
In the picker view you can use the
tableView:didSelectRowAtIndexPath:
to select the row you want. Here i set the data property.
The previous view is the delegate for the protocol.