I have been reading and experimenting with allowing links in a custom drawn NSCell for the last few days and have basically got nothing usable, there's always issues with each approach.
Does anyone know of a way of doing this that works?
I am custom drawing the NSCell using - (void)drawInteriorWithFrame:(NSRect)theCellFrame inView:(NSView *)theControlViewm
The NSCell is just a variable height block of text with links inside it, some cells have links, some do not.
I've tried using nsattributedstring with NSLinkAttributeName
I've tried intercepting all hits to the cell and then trying to match up where they clicked to where the link would be in the text but that never works out.
I've basically tried all suggestions that I could find on all boards but most comments are old so I'm hoping someone has figured out a good way to do this.
Thanks, David
I haven't tried this exactly, but give this a try:
First, for hyperlinks I use a category on NSAttributedString, akin to this post from Apple developer docs. The example here gives you a method on NSAttributedString 'hyperlinkFromString:withURL:`
Second, create a delegate for the table, and implement tableView:willDisplayCell:forTableColumn:row: method.
In that method,
setAttributedStringValue:[NSAttributedString hyperlinkFromString:YOUR_STRING withURL:YOUR_URL]
or, if you need non-hyperlinked string text as well,
setAttributedStringValue:[SOME_NON_HYPERLINKED_STRING appendAttributedString:[NSAttributedString hyperlinkFromString:YOUR_STRING withURL:YOUR_URL]]
If that is the only reason you are custom drawing an NSCell, you can try getting rid of your custom class, because this should work with an NSTextFieldCell. I've seen online, though, that some people have had trouble with centering attributed strings in text field cells, so I hope it works ok. One other caveat: with the delegate method, be sure that you set the cell attribute that you are changing for all conditions. I quote:
Because aCell is reused for every row in aTableColumn, the delegate must set the display attributes both when drawing special cells and when drawing normal cells.
from "http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSTableViewDelegate_Protocol/Reference/Reference.html" (sorry, StackOverflow won't let me post more than one hyperlink yet)
Hope this helps.
Related
I am quite new to NSTableView but as I tried to get things straight, I took a look at InterfaceBuilder!!
TableView hierarchy
I understand that objects are responsible for scrolling and clipping. TableView is the real NSTableView instance. The object titled function list ist the NSTableColumn below that is my TableCellView objects. What I don't understand is the object TextCell. It doesn't seem anything to do. Even wrong colors and alike have no effect at all. I am using a view based variant. Is the TextCell solely for cell based TableViews?
I found that part not quite well documented. I am planning on building custom views for my table. So I was thinking a thorough understanding would be a good approach.
Yes, it's strange that that's still there. It's useless and has no effect on anything, but you can't delete it. Ignore it.
I've spent many hours trying to figure this one out with no luck. Someone had a similar problem on the Apple mailing lists a while ago and no one answered. Basically, it comes down to this: I've subclassed NSTextFieldCell and overridden the drawWithFrame: method to create a custom bezel. Then I call drawInteriorWithFrame: at the end of the method to draw the text. Everything works perfectly except for the fact that sometimes the text disappears. Everything else is drawn, except for the text. I think it might have something to do with the field editor, but I really don't know. Has anyone run into this problem before?
I apologize that this question wasn't better, but I feel others might run into this mysterious drawing problem someday and I have found a solution. The key to subclassing NSTextFieldCell is that when you override drawWithFrame:, you want to call [super drawWithFrame:] or else you might get these rendering problems. You can set the backgroundColor of the cell to whatever you want and use setClip to get the desired look, but you don't want to do all of the drawing yourself. At least this worked for me.
learning Cocoa can be pretty tough for web developers. Some things are so simple in HTML, and I have no idea, how to do this in Cocoa.
Let me just show you an image here, to show you what I have on my mind.
So it's kinda like a blog. Each post has variable length, so it can take up some space. Also, you're able to scroll through posts.
I was thinking about using NSTableView or NSCollectionView, but since I don't know much about Cocoa, I'm asking you for advice.
Also please do link any related articles.
Updates
So here are some things that I discovered.
I could make a subclass of NSCell and use it in Table View. I can use it, I can put there a string, something like this:
http://pastie.org/1140412
(please take a look at this code, I'm wondering if I should use awakeFromNib/setDataCell combination)
But string is not enough. I need a NSTextView. The problem is, it doesn't have method like drawInRect: withAttributes:. So I don't know how to draw it into that cell. I guess I'm missing some basics here, so I'm just gonna study some Cocoa views now.
Any ideas are welcome.
You want to use a NSTableView. And I will recommend to take a look/glance at NSTableView, NSTableViewDelegate and NSTableViewDataSource docs:
http://developer.apple.com/mac/library/documentation/cocoa/reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
http://developer.apple.com/mac/library/documentation/cocoa/reference/NSTableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40008622
http://developer.apple.com/mac/library/documentation/cocoa/reference/ApplicationKit/Protocols/NSTableDataSource_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40004178
You choose the object you want to be your datasource depending on the data you have.
The delegate is the object that helps you to so some settings, like rows, groups, cells, etc.
There are useful methods of NSTableViewDelegate you want to implement like – tableView:heightOfRow:
and just google NSTableView tutorial or something, there are many good examples ;)
You could just use a WebView and write it in HTML.
Look at http://mattgemmell.com/source for an example: the Skinnable App one.
I am trying to create a view for a kind of brainstorming application like, for example, OmniGraffle, with elements that contain textviews and can be dragged around. (Also, the should be connectable with arrows, but that is not (yet) the problem)
I did my homework and searched via google and read books about cocoa, but there seems to be no similar example around.
Since I am also new to cocoa, I’m a bit helpless here.
The thing I am sure of is, that I need a custom view in which I can create my elements - what I tried until now to do that is:
First, I searched for the syntax to add subwindows to a window to create my elements. Subwindows, I imagined, would automatically be movable and come to front and so on.
The problem: As the experienced Cocoa-programmers of you probably are not surprised, I was stunned to find nothing about anything like that - this seems to be something, that is just not intended in Cocoa?!
Then I thought about creating subviews that contain a custom view for the title bar drawing (where the user can click to drag the element) and a NSTextView.
Problems:
I read, that it is not so clever to create dozens of subviews in a window because that would be very slow (or would that be not so bad in this case because all the subviews would be instances of always the same class?).
Also I can’t find out how to load a subview from a nib- or xib-file. Would I need a viewController? Or would that make the dozens-of-instances-problem even worse?
And Apple tells you not to overlap subviews (okay, that would be not so important, but I really wonder how the guys at OmniGroup made OmniGraffle...)
Because of that, I now wanted to do the title-bar-drawing in the surrounding custom view and create the textview programmatically (as I understand, a text-“view“ ist not really a view and takes its functionality from NSCell to reduce all the effort with the views?).
Problems:
Even that failed because I was not able to create a textview that doesn’t fill the complete window (the initWithFrame: of the [[NSScrollView alloc] initWithFrame: aRect] just seems to be ignored or do I get that wrong?).
Also, there should be some buttons on each element in the final application. I imagine that would be easier to accomplish with a subview from a nib-file for each element?
Well, now that nothing works and the more I read, the more problems seem to occur, I am pretty confused and frustrated.
How could I realize such a program? Could someone please push me in the right direction?
I created a class for the draggable elements where I save position, size and text in instance variables. In my view, every new element instance is added to an array (for now, this works without a controller). The array is used to draw all the elements in a loop in drawRect:. For the text of the element I just use a NSTextFieldCell which is set to the saved text from every element in the same loop.
That way it is also possible to overlap the elements.
If you wanted to implement a highlighting for specific substrings in a NSTextField like on the screenshot (Tweetie.app) how would you do it? :)
Tweetie Link Highlighting http://qkpic.com/88c61
Thanks for your help!
For an NSTextField, note that it's an NSTextFieldCell that does the drawing. You'll want to override -drawInteriorWithFrame:inView: and do the string drawing yourself. The challenge will be finding the rectangles (more than one if the range is wrapped) in which your substring is drawn. You'll end up having to use NSLayoutManager and an NSTextStorage container.
Best to use an NSTextView. The associated NSLayoutManager and NSTextStorage components are already pre-assembled and you get a lot of other functionality for free. Most importantly, there's a convenient -[NSTextView drawViewBackgroundInRect:] method so you don't have to subclass anything. You just ask the text view for its layout manager and text storage, then ask it for the rectangles for the given range. See the Text System Overview and linked documents for more details.
To find the interesting substrings efficiently, you might use custom attributes (or the built-in ones such as NSLinkAttributeName) for your interesting ranges.
An alternative to consider is an editable WebView where you can build the custom attributes with CSS.