Selecting the Tag of NSSegmentedControl - objective-c

I'm attempting to implement an NSSegmentedControl button in my IB.
I have it connected to - (IBAction)editCart:(id)sender;
Also, it is connected to NSSegmentedControl *editCartButton;
The first "segment" is a "-" button to decrease the cart value.
The second "segment" is a "+" button to increase the cart value.
When I attempt to use the "sender" value like so: [sender selectedSegment], I get an error:
-[NSTableView selectedSegment]: unrecognized selector sent to instance 0x100622aa0
My button is located inside an NSTableView.
I've also tried: [[editCartButton cell] selectedTag]
When I run it through my conditions, it always returns a value of (null).
I would like to retrieve the specific tags of 0 and 1 I'm expecting to get, but can't find the right actions.
Help appreciated greatly, thanks.

This:
-[NSTableView selectedSegment]: unrecognized selector
sent to instance 0x100622aa0
basically tells you that the sender is not the NSSegmentedControl you think it is. The sender is an NSTableView. So either you wired things up the wrong way, or you have a severe memory management problem where the NSSegmentedControl is deallocated, and an NSTableView is currently to be found at its memory location.
In -(IBAction)editCart:(id)sender you could add a line:
NSLog(#"editCart, sender = %#",sender);
to confirm this. You can drop NSLog lines like this in other places in your code, to verify your ideas about what should be happening.

in IBAction try replacing (id) with (UISegmentedControl *)

I had a similar problem when working on updating Seashore (A port of GIMP to native OS X APIs).
First, you have to get NSSegmentedControl's cell object:
NSSegmentedControl *segControl = ...
NSSegmentedCell *segCell = [segControl cell];
Then, you set the tag for the segment you want to modify:
[segCell setTag:200 forSegment:2];
More info is available in Apple's documentation.

Related

NSTableView + NSTextView = Disaster :(

This is driving me a bit crazy..
Down below is a screenshot of my program so far.
On the right is an NSTableView (view-based). This is where the user can select a document they want to work on.
On the left is the NSTextView. Text will be displayed depending on what item they choose in the NSTableView.
There are also big plus and minus buttons for creating/deleting new items in the tableview.
Simple right? I wish.
Right now I have it so the tableview gets data from a mutable array. The mutable array contains objects of a class called DocumentItem. The DocumentItem just has two strings, one for the document text and one for the document title.
What works so far:
When I manually add objects to the array using code, I am able to freely switch through the documents and the textview will update accordingly.
What doesn't work:
When the user switches to a different document, I want to call the NSTableView replaceObjectAtIndex method save the changes that they have made to the object in the array.
How my code works so far:
The mutable array is stored in a data class. The data class is a shared class and is referred to in my code as theDATA.
I have a thread looping in my class that has the textview. In my tableview class I have a method called blastToScreen that will change a BOOL called shouldBLAST to YES.
Here is the code in my TableController class to set the BOOL to YES:
- (void) blastToScreen{
theDATA.blasttext = [[theDATA.globaldoclist objectAtIndex:[tablevieww selectedRow]] doccontents];
theDATA.shouldBLAST=YES;
}
Here is the shouldBLAST method in my looped thread(in a different class from the textview). Please note that the if-statement that says if(theDATA.switchedrow) is there to make sure that certain code gets runned only when a user switches their row in the tableview.
if(theDATA.shouldBLAST){
if(theDATA.switchedrow){
DocumentItem * itemr = [theDATA.globaldoclist objectAtIndex:theDATA.lastindex];
NSLog(#"(%li) prev content - >%#",(long)theDATA.lastindex,itemr.doccontents);
itemr.doccontents=textvieww.string;
NSLog(#"(%li)adding content - > %# <- to %#",theDATA.lastindex, itemr.doccontents,itemr.docname);
theDATA.switchedrow=NO;
[theDATA.globaldoclist replaceObjectAtIndex:theDATA.lastindex withObject:itemr ];
NSLog(#"changed: - > %#",[[theDATA.globaldoclist objectAtIndex:theDATA.lastindex] doccontents]);
}
textvieww.string=theDATA.blasttext;
theDATA.shouldBLAST=NO;
NSLog(#"changed: - > %#",[[theDATA.globaldoclist objectAtIndex:theDATA.lastindex] doccontents]);
theDATA.lastindex=theDATA.selectedrow;
}
Here's the weird part about all this:
According to the NSLog statements I set up, my code works for a split second and then resets.
Down below is what the console says. ignore the (0). that is just talking about the last selected index.
What it is saying is that the text before switching was nothing(fine). It is saying that it is adding the text "Potato" to that array(still fine). Then, the first time I fetched the object from the array it shows that it successfully changed to "Potato"(Still fine). Then when I tried to fetch the SAME exact data a few lines later, it returned nothing. :(
I feel like the issue resides somewhere in my TableController class. Here's a link to the code in my TableController class.
Here's what the console returned:
2015-09-14 17:17:46.024 Simplicity[4801:432580] (0) prev content - >
2015-09-14 17:17:46.025 Simplicity[4801:432580] (0)adding content - > Potato <- to Untitled
2015-09-14 17:17:46.025 Simplicity[4801:432580] changed: - > Potato
2015-09-14 17:17:46.025 Simplicity[4801:432580] changed: - >
I really hope you guys can help me. I tried pretty much everything I could to solve this issue.This is holding me back from finishing my software.
Probably, the doccontents property of your DocumentItem class is strong (or retain) when it should be copy.
From the docs for the string property of NSText (from which NSTextView inherits):
For performance reasons, this method returns the current backing store of the text object. If you want to maintain a snapshot of this as you manipulate the text storage, you should make a copy of the appropriate substring.
So, if you're just keeping a reference to that same object, when the text view's content is changed, the content of the object you've got a reference to also changes. You need to make a private copy.

Resizing NSTokenField after populating with tokens

I am using an NSTokenField as a way for users to enter tags. Everything works fine and it hooks up with CoreData managing the tags both when the user adds or deletes a tag.
I recently added logic so that the NSTokenField would resize vertically as the user adds tags and they break to the next line using Andrew Bowman's IFVerticallyExpandingTextField. Again this all works fine.
The issue is that when I have to initially populate the NSTokenField with tags, I need it to resize. I populate the field by calling:
[tagField setObjectValue: anArray];
Where anArray is a series of objects that represent a tag or a Token. This in turn calls the NSTokenField delegate method
tokenField:displayStringForRepresentedObject:
Which returns the string representation for the object passed in the previous array.
I need to resize the NSTokenField after all of the calls to displayStringForRepresentedObject. Does anyone have any ideas of a notification or a way of finding out that it's all done? Even a way of calling the resize in between each call to displayStringForRepresentedObject would probably work.
Thanks in advance.
You might try something similar to -setNeedsDisplay: and -displayIfNeeded ... i.e., -setNeedsSizeToFit: and -sizeToFitIfNeeded.
You'll just need a "needsSizeToFit" BOOL flag and the -setNeedsSizeToFit: and -sizeToFitIfNeeded methods.
After you set your tokens, call -setNeedsSizeToFit:YES. It in turn will set the instance's needsSizeToFit flag, then if the flag is YES, it will call [self performSelector:#selector(sizeToFitIfNeeded) withObject:nil afterDelay:0]. Your -sizeToFitIfNeeded method will check if your needsSizeToFit flag is YES, call [self sizeToFit], then set the needsSizeToFit flag to NO.
Update
Here's a complete class (JLNAutoSizingTokenField) that does basic autosizing as described above. The only augmentation was to call this in the afore-mentioned delegate method:
- (NSString *)tokenField:(NSTokenField *)aTokenField
displayStringForRepresentedObject:(id)representedObject
{
[(JLNAutoSizingTokenField *)aTokenField setNeedsSizeToFit:YES];
return representedObject;
}

Change window title to the one in text box in Objective-C?

I'm just getting started with Objective-C and I'm writing a simple application.
I made two outlets :
wnd - main window
display - the text box
Then I've tried using this code:
[wnd setTitle:[display value]];
Unfortuanately it didn't work ...
The debugger said :
2010-05-22 XX:XX:08.577
HelloWorld[2536:a0f] -[NSTextField
value]: unrecognized selector sent to
instance 0x102e032a0
Does anyone know how to get it to work?
Not my forte, but try stringValue instead of value.
NSTextFiled does not have a method value - try stringValue.
See NSControl the superclass of NSTextField

How do I set Cocoa NSLevelIndicatorCell values?

I have a tableview. One of the columns in the tableview uses an NSLevelIndicatorCell.
I want to be able to allow the user to edit the warn and critical values for the level indicator such that when they enter a value into a a "warning level" textbox, it changes the warn value of the level indicators being displayed in ALL of the tableview's rows.
I am very much a newbie with Objective-C so all I can figure out so far is that I must need a delegate method to watch the textbox BUT if I succeed in doing that, how on earth do I send the new value to the particular tableview column so that the update happens to ALL of the rows (i.e. how do I send what message to the tableview and target a cell within a column within a tableview)?
Here is the code to the solution I came up with should anyone need it.
- (IBAction)setWarningLevel:(id)sender {
double v;
NSScanner *ns = [NSScanner scannerWithString:[warnLevel stringValue]];
[ns scanDouble:&v];
[levelIndicator setWarningValue:v];
}
This is a textbook case for using Cocoa bindings. Just bind the value of the text field to the NSLevelIndicatorCell in your table view (do that in Interface Builder). The updates should happen automagically.
I think it should apply for all the cells in the table view if you apply the binding to the cell in IB. However if it doesn't, you will need to write a couple lines of code that set up the binding every time a new row in the table is created. That link above will explain everything in detail, but basically you will be setting up a Key-Value Observer relationship in code between the text field and the instance of the level indicator in the row being created.
I think you may have overdone it.
NSTextField subclasses NSControl, so you need to look in the docs for NSControl for a useful function.
Try re-writing it like this; assuming you're taking the value from a warnLevel textfield.
- (IBAction)setWarningLevel:(id)sender {
double v = [warnLevel doubleValue];
[levelIndicator setWarningValue:v];
}
Although this is usually shortened to this;
- (IBAction)setWarningLevel:(id)sender {
[levelIndicator setWarningValue:[warnLevel doubleValue]];
}
You should probably have some validation that the textfield has a valid number. If you're only choosing a couple of numbers have a look at using a stepper control.
Usually, with Cocoa, if you feel like you're jumping through too many hoops, there is sometimes an easier way.
Usually ;-)

How do I keep an NSPathControl updated with the path of the selected cell in an NSBrowser

I need to keep an NSPathControl updated with the currently selected path in an NSBrowser, but I'm having trouble figuring out a way of getting notifications when the path has changed from the NSBrowser. The ideal way to do this would just to be to observe the path key path in the NSBrowser, but that gives a KVO can only observe set<key> methods which return void message and no updates (setPath returns a bool success value).
I also tried observing the selectedCell key path, but I'm not getting notifications when the selection there is changed.
Is there some other really obvious way to do this that I'm missing?
Courtesy of Rob Keniger over at Cocoa Dev:
Have you looked at the SimpleBrowser
example in /Developer/Examples? It
shows how to get the current selection
when it is changed by the user,
basically by just setting up the
action of the NSBrowser.
That is indeed the way to do it. Just implement a method like - (void)browserClicked: in your controller and map it to the NSBrowser's action in interface builder with whatever you want to happen each time the selection changes inside that method, e.g.
- (void)browserClicked:(id)browser {
self.pathToSelectedCell = [browser path]; // NSPathControl is bound to pathToSelectedCell
}
I just checked in IB, and it looks like NSBrowser has a selection index paths binding (an array of NSIndexPath objects) that you could possibly monitor with KVO. It's strange but I don't see any mention of it in the docs, so you might need to do a little research to see if that's something you should or shouldn't use, even if it seems to work. If it does, in your KVO observation method you would find the browser's current path, and convert that to an NSURL the path control can use.
If that doesn't work there's also the delegate methods - (BOOL)browser:(NSBrowser *)sender selectRow:(NSInteger)row inColumn:(NSInteger)column and - (BOOL)browser:(NSBrowser *)sender selectCellWithString:(NSString *)title inColumn:(NSInteger)column.
As of 10.6, one can find out which items are selected, by using the delegate callback as follows:
- (NSIndexSet *)browser:(NSBrowser *)browser selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes inColumn:(NSInteger)column
{
NSLog(#"New first item of the new selection is at index %#", [proposedSelectionIndexes firstIndex]);
// Do something with the selected index or indicies
return proposedSelectionIndexes; // Allow the selection to occur by not changing this
}