NSWindow does not respond to keystroke command-s - objective-c

It may be very simple, but I cannot find it:
I have three windows in three separate NIBs in my application. One is opened when a new document is opened, the other two can be opened from the program's window menu.
The problem is: two windows (in them the one that is opened at the beginning) accepts the normal keystroke as for example command-s for save, and the other one does not and gives a warning sound instead. I cannot figure out the difference between the two windows or their controllers. I know it will have to do with the responder chain, but I am left clueless.
Any ideas?

Check to make sure that the window's delegate is set to the window controller, and that the window controller implements -saveDocument: (or whatever action the Save item is connected to).

Windows don't respond to key combinations. Menu items do. In response to being pressed (whether using the mouse, using a key combination, or using Accessibility), the menu item sends its action message down the responder chain.
You get a beep when nothing in the responder chain responds to the action message.
Assuming that this is an NSDocument-based application and you've started Apple's doc-based-app template, the menu item's action is saveDocument:, and the NSDocument object is the object that responds to that message. When your document windows are active, their documents are in the responder chain, so the menu item that sends that action message is enabled. When your third window is active, the document is not in the responder chain; nothing else responds to that message, so the menu item is disabled.
This problem isn't specific to Save—it affects all action messages that should go through to the document object. One important other example is Print: The user will probably mean to print the document, not the third window.
You've probably made this third window a kind of window that exists as a peer to the other windows. Besides this responder-chain problem you're having, the user will also probably not realize that they have left the document; they expect to still be able to do document things. Consider making it a utility panel instead.
If you really do have a good reason to make this window whatever kind of window it is, you'll need to keep the last-active document object in the responder chain when this third window becomes main, while at the same time handling the case where the window becomes main because a document window (possibly the last one) has closed.

Well, it turns out that I implemented the third window in a way where I created it with its controller using initWithNibFile, ran a procedure in the controller and then sent it a [window close] command because I did not want it to appear on the screen yet. That somehow took it out of the document-associated window, no idea why. No I migrated that specific called procedure into the document controller itself, treat the window like the second window and voila, it works again.

Related

Custom Drop-down window/dialog in Cocoa

What are the alternatives of dialog windows in Cocoa? I need to create a custom dialog (modal) where the user will be able to enter some info and when he/she presses OK, my app will close this dialog and process input.
So essentially, I need something like a drop-down window in Xcode when you add a new file (command + N):
[not enough reputation to post a screenshot]
All I have discovered so far are a few old listings and topics where people say it's called a sheet. But the methods suggested seem deprecated, like
beginSheet: myCustomSheet
modalForWindow: window
modalDelegate: self
didEndSelector: #selector(didEndSheet:returnCode:contextInfo:)
contextInfo: nil
Are there any other ways?
For example, I can create a separate window with its own xib file, is there some kind of setting to make it a "panel" or "sheet"? I'm a bit confused by the terms.
What you want is a "sheet". A sheet is one window which is attached to another and blocks most inputs to the window that it's attached to.
A panel is just a specific kind of window. NSPanel is a subclass of NSWindow. It has some different behaviors and possible styles. You can use a panel as a sheet, but you don't have to and it doesn't make much difference.
Note that a sheet is window-modal, not application modal. That is, it prevents the user from doing other stuff with the window to which it is attached, but doesn't prevent the user from doing stuff in the app's menus or its other windows. Implicit in this is that sheets operate asynchronously. You begin a sheet and then execution continues without the sheet's work having been completed. You should then generally allow flow of execution to return to the main event loop. When the sheet completes, it will call some code that you have specified.
If you need synchronous behavior, use an app-modal dialog instead.
The modern API for presenting a sheet is -[NSWindow beginSheet:completionHandler:]. You send that message to the "normal" window (e.g. document window). The first parameter is the window which is to be the sheet. The completion handler is the code to be run when the sheet completes.
The controls within your sheet would typically target their actions to the window controller for the sheet (just as with any other window). Within the action methods, you would call -[NSWindow endSheet:] or -endSheet:returnCode: on the parent window to complete the sheet and determine the result code which is passed to the completion handler. You can obtain the parent window using the sheetParent property.

Do not require attention for ShowDialog

I had a question about Dialogs in VB.NET. I am working on a point of sale program, and at one point during a sale, I have a few windows that pop up. For example, a user will go into a sale that is window A. In window A, they have the option of entering products, etc., and if they choose a 'repair' product, it opens window B, allowing them to choose options. In window B, there is a button that pops up window C that allows them to attach products TO the repair. My issue is with window B opening window C.
Because I open window B as a Dialog (in order to check if DialogResult.OK is true), any window I open with B is non-touchable, as B is a Dialog and requires attention before going to any other windows/forms.
My question is - is there any way to still use a dialog, but allow for manipulating other open forms while the dialog is up, and if not, what would be the best way to check if the user selected OK, or cancelled out of the window?
The only solution I can think of right now would be to open window C as a dialogue as well (it's actually a UserControl, and I'm still trying to find where in the code it's actually getting openned/called), or to create a variable that is passed in to the form, and then passed back out when it's closed, that basically sets a flag to either continue or cancel...
Any advice/ideas??
If I were to explain this using code, this answer would be very long, so instead I'm going to give you a high level overview.
.Show() vs .ShowDialog()
The link below will take you off to Microsofts website to explain the technical differences between these two. However in laymans terms, .ShowDialog() will create the form where it is the only window allowed to have focus in the application. Forms that are called in this instance are hierarchical, in that if you open them in order of 1,2,4,3 then they must be closed in the 3,4,2,1 order. Forms that are opened with just .Show() can be focused at any time.
How to: Display Modal and Modeless Windows Forms
Form.FormBorderStyle property
This property controls how the OS will display the window. The different options under this selection changes the way the window behaves. Depending on the options that are chosen you can make a window that only has a close button on it, or it may not even have a title bar at all. Setting this option to None will take away all controls of the form and only leave you with the Me.ClientArea to work with. When you want a completely custom GUI, this is how you do it but you have to implement your own controls for everything, closing the form, size handles, the ability to move the form on the screen, etc...
Form.FormBorderStyle Property
Passing data between forms
When someone asks how to pass data back and forth between forms, they are usually talking about modeless forms that were created using .Show(). The most common thing I see on SO is to use the tag property of an object (a form is an object that has this property too) to pass data back and forth. While I won't say this is a bad practice, I will recommend creating public properties on your forms. These can be set from a separate form and you can perform additional actions when setting the values (be careful though, this way of doing things isn't thread safe). If you are using a Modeless form as though it were a Modal form, then you can simply override the .Dispose property to return a value or you can create a method named DialogResult that will return the value you need. The caveat to using a DialogResult or similar method is that if the form has been disposed then you can't access the value you wanted to return.
You can use myNewForm.Show(Me) for the Window you want to be shown as a dialog. This will show myNewForm as a child of the current form, but lets you interact with the current form.

pyGTK how to redisplay a top level window (with child widgets) after window destroy signal is sent

I have an application which displays a window containing widgets every minute. If I destroy this window by closing it in the window manager (linux), the destroy signal is sent. Then the next minute rolls around, at which time self.window.show_all() is executed and the window pops up empty.
So I did some investigating. I executed print self.window.get_children() just before the show_all command, which returned an empty list. So I executed self.vbox.reparent(self.window) and I get this response:
calendar.py:237: GtkWarning: IA__gtk_widget_reparent: assertion `widget->parent != NULL' failed
self.vbox.reparent(self.window)
These two responses seem to contradict one another. On the one hand, the empty list returned by print self.window.get_children() seems to imply that the window does not have any children. On the other, the output returned by self.vbox.reparent(self.window) seems to imply that self.vbox still has a parent, which would be self.window (as defined previously)
I've tried using a popup window: self.window = gtk.Window(gtk.WINDOW_POPUP) instead, but I would like to be able to close the window through the window manager, so that I don't have to add an additional button just to close (hide) the window. The popup window doesn't seem to provide this functionality in my window manager (awesome).
So if you want to redisplay a top level window with its children after it is destroyed, how can this be done?
Have you tried making another copy of
the window class and showing that one
instead? Note: This will reset anything that was set in the window. i.e. if a person did something to make label1 say 'Hi!' instead of 'Hello!', it is going to be reset again to 'Hello!', since you are recreating the window.
You can also set Gtk.Window.hide_on_delete as the handler for the delete-event signal; then closing the window will hide it instead of destroying it.

How can I make a button not fire its action on click-through?

The Apple Human Interface Guidelines state that:
An item that provides click-through is one that a user can activate on an inactive window with one click, instead of clicking first to make the window active and then clicking the item. Click-through provides greater efficiency in performing such tasks as closing or resizing inactive windows, and copying or moving files. In many cases, however, click-through could confuse a user who clicks an item unintentionally.
and
Don’t provide click-through for an item or action that:
Is potentially harmful and does not allow the user to cancel it (for example, the Delete button in Mail)
Is difficult or impossible to cancel (such as the Send button in Mail)
Dismisses a dialog without telling the user what action was taken (for example, the Save button in a Save dialog that overwrites an existing file and automatically dismisses the dialog)
Removes the user from the current context (for example, selecting a new item in a Finder column can change the target of the Finder window)
What I want to do is that if the user clicks a specific button it will not send its message unless the window is active (for example, the delete message button in Mail). How can I achieve this? If I need to subclass NSButton that's fine.
Look at the NSView Documentation:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/Reference/NSView.html#//apple_ref/occ/instm/NSView/acceptsFirstMouse:
You need to override acceptsFirstMouse to return TRUE to enable click through.
The default behaviour is not click-through:
The default implementation ignores theEvent and returns NO.
It's possible you have already overridden this method in your code, or in code you have based your code on. Try removing the implementation of acceptsFirstMouse in your code.

Connecting Menu Items in Document Based Applications

I've already asked a couple questions on this topic, and haven't really received a real answer on how to do it (it actually received the "Tumbleweed Badge" lol).
I have a document based application (meaning the Menu.Xib is separate from MyDocument.Xib).
Say I want to add a 'Bold' button, or a Check Spelling button (items that are listed in Menu.xib (under Format > Font etc) to MyDocument (the primary interface). I cannot figure out how to do this.
Any help would be greatly appreciated (I will reward an answer immediately if it works, this has stumped me for a couple weeks now).
I tried adding a Font Manager to MyDocument.Xib and connecting that way, but the Bold button only enables, it doesn't disable. Plus, Spell Check etc can't be activated via Font Manager.
There has to be a better way to do this.
The Apple Documentation is incredibly vague.
This is exactly what the First Responder object in IB is for. It is a proxy object for connecting actions. Any action messages sent to it will be passed down the responder chain to the first oobject that accepts them. For document based applications, the responder chain includes the current document. So, to connect the menu item to your document:
Add the action to First Responder, if needed. You can do this from IB's inspector window.
Connect the action to First Responder as if it were a normal object.
Implement the action method in your document.
If you need to add a message to the first responder programatically, set the object's target to nil.