Is there a "right" way to have NSTextFieldCell draw vertically centered text? - cocoa

I have an NSTableView with several text columns. By default, the dataCell for these columns is an instance of Apple's NSTextFieldCell class, which does all kinds of wonderful things, but it draws text aligned with the top of the cell, and I want the text to be vertically centered in the cell.
There is an internal flag in NSTextFieldCell that can be used to vertically center the text, and it works beautifully. However, since it is an internal flag, its use is not sanctioned by Apple and it could simply disappear without warning in a future release. I am currently using this internal flag because it is simple and effective. Apple has obviously spent some time implementing the feature, so I dislike the idea of re-implementing it.
So; my question is this: What is the right way to implement something that behaves exactly like Apple's NStextFieldCell, but draws vertically centered text instead of top-aligned?
For the record, here is my current "solution":
#interface NSTextFieldCell (MyCategories)
- (void)setVerticalCentering:(BOOL)centerVertical;
#end
#implementation NSTextFieldCell (MyCategories)
- (void)setVerticalCentering:(BOOL)centerVertical
{
#try { _cFlags.vCentered = centerVertical ? 1 : 0; }
#catch(...) { NSLog(#"*** unable to set vertical centering"); }
}
#end
Used as follows:
[[myTableColumn dataCell] setVerticalCentering:YES];

The other answers didn't work for multiple lines. Therefore I initially continued using the undocumented cFlags.vCentered property, but that caused my app to be rejected from the app store. I ended up using a modified version of Matt Bell's solution that works for multiple lines, word wrapping, and a truncated last line:
-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSAttributedString *attrString = self.attributedStringValue;
/* if your values can be attributed strings, make them white when selected */
if (self.isHighlighted && self.backgroundStyle==NSBackgroundStyleDark) {
NSMutableAttributedString *whiteString = attrString.mutableCopy;
[whiteString addAttribute: NSForegroundColorAttributeName
value: [NSColor whiteColor]
range: NSMakeRange(0, whiteString.length) ];
attrString = whiteString;
}
[attrString drawWithRect: [self titleRectForBounds:cellFrame]
options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin];
}
- (NSRect)titleRectForBounds:(NSRect)theRect {
/* get the standard text content rectangle */
NSRect titleFrame = [super titleRectForBounds:theRect];
/* find out how big the rendered text will be */
NSAttributedString *attrString = self.attributedStringValue;
NSRect textRect = [attrString boundingRectWithSize: titleFrame.size
options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin ];
/* If the height of the rendered text is less then the available height,
* we modify the titleRect to center the text vertically */
if (textRect.size.height < titleFrame.size.height) {
titleFrame.origin.y = theRect.origin.y + (theRect.size.height - textRect.size.height) / 2.0;
titleFrame.size.height = textRect.size.height;
}
return titleFrame;
}
(This code assumes ARC; add an autorelease after attrString.mutableCopy if you use manual memory management)

Overriding NSCell's -titleRectForBounds: should do it -- that's the method responsible for telling the cell where to draw its text:
- (NSRect)titleRectForBounds:(NSRect)theRect {
NSRect titleFrame = [super titleRectForBounds:theRect];
NSSize titleSize = [[self attributedStringValue] size];
titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height) / 2.0;
return titleFrame;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSRect titleRect = [self titleRectForBounds:cellFrame];
[[self attributedStringValue] drawInRect:titleRect];
}

For anyone attempting this using Matt Ball's drawInteriorWithFrame:inView: method, this will no longer draw a background if you have set your cell to draw one. To solve this add something along the lines of
[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);
to the beginning of your drawInteriorWithFrame:inView: method.

FYI, this works well, although I haven't managed to get it to stay centered when you edit the cell... I sometimes have cells with large amounts of text and this code can result in them being misaligned if the text height is greater then the cell it's trying to vertically center it in. Here's my modified method:
- (NSRect)titleRectForBounds:(NSRect)theRect
{
NSRect titleFrame = [super titleRectForBounds:theRect];
NSSize titleSize = [[self attributedStringValue] size];
// test to see if the text height is bigger then the cell, if it is,
// don't try to center it or it will be pushed up out of the cell!
if ( titleSize.height < theRect.size.height ) {
titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height) / 2.0;
}
return titleFrame;
}

No. The right way is to put the Field in another view and use auto layout or that parent view's layout to position it.

Though this is pretty old question...
I believe default style of NSTableView implementation is intended strictly for single line text display with all same size & font.
In that case, I recommend,
Set font.
Adjust rowHeight.
Maybe you will get quietly dense rows. And then, give them padding by setting intercellSpacing.
For example,
core_table_view.rowHeight = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4;
core_table_view.intercellSpacing = CGSizeMake(10, 80);
Here what you'll get with two property adjustment.
This won't work for multi-line text, but very good enough for quick vertical center if you don't need multi-line support.

I had the same problem and here is the solution I did :
1) In Interface Builder, select your NSTableCellView. Make sure it as big as the row height in the Size Inspector. For example, if your row height is 32, make your Cell height 32
2) Make sure your cell is well placed in your row (I mean visible)
3) Select your TextField inside your Cell and go to your size inspector
4) You should see "Arrange" item and select "Center Vertically in Container"
--> The TextField will center itself in the cell

Related

How to do batch display using NSTextView

I'd like to be able to show a view that resembles something like a console log, with multiple lines of text that are scrollable and selectable.
The fundamental procedure I have in mind is maintaining an array of strings (call it lines) and appending these to the textStorage of the NSTextView using a new line character as delimiter.
However there are a few factors to consider, such as:
Updating the textStorage on scroll so that it appears seamless to the user
Updating the textStorage on resizing the view height
Maintaining scroll position after the textStorage gets updated
Handling an out of memory possibility
Can someone please provide some guidance or a sample to get me started?
Add a string from your array to the NSTextStorage and animate the NSClipView bounds origin.
- (void)appendText:(NSString*)string {
// Add a newline, if you need to
string = [NSString stringWithFormat:#"%#\n", string];
// Find range
[self.textView.textStorage replaceCharactersInRange:NSMakeRange(self.textView.textStorage.string.length, 0) withString:string];
// Get clip view
NSClipView *clipView = self.textView.enclosingScrollView.contentView;
// Calculate the y position by subtracting
// clip view height from total document height
CGFloat scrollTo = self.textView.frame.size.height - clipView.frame.size.height;
// Animate bounds
[[clipView animator] setBoundsOrigin:NSMakePoint(0, scrollTo)];
}
If you have elasticity set in your NSTextView you need to monitor for its frame changes to get exact results. Add frameDidChange listener to your text view and animate in the handler:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Text view setup
[_textView setPostsFrameChangedNotifications:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(scrollToBottom) name:NSViewFrameDidChangeNotification object:_textView];
}
- (void)appendText:(NSString*)string {
// Add a newline, if you need to
string = [NSString stringWithFormat:#"%#\n", string];
// Find range
[self.textView.textStorage replaceCharactersInRange:NSMakeRange(self.textView.textStorage.string.length, 0) withString:string];
}
- (void)scrollToBottom {
// Get the clip view and calculate y position
NSClipView *clipView = self.textView.enclosingScrollView.contentView;
// Y position for bottom is document's height - viewport height
CGFloat scrollTo = self.textView.frame.size.height - clipView.frame.size.height;
[[clipView animator] setBoundsOrigin:NSMakePoint(0, scrollTo)];
}
In real-life application you would probably need to set some sort of threshold to see if the user has scrolled away from the end more than the height of a line.

NSTextFieldCell's cellSizeForBounds: doesn't match wrapping behavior?

It seems to be commonly accepted that cellSizeForBounds: allows one to calculate a text field's "natural" size. However, for NSTextField, I've found that it doesn't quite match:
#interface MyTextField : NSTextField #end
#implementation MyTextField
- (void)textDidChange:(NSNotification *)notification {
[super textDidChange:notification];
[self validateEditing]; // Forces updating from the field editor
NSSize cellSize = [self.cell cellSizeForBounds:
NSMakeRect(0, 0, self.bounds.size.width, CGFLOAT_MAX)];
NSRect frame = self.frame;
CGFloat heightDelta = cellSize.height - frame.size.height;
frame.size.height += heightDelta;
if (!self.superview.flipped) { frame.origin.y -= heightDelta; }
self.frame = frame;
}
#end
(Note that I'm not using Auto Layout, but the principle is the same. This problem doesn't happen with every string, but it is pretty easy to reproduce.)
I suspect this is because of the text field's border, which adds an extra offset. Is there any way to automatically compute the relationship between cellSizeForBounds: and the NSTextField's frame? How else might I solve this issue?
There is a difference between the cell size and the frame size. The best way to determine it is to ask a text field to size itself to its content using -sizeToFit and then compare its cell size to its frame size. You may want to do this with a secondary, off-screen text field. Be sure to configure all of its parameters identically to the text field you're intending to resize. Also, the cell size will be an "exact" fit, meaning it will potentially have fractional width or height. The frame size resulting from -sizeToFit will be integral. So, you should apply ceil() to the cell size components before comparing to the frame size to compute the border size.
In theory, you only have to do this once for a given text field configuration / style.

How to move to the right the label Core Plot?

I use the following method to display the labels for my plot:
-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index{
...
CPTTextLayer *label=[[CPTTextLayer alloc] initWithText:stringValue style:textStyle];
}
which for every index should return the label
I know that it's possible to move label up or down using:
plot.labelOffset=10;
The question is: how can i move the label a bit to the right?
I tried to use
label.paddingLeft=50.0f;
but it doesn't work.
Adding padding as in your example does work, but maybe not in the way you expect. Scatter and bar plots will center the label above each data point (with a positive offset). The padding makes the whole label wider so when centered, the test appears off to the side. It's hard to control, especially if the label texts are different lengths.
There is an outstanding issue to address this (issue 266). No guarantees when it will be fixed, but it is something we're looking at.
I ran into the same problem and came up with a different solution.
What I decided to do was to create the label using the CPTAxisLabel method initWithContentLayer:
CPTTextLayer *textLayer = [[CPTTextLayer alloc] initWithText:labelStr style:axisTextStyle];
CGSize textSize = [textLayer sizeThatFits];
// Calculate the padding needed to center the label under the plot record.
textLayer.paddingLeft = barCenterLeftOffset - textSize.width/2.0;
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithContentLayer:textLayer];
Here barCenterLeftOffset is the offset of the center of the plot record.
I wrote an article about this:
http://finalize.com/2014/09/18/horizontal-label-positioning-in-core-plot-and-other-miscellaneous-topics/
A demo project I created that uses this solution can be found at:
https://github.com/scottcarter/algorithms
You can subclass CPTTextLayer and include an offset.
#interface WPTextLayer : CPTTextLayer
#property (nonatomic) CGPoint offset;
#end
#implementation WPTextLayer
-(void)setPosition:(CGPoint)position
{
CGPoint p = CGPointMake(position.x + self.offset.x, position.y + self.offset.y);
[super setPosition:p];
}
Then Use:
WPTextLayer *tLayer = [[WPTextLayer alloc] initWithText:#"blah" style:textStyle];
tLayer.offset = CGPointMake(3, -3);
return tLayer;
There may be consequences of this that I'm not aware of, but it seems to be working so far.

NSSplitView: Controlling divider position during window resize

I have an NSSplitView that's having two panes - a sidebar table view on the left and a web view on the right one. I also have a delegate set that's handling constraints for the sidebar like this:
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex {
return 500.0f;
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
return 175.0f;
}
- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview {
return NO;
}
It means that the sidebar can only be resized between 175 and 500 pixels and this works fine when using the divider handle. But when resizing the whole window the divider gets repositioned out of these constraints.
Does anybody know how to control this?
Additionally: If I want to store the user's choice of sidebar width, is it a good thought to read it out, save it to a preferences file and restore it later, or is there a more straight-forward way to do this? I noticed that the window's state gets saved in some cases - is this generally happening or do I have to control it?
Thanks in advance
Arne
I initially implemented the NSSplitView delegate functions and ended up with a lot of code to try to do something so simple as limit the minimum size for each of the split view sides.
I then changed my approach and found a clean and extremely simply solution. I simply set a auto layout constant for a width (>= to my desired minimum size) on the NSView for one side of the NSSplitView. I did the same on my other side. With these two simple constraints the NSSplitView worked perfectly without the need for delegate calls.
What you are looking for is:
- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize
[sender frame] will be the new size of your NSSplitView after the resize. Then just readjust your subviews accordingly.
The problem is that when the NSSplitView itself is resized, -adjustSubviews gets called to do the work, but it plain ignores the min/max constraints from the delegate!
However -setPosition:ofDividerAtIndex: does take the constraints into account.
All you need to do is combine both - this example assumes an NSSplitView with only 2 views:
- (CGFloat)splitView:(NSSplitView*)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
return 300;
}
- (CGFloat)splitView:(NSSplitView*)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
return (splitView.vertical ? splitView.bounds.size.width : splitView.bounds.size.height) - 500;
}
- (void)splitView:(NSSplitView*)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
[splitView adjustSubviews]; // Use default resizing behavior from NSSplitView
NSView* view = splitView.subviews.firstObject;
[splitView setPosition:(splitView.vertical ? view.frame.size.width : view.frame.size.height) ofDividerAtIndex:0]; // Force-apply constraints afterwards
}
This appears to work fine on OS X 10.8, 10.9 and 10.10, and is much cleaner than the other approaches as it's minimal code and the constraints are not duplicated.
An alternative way to solve this is using splitView:shouldAdjustSizeOfSubview:
I've found this much simpler for my purposes.
For example, if you want to prevent the sidebarTableView from ever being smaller than your 175 minimum width then you can do something like this (assuming you made sidebarTableView an outlet on your view controller/delegate);
- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
{
if ((subview==self.sidebarTableView) && subview.bounds.size.width<=175) {
return NO;
}
return YES;
}
Here's my implementation of -splitView:resizeSubviewsWithOldSize::
-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
if (![splitView isSubviewCollapsed:self.rightView] &&
self.rightView.frame.size.width < 275.0f + DBL_EPSILON) {
NSSize splitViewFrameSize = splitView.frame.size;
CGFloat leftViewWidth = splitViewFrameSize.width - 275.0f - splitView.dividerThickness;
self.leftView.frameSize = NSMakeSize(leftViewWidth,
splitViewFrameSize.height);
self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
0.0f,
275.0,
splitViewFrameSize.height);
} else
[splitView adjustSubviews];
}
In my case, rightView is the second of two subviews, which is collapsible with a minimum width of 275.0. leftView has no minimum or maximum and is not collapsible.
I used
- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize
but instead of changing the subview frame, I used
[sender setPosition:360 ofDividerAtIndex:0]; //or whatever your index and position should be
Changing the frame didn't give me consistent results. Setting the position of the divider did.
Maybe too late for the party, however this is my implementation of resizeSubviewWithOldSize:. In my project I need a vertical resizable NSplitView with leftView width between 100.0 and 300.0; no 'Collapsing' taken in account. You should take care of all possible dimensions for the subviews.
-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
if (self.leftView.frame.size.width >= kMaxLeftWidth) {
NSSize splitViewFrameSize = splitView.frame.size;
CGFloat leftViewWidth = kMaxLeftWidth;
CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;
self.leftView.frameSize = NSMakeSize(leftViewWidth,
splitViewFrameSize.height);
self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
0.0f,
rightViewWidth,
splitViewFrameSize.height);
} else if (self.leftView.frame.size.width <= kMinLeftWidth) {
NSSize splitViewFrameSize = splitView.frame.size;
CGFloat leftViewWidth = kMinLeftWidth;
CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;
self.leftView.frameSize = NSMakeSize(leftViewWidth,
splitViewFrameSize.height);
self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
0.0f,
rightViewWidth,
splitViewFrameSize.height);
} else {
NSSize splitViewFrameSize = splitView.frame.size;
CGFloat leftViewWidth = self.leftView.frame.size.width;
CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;
self.leftView.frameSize = NSMakeSize(leftViewWidth,
splitViewFrameSize.height);
self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
0.0f,
rightViewWidth,
splitViewFrameSize.height);
}
}
I've achieved this behavior by setting the holdingPriority on NSSplitViewItem to Required(1000) for the fixed side in Interface Builder. You can then control the width for the fixed side by setting a constraint on the underlying NSView.
I just needed to do this, and came up with this method which is a bit simpler than previous examples. This code assumes there are IBOutlets for the left and right NSScrollViews of the NSSplitView container, as well as CGFloat constants for the minimum size of the left and right views.
#pragma mark - NSSplitView sizing override
//------------------------------------------------------------------------------
// This is implemented to ensure that when the window is resized that our main table
// remains at it's smallest size or larger (the default proportional sizing done by
// -adjustSubviews would size it smaller w/o -constrainMinCoordiante being called).
- (void) splitView: (NSSplitView *)inSplitView resizeSubviewsWithOldSize: (NSSize)oldSize
{
// First, let the default proportional adjustments take place
[inSplitView adjustSubviews];
// Then ensure that our views are at least their min size
// *** WARNING: this does not handle allowing the window to be made smaller than the total of the two views!
// Gather current sizes
NSSize leftViewSize = self.leftSideView.frame.size;
NSSize rightViewSize = self.rightSideView.frame.size;
NSSize splitViewSize = inSplitView.frame.size;
CGFloat dividerWidth = inSplitView.dividerThickness;
// Assume we don't have to resize anything
CGFloat newLeftWidth = 0.0f;
// Always adjust the left view first if we need to change either view's size
if( leftViewSize.width < kLeftSplitViewMinSize )
{
newLeftWidth = kLeftSplitViewMinSize;
}
else if( rightViewSize.width < kRightSplitViewMinSize )
{
newLeftWidth = splitViewSize.width - (kRightSplitViewMinSize + dividerWidth);
}
// Do we need to adjust the size?
if( newLeftWidth > 0.0f )
{
// Yes, do so by setting the left view and setting the right view to the space left over
leftViewSize.width = newLeftWidth;
rightViewSize.width = splitViewSize.width - (newLeftWidth + dividerWidth);
// We also need to set the origin of the right view correctly
NSPoint origin = self.rightSideView.frame.origin;
origin.x = splitViewSize.width - rightViewSize.width;
[self.rightSideView setFrameOrigin: origin];
// Set the the ajusted view sizes
leftViewSize.height = rightViewSize.height = splitViewSize.height;
[self.leftSideView setFrameSize: leftViewSize];
[self.rightSideView setFrameSize: rightViewSize];
}
}

Draw Lines Diagonally in a particular NSTableview cell

Is there a way to draw lines diagonally in NSTableview cell.Can u please post sample to do this.I am new to the Mac development.Please help me in this issue.
Thanks in advance.......
Yes, easily.
You need to create a subclass of NSTextFieldCell which is actually the type of cell a NSTableView uses to display text.
Subclassing an class creates a new version of that class that does all that the original class did plus more.
This is using Xcode 4. If you are using Xcode 3 let me know.
In Xcode, create a new file by choosing File > New > New File...
In the sheet that pops up choose Objective-C Class and hit Next.
Make it a subclass of NSTextFieldCell, which is what we will be making a modified copy of. Hit Next.
You can save it as anything you want, but for the purposes of this tutorial, save it as MyDiagonalLinedTextFieldCell. Hit Save.
Two new files should pop up.
Click on the .m file. This is the implementation file that tells what the methods in the class do.
Its contents should be similar to below:
//
// MyDiagonalLinedTextFieldCell.m
// CustomCell
//
// Created by spudwaffle on 7/4/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "MyDiagonalLinedTextFieldCell.h"
#implementation MyDiagonalLinedTextFieldCell
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
#end
Below the init method add a drawInteriorWithFrame: inView: method.
The application calls the drawInteriorWithFrame: inView: method each time the cell needs to render on screen.
Your code should now look like this:
#implementation MyDiagonalLinedTextFieldCell
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
}
#end
The first thing you need to do is just draw a standard NSTextFieldCell.
This can be done by calling:
[super drawInteriorWithFrame:cellFrame inView:controlView];
This draws a normal NSTextFieldCell in the exact area the program wants it to.
Now, we need to draw our custom lines. Let's put them 5 pixels apart and make them 1 pixel wide.
This calls for a for loop!
for (int i = 0; i < cellFrame.size.width/5; i ++) {
}
This makes a int that equals 0,adds to that count every time the loop runs, and stops when i reaches the amount of lines that need to be drawn.
Next, put in the drawing code to draw the lines.
for (int i = 0; i < cellFrame.size.width/5; i ++) {
NSBezierPath *path = [NSBezierPath bezierPath];
[path moveToPoint:NSMakePoint(i * 5, cellFrame.origin.y)];
[path lineToPoint:NSMakePoint((i * 5) + 2, cellFrame.origin.y + cellFrame.size.height)];
[[NSColor grayColor]set];
[path setLineWidth:1];
[path stroke];
}
This:
Creates an NSBezierPath, which is used to draw lines and shapes.
Moves the start of the path to the bottom edge of the cell.
Draws a line to the top edge of the cell.
Sets the drawing color to gray.
Sets the drawing line width to 1.
Draws the line.
It does this over and over for each line thanks to the for loop.
Here is the completed MyDiagonalLinedTextFieldCell.m file. You don't need to worry about the .h one for now.
#import "MyDiagonalLinedTextFieldCell.h"
#implementation MyDiagonalLinedTextFieldCell
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
[super drawInteriorWithFrame:cellFrame inView:controlView];
for (int i = 0; i < cellFrame.size.width/5; i ++) {
NSBezierPath *path = [NSBezierPath bezierPath];
[path moveToPoint:NSMakePoint(i * 5, cellFrame.origin.y)];
[path lineToPoint:NSMakePoint((i * 5) + 2, cellFrame.origin.y + cellFrame.size.height)];
[[NSColor grayColor]set];
[path setLineWidth:1];
[path stroke];
}
}
#end
Now, we need to set the cells in the table view to use this class.
Click on your MainMenu.xib file.
Click on the cell in a row of your table view until it turns blue.
Then, hit the button in the right side bar that looks like so:
Change the Class to MyDiagonalLinedTextFieldCell and hit enter.
Now hit run and enjoy the fruits of your labor!
Mess with the drawing code until you get the exact kind of lines you want.
Feel free to contact me with any questions.
This is a beautiful answer, and very well presented. Still, I tried it, and it seems to be incomplete or inaccurate. I have 4 columns in my NSTableView, and apply the custom cell to just the right one - for some reason only the FIRST (left) column gets the special diagonals drawn, no matter what I do.
It seems that the logic in your drawing code is missing some step of "aligning to the positional column" which I really don't know how to do.
you could also improve the sample by only introducing the custom cell .m once - and adding the .h to accompany it - thus demonstrating the inheritance.

Resources