Adding vertical scrolling for IKImageBrowserView that is created programmatically - cocoa

I would like to create a Cocoa library Test.dylib that provides Icon view using IKImageBrowserView. I cannot create IKImageBrowserView in nib since dylib does not support Resources. So, I am creating the IKImageBrowserView programmatically as follows:
IKImageBrowserView *browser = [[IKImageBrowserView alloc]initWithFrame:[self bounds]];
Datasource *ds = [[dataSource alloc]init];
[browser setDataSource:ds];
[browser setDelegate:ds];
But, when there are more items than visible area vertical scrollers should be displayed which is not happening.
How do I support scrolling for IKImageBrowserView that is created programmatically?
I have tried the following with no positive results:
NSScrollView *scroller = [[NSScrollView alloc]initWithFrame:[self bounds]];
[scroller addSubview:browser];
How do I solve this?

You're on the right track with trying to place the IKImageBrowserView inside of a NSScrollView. However, instead of using addSubview (inherited from NSView), use setDocumentView…
NSScrollView *scroller = [[NSScrollView alloc]initWithFrame:[self bounds]];
[scroller setDocumentView:browser];
[scroller setHasVerticalScroller:YES];
The Scroll View Programming Guide has some good info in it…
NSScrollView instances provide
scrolling services to its document
view. This is the only view that an
application must provide a scroll
view. The document view is responsible
for creating and managing the content
scrolled by a scroll view.

Related

nssplitview programmatically add nsview on top

I am trying to programmatically add a NSView over a NSSplitView (to cover it). Every attempt to do this has resulted in it being added into the NSSplitview as an extra subview.
Can anyone please help?
Codes:
InfoTrainView *myView = [[[InfoTrainView alloc] initWithFrame: aFrame] autorelease];
[NSBundle loadNibNamed:#"InfoTrainView" owner:myView];
[self.windowController.splitViewBase addSubview:myView];
I believe you need to add your new view as a child to the NSSplitView's superview (ie. parent). This way it becomes a sibling to the NSSplitView and can cover it. Your current method makes the new view a child of the split view, which then sets itself up as splitting four ways.
NSView* parentView = [self.windowController.splitViewBase superview];
if (parentView)
[parentView addSubview:myView];
parentView above should get you the "content view" that is the default NSView inside of an NSWindow, which IB placed the NSSplitView inside. If parentView == nil, you can try manually adding an NSView to the window first, then putting your NSSplitView inside of that.
On a side note, your question answered my own question - how to programmatically add to the views split inside of an NSSplitView! Thanks :)

Changing the background color of an NSCollectionView

Is it a chance to programatically change the background color of NSCollectionView?
I was trying subclassing.. but not working..
#interface CollectionViewBg : NSCollectionView
in .m
[self setBackgroundColors:[NSArray arrayWithObjects:[NSColor blueColor], nil]];
In .m, remove this line :
[self setBackgroundColors:[NSArray arrayWithObjects:[NSColor blueColor], nil]];
And use this code:
- (void)drawRect:(NSRect)dirtyRect{
[[NSColor blueColor] setFill];
NSRectFill(dirtyRect);
}
Also don't forget to change class of NSCollectionView object in IB to CollectionViewBg.
Hope this helps :)
Guess subclassing isn't a great idea, because most of Cocoa controls provide various techniques to avoid subclassing in order to customize appearance and behavior.
In this particular case, you can set backgroundView property to your NSCollectionView and provide a custom view that is dedicated for drawing a custom background.
If you need to change only background color, then you can consider take advantage of the fact that collection view usually resists inside scroll view. Just set backgroundColor and drawsBackground properties of NSScrollView.
Here's a more modern solution. First, make yourself an NSView subclass that draws the effect you want to achieve. Here's a simple one that paints a block colour:
class ColouredView: NSView {
#IBInspectable var color: NSColor = .windowBackgroundColor
override func draw(_ dirtyRect: NSRect) {
color.setFill()
dirtyRect.fill()
}
}
Now go to your nib or storyboard and drag a custom view onto the left bar. We don't want it to be part of the view hierarchy, but we do want it to be listed under the view controller containing the collection view. Just drag it in below 'First Responder'. You can then set up any important properties or relationships - in my case, the background colour.
Finally, right-click your collection view and connect its 'background view' outlet to your custom view. This lets you do all the setup in your storyboard. If you like you can make your custom view #IBDesignable but I find that usually causes more trouble than it's worth.

Cocoa: NSView drawRect painting over IBOutlets

I have an NSView in IB which sits above the app window. I have a subclass of NSView (AddSource) which I assign to the NSView.
On awakeFromNib I instantiate the view:
//add a new Add Source class
addSourceView = [[AddSource alloc] initWithFrame:NSMakeRect(0.0, 959.0, 307.0, 118.0)];
[[winMain contentView] addSubview:addSourceView];
in addSourceView's drawRect method I am adding a white background to the view:
[[NSColor whiteColor] set];
NSRectFill(rect);
[self setNeedsDisplay:YES];//added this to see if it might solve the problem
In winMain's contentView I have a NSButton that when clicked slides the addSourceView onto the window:
NSRect addSourceViewFrame = [addSourceView frame];
addSourceViewFrame.origin.y = 841.0;
[[addSourceView animator] setFrame:addSourceViewFrame];
But it seems as if the app is painting over the IBOutlets I placed on the NSView in IB. If, in IB, I repoistion the NSView so that it is on screen when the app launches everything works fine, the IBOutlets are there as well as the background color.
I'm not sure why this is happening. I've done this before with no problems. I must be doing something different this time.
Thanks for any help.
*note - on the 3rd screen capture, when I say this is what the app looks like when opened, that's when I hard code the Y position of the NSView. When it is functioning correctly it should open as screen capture 1.
Most likely your buttons and custom view are siblings, i.e. they are both subviews of your window's content view. Since siblings are "Stacked" depending on the order in which they are added, when you add the view in code it is being added on top of the buttons. You should be able to fix it by explicitly specifying where the view should be positioned relative to its new siblings like so:
[[winMain contentView] addSubview:addSourceView positioned:NSWindowBelow relativeTo:nil];
which should place it below any existing subviews of your window's content view. Also, remove the setNeedsDisplay: line in drawRect, that leads to unncessary, possibly infinite, redrawing.
EDIT: OK I see what you're doing.
I would suggest creating a standalove view in the NIB by dragging a "Custom View" object into the left hand side (the vertically-aligned archived objects section) and adding your controls there, that should ensure the controls are actualy subviews of the view, then you can just create a reference to the archived view in code, and add/remove it dynamically as needed.
Honestly though, you should probably be using a sheet for these kinds of modal dialogs. Why reinvent the wheel, and make your app uglier in the process?
You added TWO AddSource views to the window. You added one in IB - this view contains your textFields and buttons that are connected to the IBOutlets and it is positioned outside the window.
Then in -awakeFromNib you create another, blank AddSource view (containing nothing) and animate it into the window.
I can't recommend highly enough the Hillegass as the best introduction to IB and the correct way to build Cocoa Apps.
Also, Assertions can be useful to make sure what you think is happening is actually what is happening.
If you are certain you added a button to your view in IB, assert it is so:-
- (void)awakeFromNib {
NSAssert( myButton, #"did i hook up the outlet?");
}
NSAssert is a macro that has zero overhead in a release build.
Calling [self setNeedsDisplay:YES] from -drawRect just causes the same -drawRect to be called again. This will give you big problems.

Clean easy way to expand window according to subviews

I'm developing an application that uses a master-detail paradigm with an NSTableView as the master and an NSView as the detail. The NSView gets populated from another NSViewController's view; I have an individual NSViewController for each of the detail views and their views are configured in XIBs. What's the cleanest way to have the main window expand only as necessary (preferably with animation) to fit the current detail view (similar to what System Preferences does)? Sorry if this is an elementary question; I'm rather new at desktop Cocoa.
Calculate the size of the window you need to accommodate your master and selected detail view. You can get the size of your detail view:
NSSize detailViewFrameSize = [[detailViewController view] frame].size;
Resize the window:
[window setFrame:frameRect display:YES animate:YES];
Add the detail subview to the specified position.
[[window contentView] addSubview:detailView];

NSTextView not refreshed properly on scrolling

I have a NSTextView with a sizeable quantity of text. Whenever I scroll however, the view isn't updated properly. There are some artifacts that remain at the top or the bottom of the view. It appears that the view doesn't refresh itself often enough. If I scroll very slowly the view updates correctly though. If I add a border to the view everything works perfectly, borderless view is the one that has a problem. Here's a link to a screenshot:
Thanks
Have you set the setDrawsBackground and copiesOnScroll propertes for either the NSScrollView or the NSClipView?
The first thing I would suggest is turning off the "draws background" property of the NSScrollView:
[myScrollView setDrawsBackground:NO];
Note that this should be set on the NSScrollView, and not on the embedded NSClipView.
The following excerpt from the documentation may be relevant:
If your NSScrollView encloses an NSClipView sending a setDrawsBackground: message with a parameter of NO to the NSScrollView has the added effect of sending the NSClipView a setCopiesOnScroll: message with a parameter of NO. The side effect of sending the setDrawsBackground: message directly to the NSClipView instead would be the appearance of “trails” (vestiges of previous drawing) in the document view as it is scrolled.
Looks like the text field isn't even in the scrolling-area... Are you sure something isnt overlapping it?
I had a similar trouble - artifacts develop when the NSTextView is embedded in another scrollview (ie. a NSTableView).
I actually turned on the setdrawsbackground, and then added a nice color to make it disappear again.
-(void)awakeFromNib{
NSScrollView *scroll = [self enclosingScrollView];
[scroll setBorderType:NSNoBorder];
[scroll setDrawsBackground:YES];
[scroll setBackgroundColor:[NSColor windowBackgroundColor]];
}
This in combination with a scrollWheel event let me use the NSTextView in a NSTableView.
-(void)scrollWheel:(NSEvent *)theEvent{
NSScrollView *scroll = [self enclosingScrollView];
[[scroll superview] scrollWheel:theEvent];
}
I had the same trouble some time ago. I don't remember how I solved it.
Try to place the NSTextView to another view if the superview is a custom view. Just to see what will happen.

Resources