I have embedded an NSTableView inside an NSScrollView as shown in this example but for some reason, setting the column width only works correctly when initially setting it. Changing it later, i.e. in response to a button click, doesn't do anything at all. I do it like this:
[col setMinWidth:1000];
[col setMaxWidth:1000];
[col setWidth:1000];
After those calls col.width correctly returns 1000 but the NSTableView doesn't show the change. It still looks as before, i.e. longer entries are still cut off using ... even though the column width is 1000 points now.
I have tried to call [tableView setNeedsDisplay:YES] after changing the column width but it doesn't help. Calling setNeedsDisplay on the NSScrollView doesn't help either. I've also tried playing with NSTableColumn's resizingMask and NSTableView's columnAutoresizingStyle but all to no avail. Trying to change the column width just doesn't work here. Any ideas?
EDIT
Here's the code for reference:
listDelegate = [[MyListDelegate alloc] initWithChoices:array];
scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 52, rect.size.width - 2 * 20, 200)];
tableview = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, rect.size.width - 2 * 20 - 16, 200)];
column = [[NSTableColumn alloc] initWithIdentifier:#"Column"];
[column setWidth:400];
[tableview addTableColumn:column];
[tableview setHeaderView:nil];
[tableview setDelegate:listDelegate];
[tableview setDataSource:listDelegate];
[tableview reloadData];
[scrollview setDocumentView:tableview];
[scrollview setHasVerticalScroller:YES];
[scrollview setHasHorizontalScroller:YES];
[[win contentView] addSubview:scrollview];
[scrollview release];
[column release];
The list delegate looks like this:
#interface MyListDelegate : NSObject
{
NSArray *choices;
}
- (id)initWithChoices:(NSArray *)c;
#end
#implementation MyListDelegate
- (id)initWithChoices:(NSArray *)c
{
if(!(self = [super init])) return nil;
choices = c;
return self;
}
- (int)numberOfRowsInTableView:(NSTableView *)_tableView
{
return (int) [choices count];
}
- (id)tableView:(NSTableView *)_tableView objectValueForTableColumn:(NSTableColumn *) tableColumn row:(int)row
{
return [choices objectAtIndex:row];
}
- (BOOL)tableView:(NSTableView *)_tableView shouldEditTableColumn:(NSTableColumn *) tableColumn row:(int)row
{
return NO;
}
#end
And when the button is pressed, the following code is executed:
NSTableColumn *col = [[tableview tableColumns] objectAtIndex:0];
[col setMinWidth:1000];
[col setMaxWidth:1000];
[col setWidth:1000];
It looks like a bug to me. [col setMinWidth:1000] also sets the width to 1000 but doesn't update the table view. [col setWidth:1000] doesn't do anything because the width is 1000. Fix: set the width first:
[col setWidth:1000];
[col setMinWidth:1000];
[col setMaxWidth:1000];
Here's one technique to change the column width of a table view.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDelegate, NSTableViewDataSource> {
NSWindow *window;
NSTableColumn *column1;
}
- (void) myBtnAction;
- (void) buildMenu;
- (void) buildWindow;
#end
#implementation AppDelegate
- (void) myBtnAction {
[column1 setWidth:150];
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new];
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
}
- (void) buildWindow {
#define _wndW 500
#define _wndH 350
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable
backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: #"Test window"];
[window makeKeyAndOrderFront: nil];
// **** TableView_SO **** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect(60, 100, 380, 200)];
NSTableView *tableView = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, 364, 200)];
// create columns for our table
column1 = [[NSTableColumn alloc] initWithIdentifier:#"Col1"];
NSTableColumn * column2 = [[NSTableColumn alloc] initWithIdentifier:#"Col2"];
[column1 setWidth:252];
[column2 setWidth:198];
// generally you want to add at least one column to the table view.
[tableView addTableColumn:column1];
[tableView addTableColumn:column2];
[tableView setDelegate:self];
[tableView setDataSource:self];
[tableView reloadData];
// embed table view in the scroll view, and add the scroll view to window.
[scrlView setDocumentView:tableView];
[scrlView setHasVerticalScroller:YES];
[[window contentView] addSubview:scrlView];
// **** Button **** //
NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 30, 135, 30 )];
[myBtn setBezelStyle:NSBezelStyleRounded ];
[myBtn setTitle: #"Change Col1 Width"];
[myBtn setAction: #selector (myBtnAction)];
[[window contentView] addSubview: myBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWindow];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main (){
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
Related
How do I create a modal sheet window exclusively by programming. Interface builder seems to me over the hand, I'm at the beginning and I want to learn programming, not how I arrange some elements graphically.
I've heard on several programmers that is possible.
I tried without success:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow* mywindow;
NSButton* button;
IBOutlet NSPanel* theSheet;
}
- (void) buildWnd;
#end
#implementation AppDelegate
- (void) buildWnd {
button = [[[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 90, 25)] autorelease];
[button setTitle:#"button"];
[button setTarget:self];
[button setAction:#selector(OnbuttonClick:)];
[button setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
mywindow = [[NSWindow alloc] initWithContentRect: NSMakeRect(100, 100, 700, 500) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing: NSBackingStoreBuffered defer: NO];
[mywindow center];
[mywindow setTitle:#"Sheet example"];
[[mywindow contentView] addSubview:button];
[mywindow setIsVisible:YES];
}
- (IBAction) showTheSheet:(id)sender {
}
-(IBAction) endTheSheet:(id)sender {
[mywindow endSheet: theSheet];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWnd];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
- (IBAction) OnButtonClick:(id)sender {
NSLog(#"OnButtonClick");
[mywindow beginSheet: theSheet
completionHandler:^(NSModalResponse returnCode) {
[NSApp stopModalWithCode: returnCode];
}];
[NSApp runModalForWindow: theSheet];
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
I receive this error message: AppDelegate OnbuttonClick: unrecognized selector sent to instance.
Where I'm wrong please?
You neglected to set up the sheet. This example should run in Xcode by replacing the main.m with the code below and deleting the pre-supplied AppDelegate files:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
NSPanel *sheet;
}
- (void) buildWnd;
#end
#implementation AppDelegate
- (void) showBtnAction:(id)sender {
[window beginSheet: sheet completionHandler:^(NSModalResponse returnCode) {
[NSApp stopModalWithCode: returnCode];
}];
[NSApp runModalForWindow: sheet];
}
-(void) hideSheet:(id)sender {
[window endSheet: sheet];
}
- (void) buildWnd {
window = [[NSWindow alloc] initWithContentRect: NSMakeRect(100, 100, 700, 500) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle:#"Sheet example"];
[window setIsVisible:YES];
// **** Sheet Panel **** //
sheet = [[NSPanel alloc] initWithContentRect:NSMakeRect( 0, 0, 500, 450 )
styleMask:NSWindowStyleMaskDocModalWindow backing:NSBackingStoreBuffered defer:YES];
[sheet center];
[sheet setTitle:#"NSPanel"];
// **** OK Button on Sheet **** //
NSButton *okayBtn = [[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 50, 25)];
[okayBtn setTitle:#"OK"];
[okayBtn setBezelStyle:NSBezelStyleRounded ];
[okayBtn setTarget:self];
[okayBtn setAction:#selector(hideSheet:)];
[[sheet contentView] addSubview:okayBtn];
// **** Show Button **** //
NSButton *showBtn = [[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 150, 25)];
[showBtn setTitle:#"Show sheet"];
[showBtn setBezelStyle:NSBezelStyleRounded ];
[showBtn setAction:#selector(showBtnAction:)];
[showBtn setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[[window contentView] addSubview:showBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect(650, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildWnd];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
I want to set the width of my NSTableColumn to the exact width of the widest entry so that the text doesn't get ellipsized by .... To do that, I'm doing the following whenever a new text entry is inserted:
NSCell *cell = [tableView preparedCellAtColumn:0 row:idx];
NSSize size = [cell cellSize];
if(size.width > widestWidth) {
[tableColumn setWidth:size.width];
widestWidth = size.width;
}
Unfortunately, the width returned by cellSize seems to be a few points off because the last character still gets ellipsized by .... I can easily solve the problem by just adding about 8 points to size.width but of course I want to avoid that because there might be different font configurations where 8 is not enough and I also want the NSTableColumn's width to perfectly fit to that of its widest entry.
That's why I'd like to ask: How can I get the exact width of a row so that I can pass it to NSTableColumn::SetWidth so that the NSTableColumn's width is exactly that of the widest row?
Based on the following example, it appears that [cell cellSize].width may be used to set the column width of a cell-based table view if the greatest cellSize.width is rounded up. The source code may be run in Xcode by replacing 'main.m' with the following and deleting the pre-supplied AppDelegate.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDelegate, NSTableViewDataSource> {
NSWindow *window;
}
#property(strong, nonatomic) NSArray *teams;
- (void) createMenu;
- (void) createWindow;
#end
#implementation AppDelegate
- (id)init{
if(self = [super init])
_teams = [NSArray arrayWithObjects:#"Ravens", #"Chiefs", #"Chargers", #"Bengals", nil];
NSLog(#"teams = %#",_teams);
return self;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
NSLog(#"count = %lu", [_teams count]);
return [_teams count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *team = [_teams objectAtIndex:row];
NSLog(#"team = %#",team);
return [_teams objectAtIndex:row];
}
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)col row:(NSInteger)row {
NSTextFieldCell *cell = [col dataCell];
[cell setBackgroundColor: [NSColor redColor]];
[cell setDrawsBackground:YES];
NSSize size = [cell cellSize];
NSLog(#"cell width = %0.02f",size.width);
return cell;
}
- (void) createMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *appMenuItem = [NSMenuItem new];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit"
action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
}
- (void) createWindow {
#define _wndW 300
#define _wndH 300
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle:#"Test window"];
[window makeKeyAndOrderFront: nil];
// **** Table View with Scroll **** //
NSScrollView * scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 20, _wndH - 230, _wndW - 40, 200)];
[scrollView setBorderType:NSBezelBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setAutohidesScrollers:YES];
NSTableView *tableView = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, 180, 200)];
NSTableColumn *column1 = [[NSTableColumn alloc] initWithIdentifier:#"Col1"];
[[column1 headerCell] setStringValue:#"Teams"];
//Change this to 59 to see ellipsis : longest [cell cellSize].width = 59.33
[column1 setWidth: 60];
[tableView addTableColumn:column1];
[tableView setDelegate:self];
[tableView setDataSource:self];
[tableView reloadData];
// **** Embed table view into scroll view, and add scroll view to window
[scrollView setDocumentView:tableView];
[[window contentView] addSubview:scrollView];
// ***** Quit btn ***** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self createMenu];
[self createWindow];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *myDelegate = [[AppDelegate alloc] init];
[application setDelegate:myDelegate];
[application run];
return 0;
}
When I ran an old cell-based demo with manual reference counting and used method dataCellForTableColumn: to measure [cell cellSize].width I got the values shown in the first image for the array items listed. When I set the column width to 60 (by rounding longest string length of 59.33 up) there was no problem. When I set the col width to 59 (by rounding down) I got the ellipsis for Charge.... I can not explain why 'Bengals' has a greater cell width than 'Chargers'. The 'team' was taken from another method, objectValueForTableColumn: and my have something to do with the order in which they are called? Second image shows the correct result by rounding up the greatest cell width.
I'll try and post the source if I ever get it converted to arc.
I have created a custom NSView with an AVPlayer embedded and it is not showing at all
this is my header:
#interface VideoPlayer : NSView
- (void)loadVideo;
#end
Implementation:
#implementation VideoPlayer
AVPlayer *avPlayer;
AVPlayerLayer* playerLayer;
- (instancetype)initWithFrame:(NSRect)rect {
self = [super initWithFrame:rect];
[self setWantsLayer:YES];
[self setNeedsDisplay:YES];
self.hidden = NO;
return self;
}
-(void) loadVideo {
[avPlayer pause];
avPlayer = nil;
playerLayer = nil;
NSURL *videoURL = [NSURL fileURLWithPath:#"file://~/Documents/tests.mp4"];
//same error with a valid url
//NSURL *videoURL = [NSURL URLWithString:#"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"];
avPlayer = [AVPlayer playerWithURL:videoURL];
playerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
playerLayer.frame = self.frame;//or your desired CGRect
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
//playerLayer.masksToBounds = YES;
[self.layer addSublayer:playerLayer];
[avPlayer play];
}
#end
And this is how I am creating the view:
view = [[VideoPlayer alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)];
view.hidden = false;
[view loadVideo];
[parent_view addSubview:view];
I have tried multiple combinations, but the result is always the same... Nothing is being rendered on the application.
On the other hand, if I override the method drawRect in my view like this:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
I am getting a white rectangle where it is suppose to show my video which is expected. So I assume that I am missing something else, but most of the examples are using UIView which is not an option for me at this moment (I am working with some specific constraints)
Any thoughts?
Thank you
Update:
This finally worked for me:
-(void) loadVideo {
AVPlayer *avPlayer = [AVPlayer playerWithURL:[NSURL URLWithString:#"file://localhost/Users/xxxxxxxx/Documents/xxxxxxx.mp4"]];
AVPlayerView *playerView = [[AVPlayerView alloc] initWithFrame:self.bounds];
[playerView setPlayer:avPlayer];
[self addSubview:playerView];
[playerView.player play];
}
To perhaps make things a little clearer the following source code will create a basic AVPlayer for audio files. Note that the addition of both AVKit and AVFoundation frameworks are required for AVPlayerView and AVPlayer respectively. The code uses automatic reference counting and may be run in Terminal or used in Xcode by replacing main.m and AppDelegate and deleting the main nib in info.plist. To run in Terminal, copy/paste code into a file named avplayer.m and use the cmdLine as shown below. Apple docs state that it only runs on MacOS.
/*
To run in Terminal: clang avplayer.m -fobjc-arc -framework Cocoa -framework AVKit -framework AVFoundation -o avplayer && ./avplayer
*/
#import <Cocoa/Cocoa.h>
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
AVPlayerView *playerView;
}
- (void) openAction;
- (void) buildMenu;
- (void) buildWindow;
#end
#implementation AppDelegate
- (void) openAction {
NSOpenPanel *op = [NSOpenPanel openPanel];
if ( [op runModal] == NSModalResponseOK ) {
AVPlayer *player = [AVPlayer playerWithURL:[op URL]];
[playerView setPlayer:player];
[window setTitleWithRepresentedFilename:[[op URL]lastPathComponent]];
}
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new] ;
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
}
- (void) buildWindow {
#define _wndW 500
#define _wndH 400
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH ) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: #"Test window"];
[window makeKeyAndOrderFront: nil];
// **** AVPlayerView **** //
playerView = [[AVPlayerView alloc] initWithFrame:NSMakeRect( 0, 60, _wndW, _wndH - 60)];
[[window contentView] addSubview:playerView];
// **** Open Button **** //
NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 20, 125, 30 )];
[myBtn setBezelStyle:NSBezelStyleRounded ];
[myBtn setTitle: #"Open audio file"];
[myBtn setAction: #selector (openAction)];
[[window contentView] addSubview: myBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWindow];
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
#end
int main () {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
Make sure that you add the AVKit framework to your project.
There is a header in AVKit framework called AVPlayerView.h
Then all you need to do to see the player is to call it:
// **** AVPlayer ***** //
AVPlayerView *playerView = [[AVPlayerView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW, _wndH - 100)];
[[window contentView] addSubview:playerView];
I have a programmatic demo which I could post if you are unable to get it to work.
Here is the thing:
I have created a custom NSMenuItem with a custom NSView in it.
Everything works fine except that I can't get the NSMenuItem to get highlighted (= change the background color on mouseover).
I'm trying to do it inside the drawRect method, as shown in other answers posted here.
What am I doing wrong?
The NSView subclass:
#interface customView : NSView
#end
#implementation customView
- (id)initWithFrame:(NSRect)frame
{
NSRect theRect = NSMakeRect(0, 0, 200, 30);
self = [super initWithFrame:theRect];
if (self) {
NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:theRect
options: (NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow |NSTrackingActiveAlways)
owner:self userInfo:nil];
[self addTrackingArea:trackingArea];
}
return self;
}
#define menuItem ([self enclosingMenuItem])
- (void) drawRect: (NSRect) rect {
BOOL isHighlighted = [menuItem isHighlighted];
if (isHighlighted) {
//this nslog never happens
NSLog(#"it's highlighted");
}
- (void)mouseUp:(NSEvent*) event {
NSMenuItem* mitem = [self enclosingMenuItem];
NSMenu* m = [mitem menu];
[m cancelTracking];
NSLog(#"you clicked the %ld item",[m indexOfItem: mitem]);
}
#end
The NSMenuItem subclass:
(I add subviews on the custom view here so i can have access to the controls through the NSMenuItem instance)
#interface customItem : NSMenuItem{
}
-(void)setTheText:(NSString*)theString;
#property NSTextField *theLabel;
#end
#import "customItem.h"
#import "customView.h"
#implementation customItem
#synthesize theLabel;
-(id)init{
if (self){
customView *cv = [[customView alloc] init];
theLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 8, 130, 17)];
[theLabel setEditable:NO];
[theLabel setBordered:NO];
NSButton *myButton = [[NSButton alloc] initWithFrame:NSMakeRect(170, 7, 20, 20)];
NSButton *myButton1 = [[NSButton alloc] initWithFrame:NSMakeRect(150, 7, 20, 20)];
[myButton setBezelStyle:NSCircularBezelStyle];
[myButton1 setBezelStyle:NSCircularBezelStyle];
[myButton setTitle:#""];
[myButton1 setTitle:#""];
[cv addSubview:myButton];
[cv addSubview:myButton1];
[cv addSubview:theLabel];
[self setView:cv];
[theLabel setStringValue:#"A Value "];
}
return self;
}
-(void)setTheText:(NSString *)theString{
[theLabel setStringValue:theString];
}
#end
And this is the App Delegate :
#interface AppDelegate : NSObject <NSApplicationDelegate>{
NSStatusItem *statusItem;
IBOutlet NSMenu *theMenu;
}
#property (assign) IBOutlet NSWindow *window;
#end
#import "customItem.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
}
- (void)awakeFromNib{
statusItem = [[NSStatusBar systemStatusBar]
statusItemWithLength:NSSquareStatusItemLength];
NSBundle *bundle = [NSBundle mainBundle];
NSImage *statusImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:#"barIcon" ofType:#"png"]];
NSImage *highlightImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:#"barIcon_H" ofType:#"png"]];
[statusItem setImage:statusImage];
[statusItem setAlternateImage:highlightImage];
[statusItem setMenu:theMenu];
[theMenu removeAllItems];
customItem *mi = [[customItem alloc] init];
[theMenu addItem:mi];
customItem *mi2 = [[customItem alloc] init];
[theMenu addItem:mi2];
}
#end
This is what i get:
No need to add Booleans or anything else, you can do it from within your custom NSView which is attached to your NSMenuItem
- (void)drawRect:(NSRect)rect {
[super drawRect:rect];
//Handle the hightlight
if ([[self enclosingMenuItem] isHighlighted])
{
[self.lbl_title setTextColor:[NSColor whiteColor]];
[self.lbl_amount setTextColor:[NSColor colorWithDeviceRed:151.0f/255.0f green:164.0f/255.0f blue:179.0f/255.0f alpha:1.0f]];
[[NSColor selectedMenuItemColor] setFill];
}
else
{
[self.lbl_title setTextColor:[NSColor blackColor]];
[self.lbl_amount setTextColor:[NSColor whiteColor]];
[[self backgroundColor] setFill];
}
NSRectFill(rect);}
OK i think i got it.
I added a public bool variable in the NSView subclass.
Then i used
-(void)mouseEntered:(NSEvent *)theEvent
and
-(void)mouseExited:(NSEvent *)theEvent
to set the variable to YES or to NO. After setting the variable i used
[self setNeedsDisplay:YES]
to call
-(void) drawRect: (NSRect) rect
That's how i got it working :)
Here is the right way of changing the background colour (highlighting the item) without maintaining a local variable and force the view to draw again,
-(void)mouseEntered:(NSEvent *)event {
self.layer.backgroundColor = [[NSColor blueColor] colorWithAlphaComponent:0.3].CGColor;
[theLabel setTextColor:[NSColor whiteColor]];
}
-(void)mouseExited:(NSEvent *)event {
self.layer.backgroundColor = [NSColor clearColor].CGColor;
[theLabel setTextColor:[NSColor blackColor]];
}
Make sure you also set [self setWantsLayer:YES] before changing the layer background colour.
Can anyone please suggest some links for using UITextField in cocos2d.
I want to press on label, then the UITextField should get selected and I need to edit on that UITextField.
I'm doing this in a current project to allow for entering the number of the level to start playing at, so that's why my variables and methods are named the way they are; you should probably adjust these to make sense for you.
In your app controller, define this as an instance variable:
UITextField *levelEntryTextField;
Create it inside applicationDidFinishLaunching:
levelEntryTextField = [[UITextField alloc] initWithFrame:
CGRectMake(60, 165, 200, 90)];
[levelEntryTextField setDelegate:self];
Define a method to activate the text field. You should also declare it in the header file for your app controller.
- (void)specifyStartLevel
{
[levelEntryTextField setText:#""];
[window addSubview:levelEntryTextField];
[levelEntryTextField becomeFirstResponder];
}
This will make pressing "return" on the keypad end editing
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
//Terminate editing
[textField resignFirstResponder];
return YES;
}
This is triggered when the editing is actually done.
- (void)textFieldDidEndEditing:(UITextField*)textField {
if (textField==levelEntryTextField) {
[levelEntryTextField endEditing:YES];
[levelEntryTextField removeFromSuperview];
// here is where you should do something with the data they entered
NSString *result = levelEntryTextField.text;
}
}
Now to actually set things in motion, you put this somewhere. I call this from within one of my Scene classes, in response to a user action:
[[[UIApplication sharedApplication] delegate] specifyStartLevel];
I took the example that Jack provided and actually created a working project, this was done using the Cocos2D 0.7.1 XCode Template, and then just editting the *AppDelegate.m/.h files, which are provided below in there entirety. I also modified some of what Jack said, because I feel that creating the UITextField in the appDidFinishLoading would utilize a bit too much memory, especially if the text field is not used all the time ... this solution creates the text field only when it is needed, the sample draws an empty Cocos2D Layer scene, and on screen touch, it displays the text field for you to start entering text into. It will spit out the result of what you entered to the Console - you can pass this to whatever is necessary in your own code.
the .h
#import <UIKit/UIKit.h>
#import "cocos2d.h"
#interface MYSCENE : Layer <UITextFieldDelegate>
{
UITextField *myText;
}
-(void)specificStartLevel;
#end
#interface textFieldTestAppDelegate : NSObject <UIAccelerometerDelegate, UIAlertViewDelegate, UITextFieldDelegate, UIApplicationDelegate>
{
UIWindow *window;
}
#end
and then the .m
#import "textFieldTestAppDelegate.h"
#implementation MYSCENE
-(id) init
{
self = [super init];
isTouchEnabled = YES;
return self;
}
-(BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self specifyStartLevel];
return kEventHandled;
}
-(void)specifyStartLevel {
myText = [[UITextField alloc] initWithFrame:CGRectMake(60, 165, 200, 90)];
[myText setDelegate:self];
[myText setText:#""];
[myText setTextColor: [UIColor colorWithRed:255 green:255 blue:255 alpha:1.0]];
[[[[Director sharedDirector] openGLView] window] addSubview:myText];
[myText becomeFirstResponder];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[myText resignFirstResponder];
return YES;
}
-(void)textFieldDidEndEditing: (UITextField *)textField {
if(textField == myText) {
[myText endEditing:YES];
[myText removeFromSuperview];
NSString *result = myText.text;
NSLog([NSString stringWithFormat:#"entered: %#", result]);
} else {
NSLog(#"textField did not match myText");
}
}
-(void) dealloc
{
[super dealloc];
}
#end
#implementation textFieldTestAppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setUserInteractionEnabled:YES];
[[Director sharedDirector] setDisplayFPS:YES];
[[Director sharedDirector] attachInWindow:window];
Scene *scene = [Scene node];
[scene addChild: [MYSCENE node]];
[window makeKeyAndVisible];
[[Director sharedDirector] runWithScene: scene];
}
-(void)dealloc
{
[super dealloc];
}
-(void) applicationWillResignActive:(UIApplication *)application
{
[[Director sharedDirector] pause];
}
-(void) applicationDidBecomeActive:(UIApplication *)application
{
[[Director sharedDirector] resume];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[[TextureMgr sharedTextureMgr] removeAllTextures];
}
#end
To add Text field in cocos2d as below code
first of all you add view in Scene and afetr add textfield add in view thats very easy.
-(id) init
{
if( (self=[super init]) )
{
// add view in scene
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 568)];
view.backgroundColor = [UIColor redColor];
// add textfield in view
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 140, 300, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15];
textField.placeholder = #"enter text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDone;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.delegate = self;
[view addSubview:textField];
// add view in scene
[[[CCDirector sharedDirector] view] addSubview:view];
}
return self;
}
you can also use CCTextfield in cocos2d best example is https://github.com/iNinja/CCTextField
Try the following CCNode subclass, CCMenuItemTextField, to use text fields in cocos2d.
The class is directly subclassed from CCMenuItemSprite. When tapped, the "selected" method is called and a UITextField is added to the main window. After editing is done, "unselected" method is called and the UITextField is removed from screen. User's input is saved to a CCLabelTTF node, which position itself exactly as the original UITextField.
CCMenuItemTextField.h
#interface CCMenuItemTextField : CCMenuItemSprite<UITextFieldDelegate> {
UITextField *textField_;
CCLabelTTF *label_;
CGFloat paddingLeft_;
}
#property (readonly, nonatomic) UITextField *textField;
#property (readonly, nonatomic) CCLabelTTF *label;
#property (assign, nonatomic) CGFloat paddingLeft;
- (void)selected;
- (void)unselected;
- (void)setFontSize:(CGFloat)size;
- (NSString*)text;
- (void)setText:(NSString*)text;
#end
CCMenuItemTextField.m
#import "CCMenuItemTextField.h"
#implementation CCMenuItemTextField
#synthesize
textField = textField_,
label = label_,
paddingLeft = paddingLeft_;
- (id)init
{
CCSprite *normalSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
CCSprite *selectedSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
CCSprite *disabledSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
return [self initWithNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:disabledSprite];
}
- (id)initWithNormalSprite:(CCNode<CCRGBAProtocol> *)normalSprite
selectedSprite:(CCNode<CCRGBAProtocol> *)selectedSprite
disabledSprite:(CCNode<CCRGBAProtocol> *)disabledSprite
{
self = [super initWithNormalSprite:normalSprite
selectedSprite:selectedSprite
disabledSprite:disabledSprite
target:self
selector:#selector(selected)];
if (self) {
paddingLeft_ = 3.0;
textField_ = [[UITextField alloc] init];
[textField_ setTextColor:[UIColor blackColor]];
[textField_ setFont:[UIFont systemFontOfSize:18]];
label_ = [[CCLabelTTF node] retain];
[label_ setAnchorPoint:ccp(0,0.5)];
[label_ setFontSize:18];
[label_ setVisible:NO];
[label_ setColor:ccBLACK];
[self addChild:label_];
}
return self;
}
- (void)dealloc
{
[label_ release];
[textField_ release];
[super dealloc];
}
// --------------------------------
// Public
// --------------------------------
- (void)selected
{
[super selected];
[label_ setVisible:NO];
CGAffineTransform transform = [self nodeToWorldTransform];
float textFieldHeight = textField_.font.lineHeight;
float width = self.contentSize.width;
float height = self.contentSize.height;
float left = transform.tx + paddingLeft_;
float top = 480 - transform.ty - height + (height - textFieldHeight) / 2;
[textField_ setFrame:CGRectMake(left, top, width, height)];
[[[[CCDirector sharedDirector] view] window] addSubview:textField_];
[textField_ becomeFirstResponder];
[textField_ setDelegate:self];
}
- (void)unselected
{
[super unselected];
[label_ setVisible:YES];
[label_ setPosition:ccp(paddingLeft_, self.contentSize.height/2)];
NSString *text = textField_.text ? textField_.text : #"";
[label_ setString:text];
[textField_ resignFirstResponder];
[textField_ removeFromSuperview];
}
- (NSString*)text
{
return [label_ string];
}
- (void)setText:(NSString*)text
{
[label_ setString:text];
[textField_ setText:text];
}
// --------------------------------
// UITextFieldDelegate
// --------------------------------
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
[self unselected];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField*)textField {
[self unselected];
}
- (void)setFontSize:(CGFloat)size
{
[label_ setFontSize:size];
[textField_ setFont:[UIFont systemFontOfSize:size]];
}
// --------------------------------
// CCNode
// --------------------------------
- (void)onExitTransitionDidStart
{
[super onExitTransitionDidStart];
[self unselected];
}
#end