I have an NSScrollView inside an NSWindow, but it seems to be disabled. It looks like it would work, but the scrollbars are unresponsive to the mouse or the scroll wheel.
When I put the exact same NSScrollView inside a window on a new XCode project, it works perfect. There is something about the way I am making the window that is preventing the scroll from working.
I've been able to simplify it to this example:
//Make a window
NSWindow* myWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(300, 300, 300, 300)
styleMask:NSTitledWindowMask
backing:NSBackingStoreRetained
defer:NO];
//Make a scroll view
NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)];
[scrollview setHasVerticalScroller:YES];
[scrollview setAcceptsTouchEvents:YES];
[myWindow setContentView:scrollview];
//Add something big to the scroll view
NSButton* btn = [[[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 600, 900)] autorelease];
[scrollview setDocumentView:btn];
//Show the window
[NSApp arrangeInFront:self];
[myWindow makeKeyAndOrderFront:self];
[NSApp activateIgnoringOtherApps:YES];
Any ideas?
Your problem, based on some experimentation I just did, seems to be with specifying NSBackingStoreRetained. The docs say:
You should not use this mode. It combines the limitations of NSBackingStoreNonretained with the memory use of NSBackingStoreBuffered.
They also say:
In Mac OS X 10.5 and later, requests for retained windows will result in the window system creating a buffered window, as that better matches actual use.
This does not seem to be accurate; switching the buffer: argument to NSBackingStoreBuffered made the window and scroll view behave as expected for me. (The docs also say not to use NSBackingStoreNonRetained, and indeed, it seemed to have problems similar to NSBackingStoreRetained.)
Related
I've programmed a custom UI which looks like this: http://www.youtube.com/watch?v=XLsrVVhEs94
Currently it is only working within a NSView itself but I want it to show up in every corner of my screen.
So I programmatically created an NSWindow like so [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered
defer:NO];
This works great but there is a problem: Every time I open this UI I can barley see that the NSWindow was just created. I can see a shadow that has the size of the NSWindow and after that it disappears (because of [NSColor clearColor]). I think that [NSColor clearColor] applies too slow to the just created NSWindow.
The NSWindow was set up with [window setOpaque:NO] so it is transparent.
Is there another way to display a custom UI somewhere on my screen?
- Timo
I think you want to set the defer to YES. Referring to the documentation, the defer property will either create the window immediately, or defer it until it is displayed on the screen. In this case you can then set all the window properties, add subviews, etc before showing on the screen.
NSWindow *myWin = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
... do window setup here ...
[myWin orderFront:self];
Additionally if that still flickers, you can call 'display' on the window so it draws all the subviews into it's buffer first (including your clear), then call orderFront.
I want my app to be displayed on both laptop screen and an external screen with two separated NSWindow, I can't find any document about how to implement it. Any hint?
Thanks
The OS X OpenGL Programming Guide shows the old way of making a full-screen window:
Create a screen-sized window on the display you want to take over:
NSRect mainDisplayRect = [[NSScreen mainScreen] frame];
NSWindow *fullScreenWindow = [[NSWindow alloc] initWithContentRect: mainDisplayRect styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered defer:YES];
Set the window level to be above the menu bar.:
[fullScreenWindow setLevel:NSMainMenuWindowLevel+1];
Perform any other window configuration you desire:
[fullScreenWindow setOpaque:YES];
[fullScreenWindow setHidesOnDeactivate:YES];
Create a view with a double-buffered OpenGL context and attach it to the window:
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
NSRect viewRect = NSMakeRect(0.0, 0.0, mainDisplayRect.size.width, mainDisplayRect.size.height);
MyOpenGLView *fullScreenView = [[MyOpenGLView alloc] initWithFrame:viewRect pixelFormat: pixelFormat];
[fullScreenWindow setContentView: fullScreenView];
Show the window:
[fullScreenWindow makeKeyAndOrderFront:self];
You can use this method to create windows on each screen that you want to draw to. If you use this to create a window on only one screen, the other screen will continue to function normally, instead of being blacked out or covered in a stupid linen texture. Depending on your use, you may not want to setHidesOnDeactivate.
There are also lower-level APIs to take control of a screen completely and prevent the OS or any other application from drawing to the screen, but their use is seldom justified.
EDIT: If you want to have one GL context with the render spanning multiple screens, you need to create a single window with a NSRect that spans all the screens. If the screen resolutions aren't matched, this may result in part of your window not being visible, and low-end graphics chips may have some problems.
I am programmatically creating a NSTextView to be the contentView for a window. When I create a WebView using the following code, it displays scrollbars, and the resizing thumb, and resizing the window works flawlessly.
When I comment out the WebView and attempt to use a NSTextView as the contentView, it does not "work" when the window is resized: Resizing the window using the thumb causes the content of the text view to not repaint correctly, it also paints over the title of the window, and the resizing thumb is also not repainted.
-(void)applicationDidFinishLaunching:(NSNotification*)aNotification{
NSTextView* view = [[NSTextView alloc] initWithFrame:[window frame]];
// WebView* view = [[WebView alloc] initWithFrame:[window frame]];
[window setContentView:view];
[window makeFirstResponder:view];
[window makeKeyAndOrderFront:view];
}
Edit: Working code. Creates a NSScrollView to be the windows new contentView, and adds an NSTextView as its document.
-(void)applicationDidFinishLaunching:(NSNotification*)aNotification{
NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[window frame]];
NSTextView* view = [[NSTextView alloc] initWithFrame:[scrollView bounds]];
[window setContentView:scrollView];
[scrollView setDocumentView:view];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:YES];
[window makeFirstResponder:view];
[window makeKeyAndOrderFront:view];
}
A web view makes and manages its own scrollers and is a special case rather than the norm. An NSTextView does not. It's just the text view. This is the norm - scrollable views come pre-wrapped in an NSScrollView only in the convenience of Interface Builder. In code, you must create an NSScrollView as well, then wrap the view in it. It's the scroll view that would be your top-level view in that case.
I noticed something that has never been a problem before.
I did a project for iPad where I used several UIPickerView positioned next to each other, horizontally. Here they respect the CGRect frame I initialize them with, meaning placing other elements on either side of them was no problem.
Now I am trying to do this on an iPhone project and here a UIPickerView insists on being the only element. It sizes it self to fill the screen horizontally, with the "around" graphics.
I tried different approaches, place the UIPickerView inside a different view then sizing that super view, that just leads to clipping, not resizing. Another thing is that the UIPicker insists on being placed in the center of the screen. This basically means that when a UIPickerView is added to the screen, even though its single component is only 70 px wide, those 320 px of the screen is used up.
What I am trying to accomplish is to have a UIPicker on the right side of the screen and a button to the left of it.
Am I overlooking something obvious here? Hope someone could lend a hand, thanks in advance:)
Nothing more complicated than this:
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 250.0f, 165.0f)];
UIPickerView *picker = [[UIPickerView alloc] initWithFrame:container.frame];
[picker setDelegate:self];
[picker setDataSource:self];
[container addSubview:picker];
the frame I set, is not respected. It takes up all horizontal space.
I tried your code with the same result.
However, you can set the frame after the picker has been created and added to your container, and the new size is respected. Here's my test case, which works for me using SDK 4.2, in the iPhone simulator:
- (void)viewDidLoad {
[super viewDidLoad];
UIPickerView* pv = [[[UIPickerView alloc] initWithFrame: CGRectMake(160, 100, 100, 216) ] autorelease];
pv.delegate = self;
pv.dataSource = self;
[self.view addSubview: pv];
pv.frame = CGRectMake(10, 10, 100, 216);
}
The iPhone Application Programming Guide shows an example labelled "Listing 2-1 Creating a window with views" (see below). This shows how to create and add two subviews to a window.
I am using a similar pattern=. This works correctly, both windows get displayed.
The problem I am having is to get it to recognize and do rotation. I have added the shouldAutorotateInterfaceOrientation methods to do a return YES. These are being seen. But only one of the views gets rotated.
More specifically the last view to be added gets rotated and the previous one does not. I can get either to rotate by having it as the second addsubview. But cannot get both to rotate. (Testing in the Iphone simulator.)
Any suggestions on what is needed to get both views to rotate correctly?
Here is Apples sample code.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the window object and assign it to the
// window instance variable of the application delegate.
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.backgroundColor = [UIColor whiteColor];
// Create a simple red square
CGRect redFrame = CGRectMake(10, 10, 100, 100);
UIView *redView = [[UIView alloc] initWithFrame:redFrame];
redView.backgroundColor = [UIColor redColor];
// Create a simple blue square
CGRect blueFrame = CGRectMake(10, 150, 100, 100);
UIView *blueView = [[UIView alloc] initWithFrame:blueFrame];
blueView.backgroundColor = [UIColor blueColor];
// Add the square views to the window
[window addSubview:redView];
[window addSubview:blueView];
// Once added to the window, release the views to avoid the
// extra retain count on each of them.
[redView release];
[blueView release];
// Show the window.
[window makeKeyAndVisible];
}
This question was abandoned, sadly...
I would love to find the answer to that, as it causes alot of problems on the iPad SDK... adding more than 1 subview at a forced landscape mode, will only make one rotated view.
Causing alot of confusion, something is very wrong with the system.
~ Natan.