What is a NSBrowserTableView as compared to an NSBrowser? - cocoa

I'm implementing a -(void)delete: method so I can handle the delete key in my Cocoa app. I want it to do different things depending on what's selected: for text-fields, I want the default behaviour (remove char to the left), but for NSBrowser items, I want it to delete the item.
I thought I would ask the Window for it's first responder, and then see if that first responder is equal to the pointer for my NSBrowser, but it never matched. When I debug it, I find that the firstResponder is pointing to an instance of NSBrowserTableView, but I can't find that in the documentation.
What is it?
And how else could I test to see if my firstResponder is a particular tableView? (I Thought of subclassing NSBrowser but I tend to avoid subclassing, and my second thought was to add a tag, but I like my first method best, if only the firstResponder would point to my NSBrowser instance when one of the items in the browser is selected. )
Thoughts?

Actually, #trudyscousin is only partially correct. This class is definitely not a subclass of NSBrowser.
NSBrowserTableView is a private subclass of NSTableView used by NSBrowser to display each column. The table view is used so there is a separate place to draw the branch image (the little arrow drawn next to folders) while leaving the rest of the row to be drawn by either the default or user-defined cell.
If you think about it, it actually makes sense that the table view (rather than the browser) be the first responder, because then the table for the active column gets first crack at responding to keystrokes, and NSBrowser can let NSTableView do what it already knows how to. (For example, jumping to the first row that matches a letter typed by the user.)
Fortunately, NSBrowserTableView has a pointer back to the browser it works for. You can access this via its -(NSBrowser*)browser method. I recommend you don't subclass NSBrowser for this particular case, since you'd have to have a deep knowledge of its private implementation to do anything useful.

You can't find that in the documentation because it's private. My guess is that, when you instantiate a NSBrowser or a NSTableView, you're actually instantiating a subclass of this private class, which itself is a subclass of NSControl (which is pointed out in the documentation as being the superclass of both NSBrowser and NSTableView). Another example is NSString represented as 'NSCFString,' which I take as an allusion to the fact that CFString and NSString are "toll-free bridged."
Take this with as many grains of salt as you wish, but the way I'd go about gaining insight into the first responder is inserting a NSLog statement in my code and breaking just beyond it, seeing what was printed in the log. You could set the view's tag and display that in the statement. Or you could ask for your first repsponder's class
NSStringFromClass([myFirstResponder class])
and display that.
Hope this helped.

Related

What is the difference between UITextInputDelegate.selectionDidChange and UITextViewDelegate.textViewDidChangeSelection

Two delegate methods are very similar.
I want to know what's their differences.
When the first will be called, when will another.
UITextInputDelegate.selectionDidChange
and
UITextViewDelegate.textViewDidChangeSelection
The difference is that UITextInputDelegate.selectionDidChange tells the view which conforms UITextInput that the text selection has changed.
While UITextViewDelegate.textViewDidChangeSelection tells UITextView that the text selection has changed.
In reality UITextView conforms the UITextInput, so it should not make any difference which method you will be using. But if you implement UITextInputDelegate to your textview, it will give you more flexibility to alter selection process e.g selectionWillChange, selectionDidChange. If you do not this flexibility, stick to UITextViewDelegate.textViewDidChangeSelection :)

Tabbing between NSTextFields with nextKeyView

I have a single NSViewController with the following layout, set using a storyboard:
The nextKeyView outlet of each of the NSTextFields is configured to be the next NSTextField in the order presented on the screenshot. For example, I chose the server NSTextField in IB and dragged from the nextKeyView outlet in Connectivity inspector to the login NSTextField, and did the same for the rest of the fields.
When the app is launched, any tab press on any of the field moves the selection to the first NSTextField. How do I achieve the desired tabbing between the fields?
I tried this in the respective WindowController, but to no avail:
- (void)windowDidLoad {
[super windowDidLoad];
self.window.initialFirstResponder = self.serverTextField;
}
This seems to be the most detailed answer, from Justin Bur posted to cocoa-dev mailing list (31 Jan 2007).
On several occasions over the years, people have asked why their key
view loop doesn't work properly. Most of these queries never get
answered on the list. After failing to find help for my key view loop
problems either on this list or on web sites, I did some
experimenting.
The key view loop can be problematic to deal with. It is designed to
just work magically, so in most cases it's not an issue. But if it
doesn't work, it's pretty difficult to figure out why not. Here are
some guidelines for getting a working key view loop.
Consider whether you can settle for an automatically generated key view loop. Each responder's top left corner determines its placement
in the loop. The loop proceeds from upper left to lower right, row by
row (at least for left-to-right scripts). This is by far the easiest
solution. To enable this, make sure the window's initialFirstResponder
is nil. See also -[NSWindow recalculateKeyViewLoop].
If the automatic key view loop is not suitable, set up your own key view loop using Interface Builder as much as possible. The window's
initialFirstResponder outlet must be set, in order to disable
automatic key loop generation. From that responder around the loop,
set the nextKeyView outlet of each item in the loop. (If desired, the
last item's nextKeyView can be set to the first item, thus closing the
loop.) For any view with scrollbars (NSTextView, NSTableView, etc.),
you should use the enclosing NSScrollView when setting nextKeyView.
If you have any responders created in code, splice them into the key view loop early (preferably in awakeFromNib
or maybe -[NSWindowController windowDidLoad]).
For each (sequence of) new item(s), you must use call -[NSView setNextKeyView:] thus: once to make
the previous item point to the (first) new one, (calls to make each
new item point to the next), and finally to make the (last) new item
point to its successor.
If your window has a toolbar, toolbar items that are interested in becoming key view will automatically add and remove themselves as the
toolbar is shown or hidden. The toolbar does not take into account the
return value of -[NSWindow autorecalculatesKeyViewLoop]. Toolbar items
are always placed in the loop before the top leftmost item. There is
no easy way to change this.
Once the window has been displayed, it can be extremely difficult to modify the key view loop - in particular if you are using
NSScrollView or NSTabView. These (and others?) are special cases
because they insert their contained views into the loop automatically.
For information on the initialFirstResponder and key view loop of an
NSTabViewItem, see the AppKit release notes for OS X 10.1
.
If you have items that should sometimes be in the loop and other times not, it is not advisable to attempt to splice them in and out of
the loop. Instead, subclass -[NSResponder acceptsFirstResponder] for
these items. If an item returns NO from this method, it will be left
out of the loop (temporarily); if it returns YES, it will come back
into the loop. Alternately, if the item is derived from NSControl (it
probably is), you can call setRefusesFirstResponder: on it.
If you make a mistake, your key view loop will cease to function, either in one direction or in both. Once it breaks it stays broken. To
debug, comment out calls to setNextKeyView: or
setInitialFirstResponder: until it works again. The offending call is
likely trying to modify the key view loop in the presence of
NSScrollView or NSTabView, after these objects have already done their
behind-the-scenes loop-munging. Move the calls to an earlier point, or
do without. (If you have no calls to setNextKeyView:, then check your
nib - make sure the window's initialFirstResponder is set and that
nextKeyView outlets are chained together the way you want.)
In System Preferences/Keyboard & Mouse/Keyboard Shortcuts, at the bottom of the pane under "Full keyboard access", you can control
whether key view loops include all controls or only text fields and
scrolling lists (^F7 to toggle). You should test your key view loops
with this setting in each state.
These guidelines were determined by experiment and may not be entirely
accurate. Corrections and further explanations are most welcome.
Set the window's initialFirstResponder in windowDidLoad of the window controller or viewWillAppear of the view controller. If initialFirstResponder isn't set before the window's makeKeyAndOrderFront, recalculateKeyViewLoop is called.

Array Controller not updating Table View until "Add" button is pressed

I'm new to Cocoa and Objective-C, so I'm following the Lynda courses and learning a lot. Thing is, I've encountered a problem that I cannot figure out, even though I seem to be doing it exactly the same way...
Basically, I'm trying to get a Table View hooked up through bindings to an Array Controller, just to list out the contents of a simple NSMutableArray in my code. I'd gotten it all hooked up properly, but no matter what I did it wasn't displaying anything when I ran the program.
Here's where it gets weird: on a lark, I added a "+" button and hooked it into the "add" function of the Array Controller, and when I ran the app and clicked that button, it not only added a new line, but it displayed the whole array as well! Apparently everything had been hooked up properly the whole time, it just wasn't displaying the information. Further experimentation revealed that I could make any changes I wanted to the array, whether in the original code or during the runtime of the app, but they would only be updated in the Table View when I clicked that "+" button.
I feel like this is probably a simple solution, just some "Continuous" box that needs to be checked or something, but I cannot for the life of me find it... Can anyone point out what I need to do to get my TableView to show its contents automatically?
(Also, I don't know if this is related or not, but none of the "Model Key Path" fields in the inspector are offering suggestions as I type, which they do in the Lynda course. The app works fine if I manually type everything in, but it says "no completions found" the whole time.)
Thank you in advance for helping out a n00b!
none of the "Model Key Path" fields in the inspector are offering suggestions as I type
As I understand it this is probably because the NSMutableArray that holds your data array i.e. dogPound or similar, isn't also declared as a property, only an instance variable.
Declare the property #property NSMutableArray * dogPound; and change the instance variable declaration to _dogPound and I think interface builder should offer you the auto-completes.
I'm new to Cocoa and Objective-C
Me too.
I'd gotten it all hooked up properly,
In about 30 minutes, I can get everything setup with a custom class like Dog, and another class called AppController that consists of one instance variable: NSMutableArray* dogPound. The init() method for the AppController class creates the array and adds some Dog instances to the array. I also bound an NSArrayController to the dogPound array, and I bound the NSTableView columns to the NSArrayController. After I Build&Run the NSTableView displays the information for each Dog instance in the dogPound array.
I also tried a simpler version where there is no Dog class and the array in the AppController class just consists of some NSString objects. Once again, I was able to successfully bind an NSArrayController to the array and bind the table's columns to the NSArrayController, so that an NSTableView displayed all the NSString's in the array.
You need to post your exact code, and you need to write down every step you did in IB, which of course is a huge pain in the ass, but it's the only way anyone will be able to help you.
Here's where it gets weird: on a lark, I added a "+" button and hooked
it into the "add" function of the Array Controller, and when I ran the
app and clicked that button, it not only added a new line, but it
displayed the whole array as well!
Of course. The add: method in the NSArrayController adds a new item to the array and then signals the NSTableView that it should reload the data, i.e display everything that's currently in the array.
I feel like this is probably a simple solution, just some "Continuous"
box that needs to be checked or something,
Nope, nothing like that.
none of the "Model Key Path" fields in the inspector are offering
suggestions as I type
Lack of autocompletion choices is a big hint that you are doing something wrong--even though I find I can't always figure it out, so I just keep typing. Did you remember to start your bindings in the Attributes Inspector(Object Controller section) for the NSArrayController? In IB, did you create an instance of your AppController class, or whatever you called the class that contains the NSMutableArray, by dragging an Object onto MainWindow.xib?

RootViewController need to resort/reload data array xcode 4.3

I'm implementing an example, in that example, I read in data from a database, put it in an array, sort it, and it's displayed using the RootViewController. The DB read and array load happen before the RVC code. So, it works, I get the data in the window created by the RVC and there's a nav controller there as well.
I want to add a button or something to the nav controller so that when you hit it, it sends a value back to the RootViewController.m file, then based on that value, I want to resort the array and display it once again in the RootViewController window.
I'm not sure how to do this. What changes would I have to make to the .xib and the RootViewController.m file?
Please, I'm a confused nube. %-0 Thank you very much.
There's a fair amount to this, so I'll give some general points and if any of them cause problems, it may be easier to work out smaller details.
In you RVC's viewDidLoad method, you can create a button and set it as the right or left button in your controller's navigationItem.
You can associate a tap on that button with a method in your controller that can do whatever you want when the button is tapped. (But a button doesn't send values, really, so you may have to explain more about that idea.)
I assume the RVC has a table view if you're showing array contents, so once the array (mutable array, I'd assume) is re-sorted, you can tell the table view to reload its data.
In answer to your secondary question, once you have resorted your array (or generally updated your data however you wish) you can force the table view to reload programmatically
[tableView reloadData];
Where 'tableView' is your instance variable pointing to your table view

Creating a view with draggable text elements

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.

Resources