I am developing a cocoa app where i need to create Menu and Submenu's in my application.
I have attached a screenshot designed using flex. How can i do the same in cocoa.
Any help would be appreciated.
Thanks.
Your question itself is incomplete,though will try to match the solution your expecting…The screenshot you posted(you never mentioned the source of the screenshot you have taken,by analysing the design i edited in your question as “Flex”) looks like you don’t want to deal with NSMenuItem and NSMenu classes for the drop down menus…
Solution 1: Make a custom View(probably subview of NSView like popview) that handles input, displaying labels,imageviews etc.
==> Basically,both the menu bar and menu item are wrapped to an NSView And the drop down menu is wrapped to an NSPanel…Well as per the design you have to use NSView,because you will be able to add the corner you like and yes,there is a possibility of adding back ground colour as well…The menu item actually has subviews of NSTextView. If its a menu bar item then it only has one text subview for its title, and if its a sub menu item then it has 3 text subviews, one for the check mark, one for the title and one for the hot key list…No need to worry about the handling the events,the respective classes do their own event handling…It’s quite a complicated solution,but matches your requirement…
Found some example for you,check out this code which is in C++.
Solution 2: NSTableView with custom cell.Could be fugly, but maybe worth a shot.
==> Create a custom NSTableCellView/NSCell,with NSImageView(for icons like Pen), NSTextView(for the text “Pen Thickness”) and one more NSImageView(for the right corner icon) as it's subviews …You have to perform one of the two actions when user hits your cell…(1) If you would like to have the submenu,then again that cell should create one more NSTableView using the origin (cell.frame.origin.x+cell.frame.size.width, cell.frame.origin.y)…(2) If there is no submenu,perform the direct task...
Example: Assume "MenuItemCell" is the custom class name,in the delegate method tableView
willDisplayCell add the cell...
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
MenuItemCell *cell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
result.imageView.image = //ur image
result.textView.setString//;
result.imageView.image = //corner image icon,if you would like to have submenu upon clicking this cell.
return result;
}
On selecting the custom cell,
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)rowIndex
{
NSLog(#"%i tapped!", rowIndex);
NSTableCellView *selectedRow = [tableView viewAtColumn:0 row:rowIndex makeIfNecessary:YES];
//if you would like to have the submenu,display one more NSTableView,based on the cell origin as i described above...don't forget to add the animation..
return YES;
}
Happy Coding.. :-)
Related
As the title suggest, I've enabled right clicks for my tableview with customized rows. Anywhere there is an NSTextField, it blocks the right click.
is there a userInteractionEnabled equivalent for cocoa like on the iphone?
I though I probably needed to subclass everything in my NSTableCellView subclass, but I just needed to override -(NSView*)hitTest:(NSPoint)aPoint method in my NSTableCellView subclass to return self.
I'm able to right click on text fields within my custom view based table view cell. Here is how I configure it:
NSTextField *tf = [[NSTextField alloc] initWithFrame:NSZeroRect];
self.textField = tf;
self.imageView.autoresizingMask=NSViewWidthSizable;
self.textField.editable=NO;
self.textField.selectable=NO;
self.textField.drawsBackground=NO;
self.textField.bordered=NO;
self.textField.bezeled=NO;
self.textField.target=self;
self.textField.action=#selector(textDidEndEditing:);
[self.textField.cell setLineBreakMode:NSLineBreakByTruncatingMiddle];
Also, make sure you are setting the -menu property of NSTableView and not the cell view to enable to menu. (I don't know if that will make a difference to your issue but it is how I do right clicking in a table view.)
I am trying to make a drill down table with storyboards in a Tab bar app.
I am having a problem with working out how to get each row in a main table to point to other different tables.
This is the code I have used to detect row selection.
-(void)tableView: (UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *__strong)indexPath {
TableViewController *table = [self.storyboard instantiateViewControllerWithIdentifier:#"table"];
[self.navigationController pushViewController:table animated:YES];
}
How do I proceed please?
The real beauty to UIStoryBoards are the segues.
1. You can link one prototype cell push segue to another different table view controller
2. You can link one prototype cell push segue loop back to itself for drill downs.
[self performSegueWithIdentifier:#"segueID" sender:MyObject];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"segueID"]) segue.destinationViewController.chosenCell = sender;
}
If the segue is from the cell click, the sender is that of the cell and you can get it's indexpath from the table, and pass new information to the upcoming view controller.
If you want the cell to take various paths when clicked, keep the didSelectRowAtIndexPath and call performSegueWithIndetifier so you can choose left or right.
Tutorial: http://jleeiii.blogspot.com/2012/05/uistoryboard-power-drill-batteries.html
GitHub: http://www.github.com/jllust/UIStoryboardExamples
I was extremely frustrated with this, as the storyboards with tableviews is really not covered ANYWHERE. I literally almost pulled my hair out trying to figure this out. So my frustration is your luck!
Comparing your code to mine, yours looks fine other than the fact that in the initial didSelectRowAtIndexPath: method, you have *_strong, which should not have the _strong part. It should just be like this: (NSIndexPath *)indexPath {
Additionally, be careful in when you are referring to the instantiateViewControllerWithIdentifier in Interface Builder. I accidentally filled out the name of the instance variable under 'TITLE' instead of 'IDENTIFIER'
I hope this helps. I completely understand your frustration.
In your storyboard, if the content is Static Cells, you can ctrl-drag from the specific row to a Navigation Controller. Then connect the Navigation Controller to your next table. Look at this screen shot. http://cl.ly/1V2y0v202y390U0A351x
My guess is that progromatically, you'll need to do something similar, segue to a NavigationController which has a table view controller as it's root view.
I'm very new with iOS Development and I have just created one of my first apps, in my .xib file I have a UINavigationBar that I want to hide/show when a part of the screen is tapped by the user (like in the Photo app). I've found some snippets online but I don't know where and how to use those.
I'd appreciate a lot if somebody could give me detailed informations about how to do this.
Add this toggle method anywhere in your UIViewController. This hides on first tap and shows again in second tap.
- (void)toggleNavBar:(UITapGestureRecognizer *)gesture {
BOOL barsHidden = self.navigationController.navigationBar.hidden;
[self.navigationController setNavigationBarHidden:!barsHidden animated:YES];
}
If there is no navigation controller, link the navigation bar with an IBOutlet and replace with
- (void)toggleNavBar:(UITapGestureRecognizer *)gesture {
BOOL barsHidden = self.navBar.hidden;
self.navBar.hidden = !barsHidden;
}
Then add the following in the method -(void)viewDidLoad {}
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(toggleNavBar:)];
[self.view addGestureRecognizer:gesture];
[gesture release];
If the view where you are going to tap is a UIWebViewController, you have to add the protocol to the view controller and set it as delegate gesture.delegate = self; then add the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
This is needed because the UIWebViewController already implements its own gesture recognizers.
Ultimately, you want to send the -setHidden: message to your navigation bar. The easiest way to do this is to make an Outlet and an Action in your in your view controller. Then, in your .xib file, connect the navigation bar to the outlet and some button (even a large, full screen one) to the action.
Outlets and Actions are basic techniques used over and over in iOS
(and Mac) programming, so if you don't understand them, best go read
up on them now. Every beginning iOS/Mac programming book covers this
topic as does Apple's own Getting Started guide (pay particular
attention to the Configuring the View section).
Inside your action, send a message to the outlet like so:
-(void)myButtonAction:(id)sender{
[[self myNavigationBarOutlet] setHidden:YES];
}
This will hide the navigation bar whenever your button is tapped.
(This assumes you have a UINavigationBar in your .xib like you say. These directions will be different if you're working with a UINavigationController that manages its own UINavigationBar)
I have a (new in Lion) view-based NSOutlineView as Sidebar SourceList in my app using CoreData + NSTreeController + Bindings + NSOutlineView and an Object as NSOutlineViewDelegate.
I use these delegate methods in the outlineview delegate:
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item In my case a item is group when the (Core Data) parent relationship is nil.
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item To return the headercell view (group) or datacell view (icon + text).
And I set the size style of the outline view (in Interface Builder in XCode) as "Sidebar System Default" so the cellview changes its size when the user change it in the system preferences.
It works fine... but there are a few issues:
The first cellview is a group cell (header cell) and when expand-collapse the textfield for this cellview moves up-down. Only happens with the first one.
The textfield in the header cells changes it size (when changes the size in the system preferences) but I would like that the header cells size stay fixed like (Lion) Finder, Mail... does.
The string value of the textfield in the header cells doesn´t appear uppercase.
The images I use as icon in the image view of the data cells appears transparent (with a 0.5 alpha value or something like that).
Any help? Thanks in advance
SOLVED:
For the movement when the first cellview expand/collapse use the method setFloatsGroupRows:NO with the outlineview (Thanks Anton!)
If you want fixed size for the font of the groupcells (even if user change it in the system preferences) unbind in IB the header cell with its Table Cell View.
Using a valueTransformer (that transform a string to uppercase) with the header cell the string will appear uppercase. Also you can do this with the nsoutlineview datasource method - outlineView:objectValueForTableColumn:byItem:...
And finally the icon is semi-transparent because is not enabled. Uncheck "Conditionally Sets Enabled" in the Value or Value Path (depending the one you use) in the image cell bindings
Setting setFloatsGroupRows:NO for the outline view must solve the issue with first group item moving up-down when being expanded/collapsed.
In case it's not obvious to anyone:
"Floats group rows" in Interface Builder:
You can set "Floats group rows" directly in Interface Builder.
select your Source List in Interface Builder's document outline.
show the Attributes Inspector, and you will find the "Floats Group Rows" checkbox. Untick it, and your nasty jumping group headings suddenly behave themselves :)
In Swift:
Alternatively, if you're in Swift, you can do something like:
#IBOutlet weak var sourceList: NSOutlineView!
sourceList.floatsGroupRows = false
You may also have a look at the answer of this question: NSOulineView header cell font The automatic style unselect-reselect dance worked for me.
I was wondering how you achieved the source list that's visible on the screenshot.
I have created a little sample project, which does the same and includes the feedback from #anton-ivanov:
Display a list of items
Edit the items in a master-detail fashion
Remove and add items
Usage of bindings
Check out besi/mac-quickies on github.
Most of the stuff is either done in IB or can be found in the AppDelegate
i am having a problem displaying context sensitive menu on control click on a tableview when multiple rows are selected.
Its working fine when a single row is selected and then control clicked on it.
The way i am implementing this is shown below:
-(void)doSingleClick
{
NSLog(#"single clicked");
if([[NSApp currentEvent] modifierFlags] & NSControlKeyMask)
{
NSLog(#"control clicked.......");
[NSMenu popUpContextMenu:[self showContextMenu] withEvent:[NSApp currentEvent] forView:tableView];
return;
}
}
and showContextMenu function returns a NSMenu object.
I am dong it this way as my table view for some strange reason does not recognize mouseDown or mouseUp or menuForEvent events.
the problem with the above code segment is, when multiple rows are selected and control clicked, it does not recognize the control click and does not go into that loop and hence not displaying the context menu.
Please suggest me a mechanism to achieve this.
Thanks
I don't recommend the approach that is given in the answers above. Instead, look at the "DragNDropOutlineView" example in Leopard and higher. That, and the release notes, give a proper way to implement contextual menus for a single row, or multiple rows. This includes having AppKit automatically do the proper highlighting.
corbin dunn
(NSTableView Software Engineer)
i hve tableviewcontroller class which is a subclass of NSTableView.
That's very bad naming and suggests that you are not architecting your application properly. Views aren't controllers. Keep them separate.
but this class in which i implemented menuForEvent method but its not getting called for some reason.
Did you make your table view an instance of this class in Interface Builder? If not, your instance is still an NSTableView, and the subclass you wrote is what Ian Hickson might call “a work of fiction”.
Corbin's answer is the best one here.
link text
I don't believe the action method is called when multiple rows are selected.
What would probably be a lot easier would be to override the menuForEvent: method in NSTableView. You'd have to create a subclass of NSTableView to do this, but it would be a cleaner solution.
You could also create an informal protocol (a category on NSObject) and have the NSTableView delegate return the appropriate menu.
#interface NSObject (NSCustomTableViewDelegate)
- (NSMenu *)tableView:(NSTableView *)tableView menuForEvent:(NSEvent *)event;
#end
#implementation NSObject (NSCustomTableViewDelegate)
- (NSMenu *)tableView:(NSTableView *)tableView menuForEvent:(NSEvent *)event {
return nil;
}
#end
And in your NSTableView subclass:
- (NSMenu *)menuForEvent:(NSEvent *)event {
return [[self delegate] tableView:self menuForEvent:event];
}