基于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部分:

NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame:NSMakeRect(10, 10, 560, 540)];
    FSHighlightTableView * tableView = [[FSHighlightTableView alloc] initWithFrame:NSMakeRect(0, 0, 544, 540)];
    // create tableview style
    //设置水平,坚直线
    [tableView setGridStyleMask:NSTableViewSolidVerticalGridLineMask | NSTableViewSolidHorizontalGridLineMask];
    //线条色
    [tableView setGridColor:[NSColor redColor]];
    //设置背景色
    [tableView setBackgroundColor:[NSColor greenColor]];
    //设置每个cell的换行模式,显不下时用...
    [[tableView cell]setLineBreakMode:NSLineBreakByTruncatingTail];
    [[tableView cell]setTruncatesLastVisibleLine:YES];
    
    [tableView sizeLastColumnToFit];
    [tableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
    
    //[tableView setAllowsTypeSelect:YES];
    //设置允许多选
    [tableView setAllowsMultipleSelection:NO];
    
    [tableView setAllowsExpansionToolTips:YES];
    [tableView setAllowsEmptySelection:YES];
    [tableView setAllowsColumnSelection:YES];
    [tableView setAllowsColumnResizing:YES];
    [tableView setAllowsColumnReordering:YES];
    //双击
    [tableView setDoubleAction:@selector(ontableviewrowdoubleClicked:)];
    [tableView setAction:@selector(ontablerowclicked:)];
    
    //选中高亮色模式
    //显示背景色
    [tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular];
    //会把背景色去掉
    //[tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
    //NSTableViewSelectionHighlightStyleNone
    
    //不需要列表头
    //[tableView setHeaderView:nil];
    //使用隐藏的效果会出现表头的高度
    //[tableView.headerView setHidden:YES];
    
    // create columns for our table
    NSTableColumn * column1 = [[NSTableColumn alloc] initWithIdentifier:@"col1"];
    [column1.headerCell setTitle:@"第一列"];
    //[column1 setResizingMask:NSTableColumnAutoresizingMask];
    
    NSTableColumn * column2 = [[NSTableColumn alloc] initWithIdentifier:@"col2"];
    [column2.headerCell setTitle:@"第二列"];
    //[column2 setResizingMask:NSTableColumnAutoresizingMask];
    
    [column1 setWidth:250];
    [column2 setWidth:250];
    
    // generally you want to add at least one column to the table view.
    [tableView addTableColumn:column1];
    [tableView addTableColumn:column2];
    
    [tableView setDelegate:self];
    [tableView setDataSource:self];
    
    // embed the table view in the scroll view, and add the scroll view to our window.
    [tableContainer setDocumentView:tableView];
    [tableContainer setHasVerticalScroller:YES];
    [tableContainer setHasHorizontalScroller:YES];
    [self addSubview:tableContainer];
    [tableContainer release];
    [tableView release];
    [column1 release];
    [column2 release];

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

再来看一下代理。

关键的:

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{

    NSTableColumn *column = [[tableView tableColumns] objectAtIndex:0];
    NSCell *dycell = [tableView preparedCellAtColumn:0 row:row];
    NSRect cellBounds = NSZeroRect;
    cellBounds.size.width = [column width]; cellBounds.size.height = FLT_MAX;
    NSSize cellSize = [dycell cellSizeForBounds:cellBounds];
    return cellSize.height;
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    return listData.count;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    return [listData objectAtIndex:row];
}

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    if ([tableColumn.identifier isEqualToString:@"col1"]) {
        FSDyHeightCell *dycell = [[[FSDyHeightCell alloc]init]autorelease];

        dycell.display = [listData objectAtIndex:row];
        return dycell;
    } //一定要写判断条件,原来只有一个else 显示的不对,不写的话永远不会进第一列
//    else if ([tableColumn.identifier isEqualToString:@"col2"])
//    {
//        FSCell *customCell = [[[FSCell alloc]init]autorelease];
//        
//        [customCell setSelectionBKColor:[NSColor lightGrayColor]];
//        [customCell setSelectionFontColor:[NSColor redColor]];
//        return customCell;
//    }
    return nil;
}

看起来是不是有点像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行的起始偏移点,这个大家体会一下吧,可能我描术的不是很清楚。


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

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    //选中高亮色这种只能改变某个Cell的背景色不能整行改变
    if ([self isHighlighted]) {
        [self highlightColorWithFrame:cellFrame inView:controlView];
    }
    
    NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
    
    NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
                                           [NSFont systemFontOfSize:13], NSFontAttributeName, nil];
    NSMutableAttributedString *string = [[[NSMutableAttributedString alloc]initWithString:@"hello world" attributes:primaryTextAttributes]autorelease];
    [string setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:NSMakeRange(0, 5)];
    //[string drawAtPoint:NSMakePoint(cellFrame.origin.x+cellFrame.size.height+10, cellFrame.origin.y+20)];
    //用下面这个可以使用省略属性
    
    NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    [ps setLineBreakMode:NSLineBreakByTruncatingTail];
    NSRange range = NSMakeRange(0, [string length]);
    [string addAttribute:NSParagraphStyleAttributeName value:ps range:range];
    [ps release];
    [string drawInRect:NSMakeRect(cellFrame.origin.x+cellFrame.size.height+15, cellFrame.origin.y+10,40,15)];
    
    NSImage *icon = [NSImage imageNamed:@"1"];
    
    //icon = [self roundCorners:icon];圆形

    //这句很重要,如果没有Y轴的移偏,看到的只有第一行有头像
    float yOffset = cellFrame.origin.y;

    [icon drawInRect:NSMakeRect(cellFrame.origin.x+5,yOffset + 3,cellFrame.size.height-6, cellFrame.size.height-6)
                    fromRect:NSMakeRect(0,0,[icon size].width, [icon size].height)
                   operation:NSCompositeSourceOver
            fraction:1.0 respectFlipped:YES hints:nil];
}

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

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

/*==========================================================================================
*    设置某行是否可以被选中,返回YES,则可以选中,返回NO 则不可选中,即没有高亮选中
*    用于控制某一行是否可以被选中,前提是selectionShouldChangeInTableView:必须返回YES
*===========================================================================================*/
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
{
    if (row == 2)
    {
        return NO;
    }
        
    return YES;
}

- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
{
    return proposedSelectionIndexes;
}

- (BOOL)tableView:(NSTableView *)tableView shouldSelectTableColumn:(NSTableColumn *)tableColumn
{
    if ([tableColumn.identifier isEqualToString:kMCButtontColumnID]) {
        return YES;
    }
    return NO;
}

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

1。让tableView支持mouseMove事件。

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

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

- (void)focus:(NSWindow *) owner
{
    [owner makeFirstResponder:m_tableView];
}
其次还必须把NSTableView 的接受鼠标事件开启:

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

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

- (NSInteger)rowAtPoint:(NSPoint)point;
但注意这里的point,与鼠标的坐标不同,鼠标是相对于screen的,需要转换到app上来,怎么转?
 NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];
这样一句就可以转过来了。

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

- (BOOL)RTMouseInRect:(NSRect) rect withPoint:(NSPoint)pt
{
    // +2是因为有一个边框的大小为1
    float xpos = ceilf(pt.x); //向上取整
    float ypos = ceilf(pt.y);
    if ((xpos >= rect.origin.x) && ( xpos <= rect.origin.x + rect.size.width +2)
        && (ypos >= rect.origin.y) && ypos <= rect.origin.y + rect.size.height+2)
    {
        return YES;
    }
    return NO;
}

static NSRect prevRect;
- (void)mouseMoved:(NSEvent *)theEvent
{
    //NSLog(@"mouseMoved theEvent = %@",theEvent);
    NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];

    long column = [self columnAtPoint:p];

    long row = [self rowAtPoint:p];

    if(column != -1 && row != -1)
    {
        //NSLog(@"col = %ld",column);
        // NSLog(@"row = %ld",row);
        
       // NSLog(@"pppppp = %@",NSStringFromPoint(p));
        
        //NSLog(@"self.rowHeight = %f",self.rowHeight);
        
        NSTableColumn* theColumn = [[self tableColumns] objectAtIndex:column];

        //NSLog(@"theColumn = %@",theColumn);
        //NSLog(@"theColumn.dataCell = %@",theColumn.dataCell);
        //NSCell *dataCell = [theColumn dataCellForRow:row];//取到的类型不对,一直是NSTextFieldCell的,不是自己定义的
        //NSLog(@"dataCell = %@",dataCell);
        
        //只有用这种方法才可以取到正确的自定义cell
        NSCell *customcell = [self preparedCellAtColumn:column row:row];
        //NSLog(@"customcell = %@",customcell);
        
        NSRect rect = [self frameOfCellAtColumn:column row:row];
        
        //前后发生变化时
        if (![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(rect)])
        {
            BOOL enter = [self RTMouseInRect:prevRect withPoint:p];
            if (!enter && ![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(NSZeroRect)])
            {
                 //NSLog(@"outter");
                NSIndexSet *idxset = [self columnIndexesInRect:prevRect];
                NSUInteger col = [idxset lastIndex];
                //NSArray * cols =[[self tableColumns]objectsAtIndexes:idxset]; //也可以取到
                NSTableColumn* colobj = [[self tableColumns] objectAtIndex:col];
                NSRange rg = [self rowsInRect:prevRect];
                NSUInteger preRow = rg.location;
                id cell = [self preparedCellAtColumn:col row:preRow];
                
                if ([delegate respondsToSelector:@selector(mouseExitTableViewCell:cell:column:row:)]) {
                    [delegate mouseExitTableViewCell:self cell:cell column:colobj row:preRow];
                }
            }
            
            enter = [self RTMouseInRect:rect withPoint:p];
            if (enter)
            {
                //NSLog(@"enter ");
                if ([delegate respondsToSelector:@selector(mouseEnterTableViewCell:cell:column:row:)]) {
                    [delegate mouseEnterTableViewCell:self cell:customcell column:theColumn row:row];
                }
            }
        }
        
        prevRect = rect;
        
    }
    else
    {
        if (![NSStringFromRect(prevRect) isEqualToString:NSStringFromRect(NSZeroRect)])
        {
            //NSLog(@"outter");
            NSIndexSet *idxset = [self columnIndexesInRect:prevRect];
            NSUInteger col = [idxset lastIndex];
            //NSArray * cols =[[self tableColumns]objectsAtIndexes:idxset]; //也可以取到
            NSTableColumn* colobj = [[self tableColumns] objectAtIndex:col];
            NSRange rg = [self rowsInRect:prevRect];
            NSUInteger preRow = rg.location;
            id cell = [self preparedCellAtColumn:col row:preRow];
           
            if ([delegate respondsToSelector:@selector(mouseExitTableViewCell:cell:column:row:)]) {
                [delegate mouseExitTableViewCell:self cell:cell column:colobj row:preRow];
            }
        }
        prevRect = NSZeroRect;
    }
    [super mouseMoved:theEvent];
}

- (void)scrollWheel:(NSEvent *)theEvent
{
    NSLog(@"wheel theEvent = %@",theEvent);
    
    [super scrollWheel:theEvent];
    //滚动时触发一下鼠标移动事件
    [self mouseMoved:theEvent];
}
下面是通过代理打印出来的信息:


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

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

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

看下效果:



具体的算法:

-(NSSize)cellSizeForBounds:(NSRect)aRect
{

    NSSize tmp = NSMakeSize(aRect.size.width, aRect.size.height);
    if (display) {
        //tmp.height = [self heightForStringDrawing:display andFont:[NSFont fontWithName:@"Helvetica" size:13] withWidth:tmp.width -20]+20;
        
        NSRect rect = [self getstringHeighInWith:tmp.width -20 byString:display];
        tmp.height = CGRectGetHeight(rect)+20;
    }
    else
    {
        tmp.height = 0;
    }
    return tmp;
}

-(NSSize)cellSize
{
    NSSize tmp = [super cellSize];
    if (display) {
        //tmp.height = [self heightForStringDrawing:display andFont:[NSFont systemFontOfSize:13] withWidth:230]+20;
        NSRect rect = [self getstringHeighInWith:tmp.width -20 byString:display];
        tmp.height = CGRectGetHeight(rect)+20;
} else { tmp.height = 0; } return tmp;}- (NSRect)getstringHeighInWith:(float)width byString:(NSString *)string{ NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [ps setLineBreakMode:NSLineBreakByCharWrapping]; ps.alignment = NSJustifiedTextAlignment; NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSColor blackColor], NSForegroundColorAttributeName, [NSFont fontWithName:@"Helvetica" size:13], NSFontAttributeName, NSParagraphStyleAttributeName,ps,nil]; NSRect rect = [string boundingRectWithSize:NSMakeSize(width, 4000) options:NSStringDrawingUsesLineFragmentOrigin attributes:primaryTextAttributes]; return rect;}


其次是在高度返回值中处理:

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{

    NSTableColumn *column = [[tableView tableColumns] objectAtIndex:0];
    NSCell *dycell = [tableView preparedCellAtColumn:0 row:row];
    NSRect cellBounds = NSZeroRect;
    cellBounds.size.width = [column width]; cellBounds.size.height = FLT_MAX;
    NSSize cellSize = [dycell cellSizeForBounds:cellBounds];
    return cellSize.height;
}

以上可以实现动态高度了,但还有一点,就是列拖动大小的时候,行的高度不变,哪怎么处理呢?幸好,tableView已为我们提供了便捷的刷新方法:

- (void)tableViewColumnDidResize:(NSNotification *)aNotification
{
    NSTableView* aTableView = aNotification.object;
    NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,aTableView.numberOfRows)];
    [aTableView noteHeightOfRowsWithIndexesChanged:indexes];
}
[aTableView noteHeightOfRowsWithIndexesChanged:indexes];

- (void)noteNumberOfRowsChanged;
我们只需要在列大小改变的时候调用就OK了,我的代码里是用窗口大小变化来触发的。具体以实际情况而定了。

问题五:

tableView自身的选中色为蓝色的。要想改变,有两种变通的方法。

1.利用NSCell进行设置,注意这种处理方法,是针对每个格子的进行设置,比如有1234列,如果每例的Cell设置得不同的时候,你会发现当选中一行时,显示为不同的选中色了。样例代码。这个用法,需要注意有表格线和没有表格线时的表示,否则你会看到蓝色线条。

//自个画,,,,,
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    BOOL elementDisabled = NO;
    NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : (elementDisabled? [NSColor disabledControlTextColor] : [NSColor textColor]);
    
	NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
                                           [NSFont systemFontOfSize:13], NSFontAttributeName, nil];
	[self.displayName.stringValue drawAtPoint:NSMakePoint(cellFrame.origin.x+cellFrame.size.height+10, cellFrame.origin.y) withAttributes:primaryTextAttributes];
    //画图
    [[NSGraphicsContext currentContext] saveGraphicsState];
    float yOffset = cellFrame.origin.y;
	if ([controlView isFlipped]) {
		NSAffineTransform* xform = [NSAffineTransform transform];
		[xform translateXBy:0.0 yBy: cellFrame.size.height];
		[xform scaleXBy:1.0 yBy:-1.0];
		[xform concat];
		yOffset = 0-cellFrame.origin.y;
	}
    
    NSImageInterpolation interpolation = [[NSGraphicsContext currentContext] imageInterpolation];
	[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
    
    [avatar.image drawInRect:NSMakeRect(cellFrame.origin.x+5,yOffset+3,cellFrame.size.height-6, cellFrame.size.height-6)
			fromRect:NSMakeRect(0,0,[avatar.image size].width, [avatar.image size].height)
		   operation:NSCompositeSourceOver
			fraction:1.0];
    
    [[NSGraphicsContext currentContext] setImageInterpolation: interpolation];
	
	[[NSGraphicsContext currentContext] restoreGraphicsState];
}

- (NSAttributedString*)getCellAttributes
{
    NSDictionary*  _attributes = [NSDictionary dictionaryWithObjectsAndKeys:_cellFontColor,NSForegroundColorAttributeName,nil];
    NSString* _cellString = [self stringValue];
    
    _cellAttributedString = [[[NSAttributedString alloc]
                              initWithString:_cellString attributes:_attributes] autorelease];
    
    return _cellAttributedString;
}

- (NSColor*)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    NSRect newRect = NSMakeRect(cellFrame.origin.x - 1, cellFrame.origin.y, cellFrame.size.width + 5, cellFrame.size.height);
    if (_cellBKColor)
    {
        [_cellBKColor set];
        NSRectFill(newRect);
    }
    
    [self setAttributedStringValue:[self getCellAttributes]];
    
    return nil;
}

第2种,也是我比较喜欢的吧,不过需要继承NSTableView来实现。

- (id)_highlightColorForCell:(id)cell;进行重写。

//重写
- (id)_highlightColorForCell:(id)cell
{
    
    if([self selectionHighlightStyle] == 1)
    {
        return nil;
    }
    else
    {
        return [NSColor redColor];//_highlightBKColor;
    }
}

问题六:

这个问题是当你绘制出来的字体,不支持鼠标选中操作。

这个问题,还没有解决,初步确认是用这四个方法进行实现,但我还没有研究透。还在找资料。(也请高手指点)

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag;
- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent;
- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength;
- (void)endEditing:(NSText *)textObj;

问题七:

对于部分字体的高亮,通常会出现在搜索时的显示结果上。哪这又是怎么处理的呢?其它也是通过属性字段进行设置不同的字体色进行Draw上来的。

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    NSColor* primaryColor   = [self isHighlighted] ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
    
    if (name && phone && highlightkey)
    {
        NSDictionary* primaryTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: primaryColor, NSForegroundColorAttributeName,
                                               [NSFont systemFontOfSize:12], NSFontAttributeName, nil];
        NSMutableAttributedString *namestring = [[NSMutableAttributedString alloc]initWithString:name attributes:primaryTextAttributes];
        
        [namestring beginEditing];
        
        NSRange namerg = [name rangeOfString:highlightkey];
        [namestring setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:namerg];
        
        NSMutableAttributedString *phonestring = [[NSMutableAttributedString alloc]initWithString:phone attributes:primaryTextAttributes];
        NSRange phonerg = [phone rangeOfString:highlightkey];
        [phonestring setAttributes:@{NSForegroundColorAttributeName:[NSColor redColor]} range:phonerg];
        NSMutableAttributedString *left = [[NSMutableAttributedString alloc]initWithString:@"(" attributes:primaryTextAttributes];
        NSMutableAttributedString *right = [[NSMutableAttributedString alloc]initWithString:@")" attributes:primaryTextAttributes];
        [namestring appendAttributedString:left];
        [namestring appendAttributedString:phonestring];
        [namestring appendAttributedString:right];
        
        NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
        [ps setLineBreakMode:NSLineBreakByTruncatingTail];
        NSRange range = NSMakeRange(0, [namestring length]);
        [namestring addAttribute:NSParagraphStyleAttributeName value:ps range:range];
        [ps release];

        [namestring endEditing];
        
        CGFloat xpos = cellFrame.origin.x+cellFrame.size.height+15;
        CGFloat w = cellFrame.size.width - xpos - 30;
        [namestring drawInRect:NSMakeRect(xpos, cellFrame.origin.y+10,w,15)];
        
        [right release];
        [left release];
        [namestring release];
        [phonestring release];
    }
    
    if (ringUser)
    {
        [ringImg drawInRect:NSMakeRect(cellFrame.origin.x+9.5,cellFrame.origin.y + 1,36, 36)
                   fromRect:NSMakeRect(0,0,ringImg.size.width, ringImg.size.height)
                  operation:NSCompositeSourceOver
                   fraction:1.0 respectFlipped:YES hints:nil];
    }
    
    if (avatar)
    {
        [[NSGraphicsContext currentContext] saveGraphicsState];
        NSRect rt = NSMakeRect(cellFrame.origin.x+12.5,cellFrame.origin.y + 4,30, 30);
        CGFloat radius = 15;
        NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:rt xRadius:radius yRadius:radius];
        [clipPath setWindingRule:NSEvenOddWindingRule];
        [clipPath addClip];
        
        [avatar drawInRect: rt
                fromRect:NSMakeRect(0,0,avatar.size.width, avatar.size.height)
               operation:NSCompositeSourceOver
                fraction:1.0 respectFlipped:YES hints:nil];
        
        [[NSGraphicsContext currentContext] restoreGraphicsState];
    }
}

其中
highlightkey就是需要设置为高亮的部分。

欢迎路过大侠多多指教。


好了,有点多,也有点杂。大家需要慢慢体会。源码我都放在:http://download.csdn.net/detail/fengsh998/6887159


马上回家过年,这是2013贺岁篇,也正好是在csdn发表文章的第100篇。记念一下。

同时也祝自己马年,天马流星,神马飞扬,马到功成,马上有想法,马上有伯乐,马上当BOSS,马上开挂,最后辛苦的一年即将过去,来年心想事成,万事如意。

好,收拾 东东,马上回家。。。。。。








展开阅读全文

Git 实用技巧

11-24
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定; 更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。 我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。 本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案例进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。 在教程中会通过大量案例进行分析,案例会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。 为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。

实用主义学Python(小白也容易上手的Python实用案例)

12-24
原价169,限时立减100元! 系统掌握Python核心语法16点,轻松应对工作中80%以上的Python使用场景! 69元=72讲+源码+社群答疑+讲师社群分享会  【哪些人适合学习这门课程?】 1)大学生,平时只学习了Python理论,并未接触Python实战问题; 2)对Python实用技能掌握薄弱的人,自动化、爬虫、数据分析能让你快速提高工作效率; 3)想学习新技术,如:人工智能、机器学习、深度学习等,这门课程是你的必修课程; 4)想修炼更好的编程内功,优秀的工程师肯定不能只会一门语言,Python语言功能强大、使用高效、简单易学。 【超实用技能】 从零开始 自动生成工作周报 职场升级 豆瓣电影数据爬取 实用案例 奥运冠军数据分析 自动化办公:通过Python自动化分析Excel数据并自动操作Word文档,最终获得一份基于Excel表格的数据分析报告。 豆瓣电影爬虫:通过Python自动爬取豆瓣电影信息并将电影图片保存到本地。 奥运会数据分析实战 简介:通过Python分析120年间奥运会的数据,从不同角度入手分析,从而得出一些有趣的结论。 【超人气老师】 二两 中国人工智能协会高级会员 生成对抗神经网络研究者 《深入浅出生成对抗网络:原理剖析与TensorFlow实现》一书作者 阿里云大学云学院导师 前大型游戏公司后端工程师 【超丰富实用案例】 0)图片背景去除案例 1)自动生成工作周报案例 2)豆瓣电影数据爬取案例 3)奥运会数据分析案例 4)自动处理邮件案例 5)github信息爬取/更新提醒案例 6)B站百大UP信息爬取与分析案例 7)构建自己的论文网站案例
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值