Draw grid lines in NSTableView only for populated rows?
How can I draw grid lines in an NSTableView only for rows that are populated? When I set开发者_如何学JAVA the grid style mask to NSTableViewSolidHorizontalGridStyleMask, it draws grid lines for all rows whether populated or not.
I'm looking for a bit of sample code to do this.
What I found to work best for me so far is the following code. Just fool the original grid drawing code to draw only on populated rows.
Subclass NSTableView, if needed, and override drawGridInClipRect:(NSRect)clipRect as following:
- (void)drawGridInClipRect:(NSRect)clipRect
{
NSRect lastRowRect = [self rectOfRow:[self numberOfRows]-1];
NSRect myClipRect = NSMakeRect(0, 0, lastRowRect.size.width, NSMaxY(lastRowRect));
NSRect finalClipRect = NSIntersectionRect(clipRect, myClipRect);
[super drawGridInClipRect:finalClipRect];
}
In Swift 3.1 this is all that you need:
import Cocoa
class GridClipTableView: NSTableView {
override func drawGrid(inClipRect clipRect: NSRect) { }
}
I think you will have to subclass NSTableView
and override drawRow:clipRect:
. Another possibility would be overriding drawGridInClipRect:
, but that's a bit more unwieldy, because you'll have to manually pick out the rows.
This should get you going in the right direction:
- (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect {
// First do the default drawing
[super drawRow:rowIndex clipRect:clipRect];
// Check if there's content in any of the cells in this row
BOOL doesHaveContent = NO;
int numCols = [self numberOfColumns];
int colIndex;
for( colIndex = 0; colIndex < numCols; colIndex++ ){
NSCell * cell = [self preparedCellAtColumn:colIndex
row:rowIndex];
if( [cell objectValue] != nil ){
doesHaveContent = YES;
break;
}
}
if( doesHaveContent ){
NSRect rowRect = [self rectOfRow:rowIndex];
NSBezierPath * gridPath = [NSBezierPath bezierPath];
// Ignoring clipRect because this isn't a lot of drawing
[gridPath moveToPoint:rowRect.origin];
[gridPath lineToPoint:NSMakePoint(rowRect.origin.x + rowRect.size.width,
rowRect.origin.y)];
[gridPath moveToPoint:NSMakePoint(rowRect.origin.x,
rowRect.origin.y + rowRect.size.height)];
[gridPath lineToPoint:NSMakePoint(rowRect.origin.x + rowRect.size.width,
rowRect.origin.y + rowRect.size.height)];
[myGridColor set];
[gridPath stroke];
// You could also just do:
// [myGridColor set];
// [[NSBezierPath bezierPathWithRect:rowRect] stroke];
}
}
Yet another possibility would be to have a custom NSCell
; each cell could draw a special border around itself if it had content. This wouldn't draw a line across the whole row, though, if there were some cells in the row that were empty.
Neither solution listed here worked for me, for some reason. What I did instead is:
- Subclass
NSTableView
and overriderectOfColumn:
(see below). - Turn on layer backing on the table view, its clip view, and its scroll view (this is required for this solution to work).
This worked from macOS 10.9 up to 10.15 in my tests.
- (NSRect)rectOfColumn:(NSInteger)column
{
NSRect value = [super rectOfColumn:column];
NSInteger numberOfRows = [self numberOfRows];
if (numberOfRows == 0) {
value.size.height = 0;
} else {
NSRect firstRect = [self rectOfRow:0];
NSRect lastRect = [self rectOfRow:numberOfRows - 1];
value.size.height = NSMaxY(lastRect) - NSMinY(firstRect);
}
return value;
}
精彩评论