基于cell-base的NSTableView

写此文章,一是积累一下知识,二也是因为某个项目要求在10.6上运行,但由于10.6的NSTableView只支持Cell-Base。因此想与iphone一样,把一些视图addsubview来说就要走点弯路了。在10.7下就可以完全使用view-base来实现。对于view来说,大家都用得很顺手了,想什么画什么,add一下就OK了,但基于cell-base 的row cell,你还使用addview吗?要想了解CELL 就得先了解一下NSCell,这个是Cell的祖宗了,在mac os中各个控件基本上都有一个cell,而这些cell都是从NSCell派生出来。如果不清楚建议先了解一下。

下面重点回到tableView上,讲一下在cell-base上碰到的问题,及解决方式,如果还有更好的,请高人指点。

question:

1.如何自定义绘制某列某行的表格显示自己想要的样式?

2.如何锁定指定的行不允行选中或修改?

3.如何当鼠标进入到指定的cell中进行触发事件?

4.如何实现NSTableView的动态高度?并随列的大小改变而自动设置高度?

5.如何更改选中的行的高亮色?

6.如何可以进行选择自定义cell中的文字进行选中操作?

7.如何实现Cell中的文字高亮部分显示?

NSTableView 的代码Create部分:

[objc] view plaincopy

  1. NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame:NSMakeRect(10, 10, 560, 540)];
  2. FSHighlightTableView * tableView = [[FSHighlightTableView alloc] initWithFrame:NSMakeRect(0, 0, 544, 540)];
  3. // create tableview style
  4. //设置水平,坚直线
  5. [tableView setGridStyleMask:NSTableViewSolidVerticalGridLineMask | NSTableViewSolidHorizontalGridLineMask];
  6. //线条色
  7. [tableView setGridColor:[NSColor redColor]];
  8. //设置背景色
  9. [tableView setBackgroundColor:[NSColor greenColor]];
  10. //设置每个cell的换行模式,显不下时用...
  11. [[tableView cell]setLineBreakMode:NSLineBreakByTruncatingTail];
  12. [[tableView cell]setTruncatesLastVisibleLine:YES];
  13. [tableView sizeLastColumnToFit];
  14. [tableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
  15. //[tableView setAllowsTypeSelect:YES];
  16. //设置允许多选
  17. [tableView setAllowsMultipleSelection:NO];
  18. [tableView setAllowsExpansionToolTips:YES];
  19. [tableView setAllowsEmptySelection:YES];
  20. [tableView setAllowsColumnSelection:YES];
  21. [tableView setAllowsColumnResizing:YES];
  22. [tableView setAllowsColumnReordering:YES];
  23. //双击
  24. [tableView setDoubleAction:@selector(ontableviewrowdoubleClicked:)];
  25. [tableView setAction:@selector(ontablerowclicked:)];
  26. //选中高亮色模式
  27. //显示背景色
  28. [tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular];
  29. //会把背景色去掉
  30. //[tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
  31. //NSTableViewSelectionHighlightStyleNone
  32. //不需要列表头
  33. //[tableView setHeaderView:nil];
  34. //使用隐藏的效果会出现表头的高度
  35. //[tableView.headerView setHidden:YES];
  36. // create columns for our table
  37. NSTableColumn * column1 = [[NSTableColumn alloc] initWithIdentifier:@"col1"];
  38. [column1.headerCell setTitle:@"第一列"];
  39. //[column1 setResizingMask:NSTableColumnAutoresizingMask];
  40. NSTableColumn * column2 = [[NSTableColumn alloc] initWithIdentifier:@"col2"];
  41. [column2.headerCell setTitle:@"第二列"];
  42. //[column2 setResizingMask:NSTableColumnAutoresizingMask];
  43. [column1 setWidth:250];
  44. [column2 setWidth:250];
  45. // generally you want to add at least one column to the table view.
  46. [tableView addTableColumn:column1];
  47. [tableView addTableColumn:column2];
  48. [tableView setDelegate:self];
  49. [tableView setDataSource:self];
  50. // embed the table view in the scroll view, and add the scroll view to our window.
  51. [tableContainer setDocumentView:tableView];
  52. [tableContainer setHasVerticalScroller:YES];
  53. [tableContainer setHasHorizontalScroller:YES];
  54. [self addSubview:tableContainer];
  55. [tableContainer release];
  56. [tableView release];
  57. [column1 release];
  58. [column2 release];

上述代码是创建一个二列的table(本人不太习G使用IB来弄UI)。

再来看一下代理。

关键的:

[objc] view plaincopy

  1. - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
  2. {
  3. NSTableColumn *column = [[tableView tableColumns] objectAtIndex:0];
  4. NSCell *dycell = [tableView preparedCellAtColumn:0 row:row];
  5. NSRect cellBounds = NSZeroRect;
  6. cellBounds.size.width = [column width]; cellBounds.size.height = FLT_MAX;
  7. NSSize cellSize = [dycell cellSizeForBounds:cellBounds];
  8. return cellSize.height;
  9. }
  10. - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
  11. {
  12. return listData.count;
  13. }
  14. - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
  15. {
  16. return [listData objectAtIndex:row];
  17. }
  18. - (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
  19. {
  20. if ([tableColumn.identifier isEqualToString:@"col1"]) {
  21. FSDyHeightCell *dycell = [[[FSDyHeightCell alloc]init]autorelease];
  22. dycell.display = [listData objectAtIndex:row];
  23. return dycell;
  24. } //一定要写判断条件,原来只有一个else 显示的不对,不写的话永远不会进第一列
  25. //    else if ([tableColumn.identifier isEqualToString:@"col2"])
  26. //    {
  27. //        FSCell *customCell = [[[FSCell alloc]init]autorelease];
  28. //
  29. //        [customCell setSelectionBKColor:[NSColor lightGrayColor]];
  30. //        [customCell setSelectionFontColor:[NSColor redColor]];
  31. //        return customCell;
  32. //    }
  33. return nil;
  34. }

看起来是不是有点像iphone的tableView呀。确实有点,不过mac的有列的概念了。其实这几个代理就可以基本的把数据显示出来。这没有什么好奇怪的。但要对每个cell进行一些功能的扩展或自定义,这就需要费时了。

问题1:先看一下未定义之前,NSTableView为我们默认创建了一个NSTextFieldCell的对象来进行显示数据,

很简单的数据显示,但往往我们有时需要在某个表格中有图,有字显然NSTextFieldCell是不够的了,可以参考一下官网提供的ImageAndTextCell 。另外我们也可以自己从NSCell派生下来,自己实现NSCell的

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;方法,使用这个方法draw时可以按照自己的想法把图,文等都可以draw上去,但这个就需要有点CGGraphics 的功底了。这个方法还有一点要注意的就是cellFrame 的y轴坐标,这个坐标是一个y轴的偏移坐标。因此在使用这个来draw东东时,rect的y轴一定要跟着变,否则你看到的只有一行数据,大家都积在同一坐标点上了,另外,这个y的值会把grid的线条宽加在内,比如每行之间线条是1,哪么在第10行的时候,中间隔了9条线,哪么第10行的y的偏移会是9行的高度+8行的线行宽度的值作为第10行的起始偏移点,这个大家体会一下吧,可能我描术的不是很清楚。

如图中,我自己将第二列进行自定义,当然这个大家可以按自己的需要进行绘制。贴下简单的码:

[objc] view plaincopy

  1. - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
  2. {
  3. //选中高亮色这种只能改变某个Cell的背景色不能整行改变
  4. if ([self isHighlighted]) {
  5. [self highlightColorWithFrame:cellFrame inView:controlView];
  6. }
  7. NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
  8. NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
  9. [NSFont systemFontOfSize:13], NSFontAttributeName, nil nil];
  10. NSMutableAttributedString *string = [[[NSMutableAttributedString alloc]initWithString:@"hello world" attributes:primaryTextAttributes]autorelease];
  11. [string setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:NSMakeRange(0, 5)];
  12. //[string drawAtPoint:NSMakePoint(cellFrame.origin.x+cellFrame.size.height+10, cellFrame.origin.y+20)];
  13. //用下面这个可以使用省略属性
  14. NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
  15. [ps setLineBreakMode:NSLineBreakByTruncatingTail];
  16. NSRange range = NSMakeRange(0, [string length]);
  17. [string addAttribute:NSParagraphStyleAttributeName value:ps range:range];
  18. [ps release];
  19. [string drawInRect:NSMakeRect(cellFrame.origin.x+cellFrame.size.height+15, cellFrame.origin.y+10,40,15)];
  20. NSImage *icon = [NSImage imageNamed:@"1"];
  21. //icon = [self roundCorners:icon];圆形
  22. //这句很重要,如果没有Y轴的移偏,看到的只有第一行有头像
  23. float yOffset = cellFrame.origin.y;
  24. [icon drawInRect:NSMakeRect(cellFrame.origin.x+5,yOffset + 3,cellFrame.size.height-6, cellFrame.size.height-6)
  25. fromRect:NSMakeRect(0,0,[icon size].width, [icon size].height)
  26. operation:NSCompositeSourceOver
  27. fraction:1.0 respectFlipped:YES hints:nil];
  28. }

问题二:有时候在工作中,我们对满足某一条件的行或列进行锁定,不让用户进行编辑或随意拖动。

这个稍有点简单,主要是利用下面的代理来完成之。

[objc] view plaincopy

  1. /*==========================================================================================
  2. *    设置某行是否可以被选中,返回YES,则可以选中,返回NO 则不可选中,即没有高亮选中
  3. *    用于控制某一行是否可以被选中,前提是selectionShouldChangeInTableView:必须返回YES
  4. *===========================================================================================*/
  5. - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
  6. {
  7. if (row == 2)
  8. {
  9. return NO;
  10. }
  11. return YES;
  12. }
  13. - (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
  14. {
  15. return proposedSelectionIndexes;
  16. }
  17. - (BOOL)tableView:(NSTableView *)tableView shouldSelectTableColumn:(NSTableColumn *)tableColumn
  18. {
  19. if ([tableColumn.identifier isEqualToString:kMCButtontColumnID]) {
  20. return YES;
  21. }
  22. return NO;
  23. }

问题三:这个问题上需要费点劲,为什么呢,如果做 MAC 的话你会发现,NSView是不会自动响应MouseMove事件的,同时NSTableView也不会自动响应MouseMove事件的。况且现在是Cell-base没有View.本想利用NSView上的鼠标事件来实现移出移入单元格的思路也被卡掉了。哪么就没有办法了吗?办法总是有的,只是好用不好用,易用不易用罢了,下面我说下我的实现思路,如果有MAC高手发现不对就指教了。

1。让tableView支持mouseMove事件。

2。想办法把mouseMove事件中的鼠标坐标点转换为tableView对应的行和列。

先解决第一点,要想有mouseMove事件,先得让tableView有焦点。有时候自己手工创建的tableView 由于窗口上有好多View而使得tableView当前不在焦点上,因此可以借住第一响就这个方式来使之成为第一响应。

[objc] view plaincopy

  1. - (void)focus:(NSWindow *) owner
  2. {
  3. [owner makeFirstResponder:m_tableView];
  4. }

其次还必须把NSTableView 的接受鼠标事件开启:

[objc] view plaincopy

  1. [m_tableView.window setAcceptsMouseMovedEvents:YES];

好,现在NSTableView有鼠标移动事件了,现在关键是确定鼠标移动点是在哪一行和列上,细看NSTableView的接口你会发现有这样两个方法:

[objc] view plaincopy

  1. /* Returns the column index at ‘point‘, or -1 if ‘point‘ is outside of all table columns.
  2. */
  3. - (NSInteger)columnAtPoint:(NSPoint)point;
  4. - (NSInteger)rowAtPoint:(NSPoint)point;

但注意这里的point,与鼠标的坐标不同,鼠标是相对于screen的,需要转换到app上来,怎么转?

[objc] view plaincopy

  1. NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];

这样一句就可以转过来了。

好吧,有了这些信息哪么就好办了,现在还有一个关键点。就是这个行与行,列与列之间的事件触发。因此必须很精确的判断出来。具体看码吧。

[objc] view plaincopy

  1. - (BOOL)RTMouseInRect:(NSRect) rect withPoint:(NSPoint)pt
  2. {
  3. // +2是因为有一个边框的大小为1
  4. float xpos = ceilf(pt.x); //向上取整
  5. float ypos = ceilf(pt.y);
  6. if ((xpos >= rect.origin.x) && ( xpos <= rect.origin.x + rect.size.width +2)
  7. && (ypos >= rect.origin.y) && ypos <= rect.origin.y + rect.size.height+2)
  8. {
  9. return YES;
  10. }
  11. return NO;
  12. }
  13. static NSRect prevRect;
  14. - (void)mouseMoved:(NSEvent *)theEvent
  15. {
  16. //NSLog(@"mouseMoved theEvent = %@",theEvent);
  17. NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];
  18. long column = [self columnAtPoint:p];
  19. long row = [self rowAtPoint:p];
  20. if(column != -1 && row != -1)
  21. {
  22. //NSLog(@"col = %ld",column);
  23. // NSLog(@"row = %ld",row);
  24. // NSLog(@"pppppp = %@",NSStringFromPoint(p));
  25. //NSLog(@"self.rowHeight = %f",self.rowHeight);
  26. NSTableColumn* theColumn = [[self tableColumns] objectAtIndex:column];
  27. //NSLog(@"theColumn = %@",theColumn);
  28. //NSLog(@"theColumn.dataCell = %@",theColumn.dataCell);
  29. //NSCell *dataCell = [theColumn dataCellForRow:row];//取到的类型不对,一直是NSTextFieldCell的,不是自己定义的
  30. //NSLog(@"dataCell = %@",dataCell);
  31. //只有用这种方法才可以取到正确的自定义cell
  32. NSCell *customcell = [self preparedCellAtColumn:column row:row];
  33. //NSLog(@"customcell = %@",customcell);
  34. NSRect rect = [self frameOfCellAtColumn:column row:row];
  35. //前后发生变化时
  36. if (![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(rect)])
  37. {
  38. BOOL enter = [self RTMouseInRect:prevRect withPoint:p];
  39. if (!enter && ![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(NSZeroRect)])
  40. {
  41. //NSLog(@"outter");
  42. NSIndexSet *idxset = [self columnIndexesInRect:prevRect];
  43. NSUInteger col = [idxset lastIndex];
  44. //NSArray * cols =[[self tableColumns]objectsAtIndexes:idxset]; //也可以取到
  45. NSTableColumn* colobj = [[self tableColumns] objectAtIndex:col];
  46. NSRange rg = [self rowsInRect:prevRect];
  47. NSUInteger preRow = rg.location;
  48. id cell = [self preparedCellAtColumn:col row:preRow];
  49. if ([delegate respondsToSelector:@selector(mouseExitTableViewCell:cell:column:row:)]) {
  50. [delegate mouseExitTableViewCell:self cell:cell column:colobj row:preRow];
  51. }
  52. }
  53. enter = [self RTMouseInRect:rect withPoint:p];
  54. if (enter)
  55. {
  56. //NSLog(@"enter ");
  57. if ([delegate respondsToSelector:@selector(mouseEnterTableViewCell:cell:column:row:)]) {
  58. [delegate mouseEnterTableViewCell:self cell:customcell column:theColumn row:row];
  59. }
  60. }
  61. }
  62. prevRect = rect;
  63. }
  64. else
  65. {
  66. if (![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(NSZeroRect)])
  67. {
  68. //NSLog(@"outter");
  69. NSIndexSet *idxset = [self columnIndexesInRect:prevRect];
  70. NSUInteger col = [idxset lastIndex];
  71. //NSArray * cols =[[self tableColumns]objectsAtIndexes:idxset]; //也可以取到
  72. NSTableColumn* colobj = [[self tableColumns] objectAtIndex:col];
  73. NSRange rg = [self rowsInRect:prevRect];
  74. NSUInteger preRow = rg.location;
  75. id cell = [self preparedCellAtColumn:col row:preRow];
  76. if ([delegate respondsToSelector:@selector(mouseExitTableViewCell:cell:column:row:)]) {
  77. [delegate mouseExitTableViewCell:self cell:cell column:colobj row:preRow];
  78. }
  79. }
  80. prevRect = NSZeroRect;
  81. }
  82. [super mouseMoved:theEvent];
  83. }
  84. - (void)scrollWheel:(NSEvent *)theEvent
  85. {
  86. NSLog(@"wheel theEvent = %@",theEvent);
  87. [super scrollWheel:theEvent];
  88. //滚动时触发一下鼠标移动事件
  89. [self mouseMoved:theEvent];
  90. }

下面是通过代理打印出来的信息:


问题四:一般情况下,对于每行高度是固定的,哪就没有什么好说的了,实现

[objc] view plaincopy

  1. - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row

就可以了,但如果是某行的高度是动态的,哪对于cell-base还真有点麻烦。为什么,因为cell只有在绘制出来的时候都好确定cell的大小,不像View,可以直接用frame就可以确定。cell不一样,cell初始代的时候是是(40000,40000)宽高。你总不能把这个当作动态高度吧。因此在Cell中必须使用cellSize或cellSizeForBounds 来确定高度。

看下效果:

具体的算法:

[objc] view plaincopy

  1. -(NSSize)cellSizeForBounds:(NSRect)aRect
  2. {
  3. NSSize tmp = NSMakeSize(aRect.size.width, aRect.size.height);
  4. if (display) {
  5. //tmp.height = [self heightForStringDrawing:display andFont:[NSFont fontWithName:@"Helvetica" size:13] withWidth:tmp.width -20]+20;
  6. NSRect rect = [self getstringHeighInWith:tmp.width -20 byString:display];
  7. tmp.height = CGRectGetHeight(rect)+20;
  8. }
  9. else
  10. {
  11. tmp.height = 0;
  12. }
  13. return tmp;
  14. }
  15. -(NSSize)cellSize
  16. {
  17. NSSize tmp = [super cellSize];
  18. if (display) {
  19. //tmp.height = [self heightForStringDrawing:display andFont:[NSFont systemFontOfSize:13] withWidth:230]+20;

[objc] view plaincopy

  1. <pre code_snippet_id="172750" snippet_file_name="blog_20140127_12_624697" name="code" class="objc">        NSRect rect = [self getstringHeighInWith:tmp.width -20 byString:display];
  2. tmp.height = CGRectGetHeight(rect)+20;</pre> } else { tmp.height = 0; } return tmp;}- (NSRect)getstringHeighInWith:(float)width byString:(NSString *)string{ NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [ps setLineBreakMode:NSLineBreakByCharWrapping];
  3. ps.alignment = NSJustifiedTextAlignment; NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSColor blackColor], NSForegroundColorAttributeName, [NSFont fontWithName:@"Helvetica" size:13], NSFontAttributeName, NSParagraphStyleAttributeName,ps,nil];
  4. NSRect rect = [string boundingRectWithSize:NSMakeSize(width, 4000) options:NSStringDrawingUsesLineFragmentOrigin attributes:primaryTextAttributes]; return rect;}<p></p>
  5. <pre></pre>
  6. <br>
  7. 其次是在高度返回值中处理:
  8. <p></p>
  9. <p></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_13_7800014" name="code" class="objc">- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
  10. {
  11. NSTableColumn *column = [[tableView tableColumns] objectAtIndex:0];
  12. NSCell *dycell = [tableView preparedCellAtColumn:0 row:row];
  13. NSRect cellBounds = NSZeroRect;
  14. cellBounds.size.width = [column width]; cellBounds.size.height = FLT_MAX;
  15. NSSize cellSize = [dycell cellSizeForBounds:cellBounds];
  16. return cellSize.height;
  17. }</pre><br>
  18. 以上可以实现动态高度了,但还有一点,就是列拖动大小的时候,行的高度不变,哪怎么处理呢?幸好,tableView已为我们提供了便捷的刷新方法:<p></p>
  19. <p></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_14_4418924" name="code" class="objc">- (void)tableViewColumnDidResize:(NSNotification *)aNotification
  20. {
  21. NSTableView* aTableView = aNotification.object;
  22. NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,aTableView.numberOfRows)];
  23. [aTableView noteHeightOfRowsWithIndexesChanged:indexes];
  24. }</pre>即<pre code_snippet_id="172750" snippet_file_name="blog_20140127_15_9642394" name="code" class="objc">[aTableView noteHeightOfRowsWithIndexesChanged:indexes];</pre>和<br>
  25. <pre code_snippet_id="172750" snippet_file_name="blog_20140127_16_2357610" name="code" class="objc">- (void)noteNumberOfRowsChanged;</pre>我们只需要在列大小改变的时候调用就OK了,我的代码里是用窗口大小变化来触发的。具体以实际情况而定了。<br>
  26. <br>
  27. 问题五:<p></p>
  28. <p>tableView自身的选中色为蓝色的。要想改变,有两种变通的方法。</p>
  29. <p>1.利用NSCell进行设置,注意这种处理方法,是针对每个格子的进行设置,比如有1234列,如果每例的Cell设置得不同的时候,你会发现当选中一行时,显示为不同的选中色了。样例代码。这个用法,需要注意有表格线和没有表格线时的表示,否则你会看到蓝色线条。</p>
  30. <p></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_17_9740670" name="code" class="objc">//自个画,,,,,
  31. - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
  32. {
  33. BOOL elementDisabled = NO;
  34. NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : (elementDisabled? [NSColor disabledControlTextColor] : [NSColor textColor]);
  35. NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
  36. [NSFont systemFontOfSize:13], NSFontAttributeName, nil nil];
  37. [self.displayName.stringValue drawAtPoint:NSMakePoint(cellFrame.origin.x+cellFrame.size.height+10, cellFrame.origin.y) withAttributes:primaryTextAttributes];
  38. //画图
  39. [[NSGraphicsContext currentContext] saveGraphicsState];
  40. float yOffset = cellFrame.origin.y;
  41. if ([controlView isFlipped]) {
  42. NSAffineTransform* xform = [NSAffineTransform transform];
  43. [xform translateXBy:0.0 yBy: cellFrame.size.height];
  44. [xform scaleXBy:1.0 yBy:-1.0];
  45. [xform concat];
  46. yOffset = 0-cellFrame.origin.y;
  47. }
  48. NSImageInterpolation interpolation = [[NSGraphicsContext currentContext] imageInterpolation];
  49. [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
  50. [avatar.image drawInRect:NSMakeRect(cellFrame.origin.x+5,yOffset+3,cellFrame.size.height-6, cellFrame.size.height-6)
  51. fromRect:NSMakeRect(0,0,[avatar.image size].width, [avatar.image size].height)
  52. operation:NSCompositeSourceOver
  53. fraction:1.0];
  54. [[NSGraphicsContext currentContext] setImageInterpolation: interpolation];
  55. [[NSGraphicsContext currentContext] restoreGraphicsState];
  56. }
  57. - (NSAttributedString*)getCellAttributes
  58. {
  59. NSDictionary*  _attributes = [NSDictionary dictionaryWithObjectsAndKeys:_cellFontColor,NSForegroundColorAttributeName,nil];
  60. NSString* _cellString = [self stringValue];
  61. _cellAttributedString = [[[NSAttributedString alloc]
  62. initWithString:_cellString attributes:_attributes] autorelease];
  63. return _cellAttributedString;
  64. }
  65. - (NSColor*)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
  66. {
  67. NSRect newRect = NSMakeRect(cellFrame.origin.x - 1, cellFrame.origin.y, cellFrame.size.width + 5, cellFrame.size.height);
  68. if (_cellBKColor)
  69. {
  70. [_cellBKColor set];
  71. NSRectFill(newRect);
  72. }
  73. [self setAttributedStringValue:[self getCellAttributes]];
  74. return nil;
  75. }</pre><p></p>
  76. <p>第2种,也是我比较喜欢的吧,不过需要继承NSTableView来实现。</p>
  77. <p class="p1">- (<span class="s1">id</span>)_highlightColorForCell:(<span class="s1">id</span>)cell;进行重写。</p>
  78. <p class="p1"></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_18_4407734" name="code" class="objc">//重写
  79. - (id)_highlightColorForCell:(id)cell
  80. {
  81. if([self selectionHighlightStyle] == 1)
  82. {
  83. return nil;
  84. }
  85. else
  86. {
  87. return [NSColor redColor];//_highlightBKColor;
  88. }
  89. }</pre><br>
  90. 问题六:<p></p>
  91. <p class="p1">这个问题是当你绘制出来的字体,不支持鼠标选中操作。</p>
  92. <p class="p1">这个问题,还没有解决,初步确认是用这四个方法进行实现,但我还没有研究透。还在找资料。(也请高手指点)</p>
  93. <p class="p1"></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_19_6043153" name="code" class="objc">- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag;
  94. - (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent;
  95. - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength;
  96. - (void)endEditing:(NSText *)textObj;</pre><br>
  97. 问题七:<p></p>
  98. <p class="p1">对于部分字体的高亮,通常会出现在搜索时的显示结果上。哪这又是怎么处理的呢?其它也是通过属性字段进行设置不同的字体色进行Draw上来的。</p>
  99. <p></p><pre code_snippet_id="172750" snippet_file_name="blog_20140127_20_3774879" name="code" class="objc">- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
  100. {
  101. NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
  102. if (name && phone && highlightkey)
  103. {
  104. NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
  105. [NSFont systemFontOfSize:12], NSFontAttributeName, nil nil];
  106. NSMutableAttributedString *namestring = [[NSMutableAttributedString alloc]initWithString:name attributes:primaryTextAttributes];
  107. [namestring beginEditing];
  108. NSRange namerg = [name rangeOfString:highlightkey];
  109. [namestring setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:namerg];
  110. NSMutableAttributedString *phonestring = [[NSMutableAttributedString alloc]initWithString:phone attributes:primaryTextAttributes];
  111. NSRange phonerg = [phone rangeOfString:highlightkey];
  112. [phonestring setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:phonerg];
  113. NSMutableAttributedString *left = [[NSMutableAttributedString alloc]initWithString:@"(" attributes:primaryTextAttributes];
  114. NSMutableAttributedString *right = [[NSMutableAttributedString alloc]initWithString:@")" attributes:primaryTextAttributes];
  115. [namestring appendAttributedString:left];
  116. [namestring appendAttributedString:phonestring];
  117. [namestring appendAttributedString:right];
  118. NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
  119. [ps setLineBreakMode:NSLineBreakByTruncatingTail];
  120. NSRange range = NSMakeRange(0, [namestring length]);
  121. [namestring addAttribute:NSParagraphStyleAttributeName value:ps range:range];
  122. [ps release];
  123. [namestring endEditing];
  124. CGFloat xpos = cellFrame.origin.x+cellFrame.size.height+15;
  125. CGFloat w = cellFrame.size.width - xpos - 30;
  126. [namestring drawInRect:NSMakeRect(xpos, cellFrame.origin.y+10,w,15)];
  127. [right release];
  128. [left release];
  129. [namestring release];
  130. [phonestring release];
  131. }
  132. if (ringUser)
  133. {
  134. [ringImg drawInRect:NSMakeRect(cellFrame.origin.x+9.5,cellFrame.origin.y + 1,36, 36)
  135. fromRect:NSMakeRect(0,0,ringImg.size.width, ringImg.size.height)
  136. operation:NSCompositeSourceOver
  137. fraction:1.0 respectFlipped:YES hints:nil];
  138. }
  139. if (avatar)
  140. {
  141. [[NSGraphicsContext currentContext] saveGraphicsState];
  142. NSRect rt = NSMakeRect(cellFrame.origin.x+12.5,cellFrame.origin.y + 4,30, 30);
  143. CGFloat radius = 15;
  144. NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:rt xRadius:radius yRadius:radius];
  145. [clipPath setWindingRule:NSEvenOddWindingRule];
  146. [clipPath addClip];
  147. [avatar drawInRect: rt
  148. fromRect:NSMakeRect(0,0,avatar.size.width, avatar.size.height)
  149. operation:NSCompositeSourceOver
  150. fraction:1.0 respectFlipped:YES hints:nil];
  151. [[NSGraphicsContext currentContext] restoreGraphicsState];
  152. }
  153. }
  154. </pre><br>
  155. 其中<pre code_snippet_id="172750" snippet_file_name="blog_20140127_21_5933687" name="code" class="objc">highlightkey就是需要设置为高亮的部分。</pre><p></p>
  156. <p>欢迎路过大侠多多指教。</p>
  157. <p><br>
  158. </p>
  159. <p>好了,有点多,也有点杂。大家需要慢慢体会。源码我都放在:http://download.csdn.net/detail/fengsh998/6887159</p>
  160. <p><br>
  161. </p>
  162. <p>马上回家过年,这是2013贺岁篇,也正好是在csdn发表文章的第100篇。记念一下。</p>
  163. <p>同时也祝自己马年,天马流星,神马飞扬,马到功成,马上有想法,马上有伯乐,马上当BOSS,马上开挂,最后辛苦的一年即将过去,来年心想事成,万事如意。</p>
  164. <p>好,收拾 东东,马上回家。。。。。。</p>
  165. <br>
  166. <br>
  167. <br>
  168. <br>
  169. <br>
  170. <p><br>
  171. </p>
  172. <p><br>
  173. </p>
时间: 2024-11-13 07:55:04

基于cell-base的NSTableView的相关文章

macOS开发之NSTableView的应用详解 - 转

传送门:https://my.oschina.net/u/2340880/blog/886861 摘要: NSTableView是AppKit中的表视图控件,是macOS开发中非常重要的一种视图控件.熟练应用NSTableView控件对mac软件开发十分重要. NSTableView的应用详解 一.引言 和iOS开发中的UITableView有很大差别,NSTableView并非是一个可滚动的列表视图,其是一个不可滚动.支持多列多行的原始列表视图.若要使NSTableView支持滚动,通常会将其

Yii2的深入学习--yii\base\Event 类

根据之前一篇文章,我们知道 Yii2 的事件分两类,一是类级别的事件,二是实例级别的事件.类级别的事件是基于 yii\base\Event 实现,实例级别的事件是基于 yii\base\Component 实现. 今天先来看下类级别事件的实现,代码是 yii\base\Event 类. <?php namespace yii\base; /** * Event is the base class for all event classes. */ class Event extends Obje

Asp.net Core, 基于 claims 实现权限验证 - 引导篇

什么是Claims? 这个直接阅读其他大神些的文章吧,解释得更好. 相关文章阅读: http://www.cnblogs.com/JustRun1983/p/4708176.html http://www.cnblogs.com/jesse2013/p/aspnet-identity-claims-based-authentication-and-owin.html http://www.cnblogs.com/savorboard/p/aspnetcore-identity.html clai

openstack中region、az、host aggregate、cell 概念

1. region 更像是一个地理上的概念,每个region有自己独立的endpoint,regions之间完全隔离,但是多个regions之间共享同一个keystone和dashboard.(注:目前openstack的dashboard还不支持多region) 所以除了提供隔离的功能,region的设计更多侧重地理位置的概念,用户可以选择离自己更近的region来部署自己的服务. 2. cell cell是openstack一个非常重要的概念,主要用来解决openstack的扩展性和规模瓶颈

(转载-学习)openstack中region、az、host aggregate、cell 概念

1. region 更像是一个地理上的概念,每个region有自己独立的endpoint,regions之间完全隔离,但是多个regions之间共享同一个keystone和dashboard.(注:目前openstack的dashboard还不支持多region) 所以除了提供隔离的功能,region的设计更多侧重地理位置的概念,用户可以选择离自己更近的region来部署自己的服务. 2. cell cell是openstack一个非常重要的概念,主要用来解决openstack的扩展性和规模瓶颈

管理openstack多region介绍与实践

转:http://www.cnblogs.com/zhoumingang/p/5514853.html 概念介绍 所谓openstack多region,就是多套openstack共享一个keystone和horizon.每个区域一套openstack环境,可以分布在不同的地理位置,只要网络可达就行.个人认为目的就是为了提供环境隔离的功能,选择启虚拟机的时候可以根据自己所处的位置就近选择. 既然提到region了,那不如就此总结下openstack中其他的至上而下的不同的区域概念. Region

Jetty9开发(1)

Version: 9.2.14.v20151106  Jetty : 开发文档 jetty的官网:http://www.eclipse.org/jetty/ Jetty : 开发文档 目录 I. jetty起步 1.介绍jetty服务器 Jetty是一个开源的项目,他提供的功能有:Http服务器,Http客户端和servlet容器. 2.我应该使用什么版本的jetty服务器? 到目前为止,jetty9是最新的版本,并且拥有比以前版本jetty很多很强大的功能,然而还有很多人仍然在使用更老版本的j

【docker】docker初试与填坑

docker是最近很流行的部署方式,最近尝试之前的项目都转移到docker上运行,下面是碰到的一些坑和解决方案. 网络问题 因为国内的原因,docker pull 镜像的时候经常碰到连不上或者速度极慢的情况. 这部分可以使用 国内流行的 ?daocloud 的方案解决?,使用dao pull代替docker pull ,如果是自行构建,可能需要使用代理或者直接在国外主机build,再打包传回来. 时间同步 hub.docker.com上的镜像,包括自己构建的,基本上都是以utc时区作为默认时区,

记一次死锁问题的排查和解决

说起来这个事情还是挺悲催的,记得上周忙的不亦乐乎,目标是修改之前另外一个团队留下来的一坨代码中的一些bug,这个项目是做OLAP分析的,分为两个模块,逻辑服务器主要负责一些元数据的操作,例如页面上展示的一些信息,而分析服务器负责执行查询语句,因为他们之前使用的是mondrian作为OLAP分析引擎,所以输入的查询是MDX语句,然后结果是一个二维的数据.这是基本的项目背景,当然使用mondrian的过程中发现他的确够慢的. 而且mondrian还有一个问题,它的确在内部实现了一些缓存,缓存好像是基

关于DPM(Deformable Part Model)算法中模型结构的解释

关于可变部件模型的描写叙述在作者[2010 PAMI]Object Detection with Discriminatively Trained Part Based Models的论文中已经有说明: 含有n个部件的目标模型能够形式上定义为一个(n+2)元组:(F0,P1,..., Pn, b),F0是根滤波器,Pi是第i个部件的模型,b是表示偏差的实数值.每一个部件模型用一个三元组定义:(Fi,vi, di),Fi是第i个部件的滤波器:vi是一个二维向量,指定第i个滤波器的锚点位置(anch