Update NSMenuItem while the host menu is shown - cocoa

I have an NSMenuItem that I need to update to show a progress (like Time machine does with it's backup). The problem is that when I set a new title on that NSMenuItem and the title is not changing.
It is in fact changing when I close and reopen the menu, but I want to update it while the user is looking at it.
I also tried remove an item and re-inserting it with no result.
Any pointers?

This actually works with no additional effort if your updating code runs in the run loop mode which is used during menu tracking. This is NSEventTrackingRunLoopMode, but you probably just want to use NSRunLoopCommonModes so the menu item title is correct when the menu is pulled down.
Here's a simple example of a menu item foo that counts the number of seconds since the app launched:
- (void)doStuff;
{
static int i = 0;
[foo setTitle:[NSString stringWithFormat:#"%d", ++i]];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(doStuff)]];
[invocation setTarget:self];
[invocation setSelector:#selector(doStuff)];
[[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:1 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];
}

Related

UITextView setText should not jump to top in ios8

Following iOS 8 code is called every second:
- (void)appendString(NSString *)newString toTextView:(UITextView *)textView {
textView.scrollEnabled = NO;
textView.text = [NSString stringWithFormat:#"%#%#%#", textView.text, newString, #"\n"];
textView.scrollEnabled = YES;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length, 0)];
}
The goal is to have the same scrolling down behaviour as the XCode console when the text starts running off the bottom. Unfortunately, setText causes the view to reset to the top before I can scroll down again with scrollRangeToVisible.
This was solved in iOS7 with the above code and it worked, but after upgrading last week to iOS8, that solution no longer seems to work anymore.
I can't figure out how to get this going fluently without the jumping behaviour?
I meet this problem too. You can try this.
textView.layoutManager.allowsNonContiguousLayout = NO;
refrence:http://hayatomo.com/2014/09/26/1307
The following two solutions don't work for me on iOS 8.0.
textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;
and
CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];
I setup a delegate to the textview to monitor the scroll event, and noticed that after my operation to restore the offset, the offset is reset to 0 again. So I instead use the main operation queue to make sure my restore operation happens after the "reset to 0" option.
Here's my solution that works for iOS 8.0.
CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
[self.textView setContentOffset: offset];
}];
Try just to add text to UITextView (without scrollRangeToVisible/scrollEnabled). It seams that hack with scroll enabled/disabled is no more needed in iOS8 SDK. UITextView scrolls automatically.

UITextField - message sent to deallocated instance "UIKBStringWideAttributeValueForKey:"

After enabling Zombie Objects I am able to see the following error when I try to edit a UITextField (textLvl):
2013-01-13 13:27:10.509 testob[18418:907] *** -[NSConcreteMutableAttributedString
_UIKBStringWideAttributeValueForKey:]: message sent to deallocated instance 0x2066a1f0
I have posted the portion of code that is causing the issue below, it seems to specifically be the "textField.text = self.storeText;" part - as when I comment this out the problem goes away.
You may be able to tell I am not the most experienced iOS dev, why would my UITextView deallocate after I've set the text? Help please!
Also, I've never heard of "_UIKBStringWideAttributeValueForKey" before - any ideas?
Thanks all!
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(#"Text began editing");
self.storeText = textField.text;
textField.text = #"";
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (textField == textLvl){
if ([textField.text isEqualToString:#""]){
textField.text = self.storeText;
NSLog(#"No Text");
}
self.conv = [textField.text intValue];
if (self.conv >= 101){
textField.text = #"100";
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Oh no!" message:#"Can't be higher than 100." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[successAlert show]; }
}}
This might be a bug internal to the framework. I suggest you add - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField and set the textfield text to nil and then reset the textfield text.
I think the real answer here is that you're dealing with a UITextField that has been set to handle NSAttributedString rather than NSString. You'll notice if you're dealing with UITextField defined in a .xib, it's top property option is now "Text" with options Plain or Attributed.
If your text field was switched to attributed, you'll find this error happening if you continue to deal with the text field as if it were Plain.
My textfield was in a xib file and it's delegate was hooked up to the files owner. This was causing the crash for me, because the file's owner was NSObject.
I actually wanted to hook up the delegate to the cell, and not files owner.
Use instruments so see the retains/releases:
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the picker to run, stop recording, search for there ivar (datePickerView), drill down and you will be able to see where all retains, releases and autoreleases occurred.

NSOutlineView: How to Put a Specific Cell Into Edit Mode? (editColumn Method Not Working as Expected)

I have an NSOutlineView. When I edit a cell in it and hit return, I would like the cell directly below it to go immediately into edit mode.
I thought I would use the controlTextDidEndEditing: delegate method to find out when editing of a cell had finished, and the editColumn:row:withEvent:select: method to put the cell below it into edit mode.
Here's a demo method that I pasted into "appcontroller.m" of the Apple demo code project, "DragNDropOutlineView":
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
NSTreeNode* treeNodeJustEdited;
NSInteger indexOfCurrentRow = [outlineView selectedRow];
if (indexOfCurrentRow < 0) //no row selected
return;
treeNodeJustEdited = [outlineView itemAtRow:indexOfCurrentRow];
NSTreeNode* theRootNode = rootTreeNode;
NSInteger numberOfChildren = [[theRootNode mutableChildNodes]count];
NSInteger indexOfLastChild = numberOfChildren - 1;
if (indexOfCurrentRow < indexOfLastChild)
{
[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexOfCurrentRow+1] byExtendingSelection:NO];
[outlineView editColumn:0 row: indexOfCurrentRow+1 withEvent:nil select:NO];
}
}
For some reason, this does the following:
Correctly highlights the row below the cell
just edited. But then:
Disables that
highlighting, i.e. puts it in light
grey
Makes the cell below the cell
just edited, invisible. Clicking
twice on that cell returns the table
to normal.
What am I missing in order to get this method to perform as desired?
Here is another question, it is similar with yours
Hope helpfully.
NSTableView & NSOutlineView editing on tab key

Refresh a label in a status item menu [duplicate]

I have an NSMenuItem that I need to update to show a progress (like Time machine does with it's backup). The problem is that when I set a new title on that NSMenuItem and the title is not changing.
It is in fact changing when I close and reopen the menu, but I want to update it while the user is looking at it.
I also tried remove an item and re-inserting it with no result.
Any pointers?
This actually works with no additional effort if your updating code runs in the run loop mode which is used during menu tracking. This is NSEventTrackingRunLoopMode, but you probably just want to use NSRunLoopCommonModes so the menu item title is correct when the menu is pulled down.
Here's a simple example of a menu item foo that counts the number of seconds since the app launched:
- (void)doStuff;
{
static int i = 0;
[foo setTitle:[NSString stringWithFormat:#"%d", ++i]];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(doStuff)]];
[invocation setTarget:self];
[invocation setSelector:#selector(doStuff)];
[[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:1 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];
}

NSPopUpButton text overlaps menu image

I am using the following to create an NSPopupButton programmatically:
...
NSPopUpButton *accessoryView = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 24) pullsDown:YES];
NSFont *aFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
[accessoryView setBezelStyle:NSRecessedBezelStyle];
[accessoryView setFont:aFont];
[accessoryView setShowsBorderOnlyWhileMouseInside:YES];
[accessoryView setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
NSArray *popupItems = [[NSArray alloc] initWithObjects:#"Your Account", #"Sign In", #"Create Account", nil];
[accessoryView addItemsWithTitles:popupItems];
...
Now, when I add the NSPopUpButton to my view, I end up with the button's text overlapping the icon used for the dropdown menu. I have seen this previously when I use NSControl:setAlignment but I am not using this here. Here is the output:
Can anyone see what I'm doing wrong?
Take care,
Jeremy
It just so happens this is a simple fix. (Thanks Beelsebob on irc.freenode.net!) Basically, you need to have the following code:
[[accessoryView cell] setArrowPosition:NSPopUpArrowAtBottom];
in there somewhere. (I added it just below the line to add the menu items.) I had read the API docs on this call a few times before, since I had implemented the same call with a value of NSPopUpNoArrow to remove the arrow as an interim fix, but it didn't make it clear that the proper value being used above would do what it's doing. Problem solved.

Resources