Feb 262014
 

In some case we want to track mouse movement in table view cell. This can be done by subclassing the NSTableViewCell if the table is view type class.

The idea in this example is to show ‘Order fruit’ button only when the mouse is move into the fruit cell. Code below how this is done by subclassing NSTableViewCell.


@implementation WLFruitCellView
{
    NSTrackingArea *_trackingArea;
}

- (void)awakeFromNib{
    [self createTrackingArea];
    
    //hide the button first
    [self.eatButton setHidden:YES];
}


/**
 Create tracking area when mouse move in
 */
- (void)createTrackingArea
{
    _trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseEnteredAndExited|NSTrackingActiveInActiveApp owner:self userInfo:nil];
    [self addTrackingArea:_trackingArea];
    
    NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
    mouseLocation = [self convertPoint: mouseLocation
                              fromView: nil];
    
    if (NSPointInRect(mouseLocation, [self bounds]))
    {
        [self mouseEntered: nil];
    }
    else
    {
        [self mouseExited: nil];
    }
}

- (void)drawRect:(NSRect)dirtyRect
{
	[super drawRect:dirtyRect];
	
    // Drawing code here.
}

- (void)mouseEntered:(NSEvent *)theEvent{
    
    self.eatButton.title = [NSString stringWithFormat:@"Order %@", self.textField.stringValue];
    [self.eatButton setHidden:NO];
    NSLog(@"Entered '%@'", self.textField.stringValue);
}

- (void)mouseExited:(NSEvent *)theEvent{
    [self.eatButton setHidden:YES];
    NSLog(@"Exited '%@'", self.textField.stringValue);
}

Below is example project for tracking mouse in NSTableView or NSOutlineView, the method is same which is subclass NSTableViewCell. In this project binding is used for displaying fruits content.

Apr 262013
 

Dalam pos kali ini saya akan terangkan bagaimana untuk buat table dalam Mac OSX.

Apa yang akan dipelajari adalah
– NSTableView
– Delegate

Pertama sekali anda perlu faham maksud delegate. Contoh yang ringkas adalah delegate atau wakil untuk
sesebuah negara atau organisasi. Mereka bertindak /bercakap sebagai wakil bagi negara atau organisasi tersebut.

Begitu juga delegate untuk objective-c, contohnya class NSTableView juga menggunakan delegate untuk
– mendapatkan data-data untuk display table daripada delegate.
– memberitahu table telah diclick kepada delegate.
dan sebagainya.

1. Pertama sekali, buat Xcode projek baru dan pilih Cocoa Application dalam OS X. Pastikan Use Automatic Reference Counting dicheck. Namakan nama projek BasicTable.

2. Kemudian pergi ke MainMenu.Xib dan tambah table view ke main window. Kemudian double click kedua2 colum header dan namakan ia Nama dan Kerjaya.

Drag Table dari Object Library ke window

Table yang telah didrag dari Object Library ke window

3. Pergi ke AppDelegate.h , dan tengok di , semua yang berada dalam kurungan <> adalah untuk menunjukkan class ini iaitu AppDelegate adalah delegate kepada NSApplication.

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject

@property (assign) IBOutlet NSWindow *window;

@end

4. Buat NSMutableArray property bernama persons di AppDelegate.h

5. Sekarang kita mahu tambah table view delegate pula. Tambah code seperti di bawah. NSTableViewDataSource bermakna table view (dari NSTableView) akan wakilkan AppDelegate untuk mendapatkan maklumat untuk display table dan NSTableViewDelegate pula adalah untuk programmer melakukan aksi yang sepatutnya setelah table row diclick, didrag dan sebagainya. Untuk mengetahui apa function yang disediakan oleh delegate ini, guna Command Key + Left Mouse pada delegate. Code akhir untuk AppDelegate.h adalah seperti di bawah.

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource, NSTableViewDelegate>

@property (assign) IBOutlet NSWindow *window;
@property (nonatomic, strong) NSMutableArray *persons;

@end

6. Sekarang anda perlu connect table ke AppDelegate.h. Tekan Assistant Editor dan AppDelegate.h akan terbuka bersebelahan dengan MainMenu.xib. Pastikan table view dihighlight di Document Outline. Untuk connect outlet, hold Ctrl key kemudian drag table view ke AppDelegate.h menggunakan mouse. Namakan ia sebagai tableView(Sila refer   Simple Calculator  jika anda mempunyai masalah sehingga step ini)

Xcode 5 copy

Drag table view dari IB ke AppDelegate.h

Namakan table view IBOutlet sebagai tableView

Namakan table view IBOutlet sebagai tableView

7. Cuba run tetapi masih tiada apa akan berlaku. Sebelum ini anda connect tableView ke AppDelegate, tetapi anda masih belum set delegate untuk tableView itu. Ada dua cara untuk set delegate iaitu dari Interface Builder atau guna code.

8. Untuk set delegate guna code, pergi ke AppDelegate.m dan tambah code seperti berikut

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    self.tableView.delegate = self;  //atau sama juga [self.tableView setDelegate:self]
    self.tableView.dataSource = self;
}

9. Try run program. Anda dapati pada ruangan output seperti berikut:
*** Illegal NSTableView data source (). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
Ini kerana anda telah set delegate untuk table tetapi tidak implement di dalam AppDelegate.

10. Untuk hilangkan warning ini, tambah dua method tersebut dalam AppDelegate.m

//NSTableView tanya berapa bilangan row untuk table
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{

}

//NSTableView tanya object (string dsb) untuk didisplay bagi setiap colum dan row
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{

}

11. Apabila run sekali lagi, tiada lagi warning kerana kita telahpun implement method yang diperlukan walaupun masih tidak melakukan apa-apa. Sekarang kita akan buat array untuk digunakan oleh table.
Ubah code dalam AppDelegate.m anda supaya seperti di bawah.

#import "AppDelegate.h"

NSString *NameKey = @"nameKey";
NSString *KerjayaKey = @"kerjayaKey";

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    self.tableView.delegate = self;
    self.tableView.dataSource = self;

    self.persons = [NSMutableArray array];

    NSDictionary *Zakir = @{NameKey: @"Zakir", KerjayaKey: @"Cikgu"}; //cara lama:
    NSDictionary *Husin = @{NameKey: @"Husin", KerjayaKey: @"Peguam"};
    NSDictionary *Hasan = @{NameKey: @"Hasan", KerjayaKey: @"Pensyarah"};

    [self.persons addObject:Zakir];
    [self.persons addObject:Husin];
    [self.persons addObject:Hasan];

}

//NSTableView tanya berapa bilangan row untuk table
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{

}

//NSTableView tanya object (string dsb) untuk didisplay bagi setiap colum dan row
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{

}

@end

Code Explanation:
line 3-4: Kita hanya declare constant untuk digunakan pada dictionary key. Kemungkinan untuk tersalah taip berkurang jika ia akan banyak digunakan.
line 14: Initialize array.
line 15-19: Buat dictionary untuk setiap person, dalam dictionary itu ada ada nama dan kerjaya.
line 21-23: Masukkan setiap dictionary yang dibuat ke dalam persons array.

12. Untuk tableView mendapatkan data supaya kita berfungsi, kita perlu tambah code dalam method numberOfRowsInTableView: dan tableView:objectValueForTableColumn:. Tambah code seperti dibawah

//NSTableView tanya berapa bilangan row untuk table
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    //bilangan row adalah sebanyak bilangan person
   return  [self.persons count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSString *value;
    if ([tableColumn.identifier isEqualToString:@"name"]) {
        value = self.persons[row][NameKey]; //atau sama juga: [[self.persons objectAtIndex:row] valueForKey:NameKey];
    }
    else if ([tableColumn.identifier isEqualToString:@"kerjaya"]) {
        value = self.persons[row][KerjayaKey];
    }
    return value;
}

Code Explanation:
line 4 &7 : Table column identifier di cek supaya sama ada nama atau kerjaya
line 5 &8 : Set value untuk ambil data daripada, dari array untuk index ke row dan key NameKey atay KerjayaKey.

13. Run program. Tetapi nampaknya masih tiada apa yang berlaku. Ini disebabkan kita masih belum set identifier untuk table column. Pergi semula ke IB, highlight column Nama dan Kerjaya, dan set identifier di Identity Inspector sebagai ‘name’ dan ‘kerjaya’. Ambil perhatian bahawa identifier key ini tidak berkaitan dengan NameKey atau KerjayaKey constant. Anda boleh guna apa-apa nama sahaja.

Select table column dan set identifier di Identity Inspector

Select table column dan set identifier di Identity Inspector

14. Run dan sepatutnya anda dapat lihat table dengan person data yang dibuat. Bagaimana kalau nak tambah data? Jawapannya adalah dengan modify persons array kemudian reload data. Untuk demo secara ringkas, tambah push button di IB dan create IBAction di AppDelegate.m dan namakan ia addPerson.

Drag Add Person button to AppDelegate.m and name it addPerson

Drag Add Person button to AppDelegate.m and name it addPerson

15. Dalam addPerson:, ubah code menjadi seperti berikut

- (IBAction)addPerson:(id)sender {
    [self.persons addObject:@{NameKey: @"Ali", KerjayaKey: @"Jurutera"}];
    [self.tableView reloadData];
}

Code Explanation:
Kita lihat dalam code ini kita tambah NSDictionary baru, kemudian data direload supaya numberOfRowsInTableView: dan tableView:objectValueForTableColumn:row: dipanggil untuk update table.

16. Run dan tekan Add Person, jika anda tekan berkali-kali person baru akan sentiasa bertambah. Jika mahu tambah data person selain Ali, perlu lagi ubah code ini. Tetapi setakat ini cukuplah untuk tahu bagaimana menggunakan table.

Tekan Add Person untuk tambah data

Tekan Add Person untuk tambah data

Mar 102013
 

Salam,

Dalam post ni, saya akan ajar bagaimana untuk buat Simple Calculator app guna Xcode
Anda akan belajar beberapa perkara

1. Cara menggunakan interface builder
2. Cara connect interface builder dengan code
3. NSButton, NSPopUpButton, NSTextField

1. Buat projek baru Xcode dan pilih Cocoa Application, pada product name guna SimpleCalculator (tak kisah pn apa nama sebenarnya)

)Xcode 10

2. Pastikan uncheck Use Core Data dan check Use Automatic Reference Counting.

*Core Data adalah untuk app yang berasas database. Automatic Reference Counting (ARC) membolehkan kita tidak perlu fikir banyak pasal memory management kerana compiler yang ambil tugas itu.

3. Apabila project telah dibuat, pergi ke MainMenu.xib (xib dalam sebutan dipanggil nib). Apa yang anda lihat dipanggil Interface Builder (IB).

4. Object Library adalah dimana object yang akan diguna untuk interface.

SimpleCalculator.xcodeproj — MainMenu

Interface Builder

4. Pada Object Library, drag object supaya menjadi seperti rajah di bawah. Pada Object Library anda boleh search di bawahnya dan drag ke SimpleCalculator Window

Text Field (NSTextField)
Pop Up Button (NSPopUpButton)
Label (NSTextField)
Push Button (NSButton)

5. Tukar title supaya menjadi seperti dibawah. Anda boleh tukar title dengan double click pada object ataupun dengan tukar title di Attributes Inspector.

Xcode 8

Object yang telah di drag ke Window

5. Tekan butang Run dan anda ia akan memaparkan Window seperti yang telah dibuat di IB tetapi ia masih tidak boleh melakukan apa2.

6. Pada pop up button, kita mahu ia sebagai math operator, double click pada popup button, kemudian double click setiap menu item dan namakan seperti rajah di bawah.

Pada mulanya anda hanya ada 3 menu item, untuk tambah satu lagi menu item, click pada mana2 menu item. Kemudian copy dan paste menggunakan keyboard.

Menu items dalam pop up button

Menu items dalam pop up button

7. Bahagian interface sudah siap. Sekarang kita perlu connect object di dalam IB kepada AppDelegate. Untuk ini tekan Assistant Editor

Xcode

8. Selepas tekan Assistant Editor, sepatutnya view akan terbahagi 2 bahagian seperti di bawah.

SimpleCalculator

9. Untuk connect setiap object ke AppDelegate, hold Ctrl key, kemudian drag object ke AppDelegate.h menggunakan mouse.

Xcode 6

Connect outlet by dragging from IB to AppDelegate.h

10. Pastikan Connection adalah Outlet untuk setiap object melainkan Calculate button gunakan connection Action.

Xcode 4

11. Setelah siap setiap nama sepatutnya seperti berikut.

*IBOutlet bermaksud sesuatu property itu diconnect dengan IB supaya kita boleh mendapat value dan sebagainya. manakala IBAction bermaksud sesuatu Action (method) akan dipanggil setelah diclick di interface

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *firstTextField;
@property (weak) IBOutlet NSPopUpButton *operatorPopup;
@property (weak) IBOutlet NSTextField *secondTextField;
@property (weak) IBOutlet NSTextField *resultTextField;

- (IBAction)calculate:(id)sender;

12. Sekarang pergi ke AppDelegate.m, anda akan dapati – (IBAction)calculate:(id)sender. Ia secara automatik dibuat oleh Xcode selepas di connect.

13. Sekarang dalam AppDelegate.m tambah seperti dibawah.

- (IBAction)calculate:(id)sender
{
    NSLog(@"In calculate method!");
}

14. Kemudian Run dan tekan butang Calculate. Jika betul maka dalam Output Area iaitu bahagian bawah akan tertulis seperti berikut

2013-03-09 13:53:32.758 SimpleCalculator[4680:303] In calculate method!

14. Dalam method calculate:, tukar code menjadi seperti di bawah

- (IBAction)calculate:(id)sender {
    NSLog(@"In calculate method!");
    CGFloat firstNumber = self.firstTextField.floatValue;
    CGFloat secondNumber = self.secondTextField.floatValue;
    CGFloat result = 0;

    switch (self.operatorPopup.indexOfSelectedItem) {
        case 0: //X
            result = firstNumber * secondNumber;
            break;
        case 1: // /
            result = firstNumber / secondNumber;
            break;
        case 2: //+
            result = firstNumber + secondNumber;
            break;
        case 3: //-
            result = firstNumber - secondNumber;
            break;
        default:
            break;
    }
    self.resultTextField.floatValue =result;
}

15. Run dan cuba kalculator yang telah siap!

16. Dalam code ni mula2 kita ambil nilai daripada textfield di IB dan masukkan dalam firstNumber dan secondNumber.

17. Kemudian untuk tahu operator mana yang dipilih kita gunakan switch dan method dari NSPopupButton indexOfSelectedItem. Index adalah bermula dari 0, daripada nilai index kita buat operasi yang sewajarnya ke dalam variable result.

18. Akhirnya nilai result di pas ke resultTextField untuk update interface.

*Jika tak faham sesuatu fungsi, documentation sangatlah berguna. Pada bahagian sebelah kanan di Quick Help, apabila anda tekan cursor mouse contohnya di indexOfSelectedItem. Quick Help akan tulis description untuk indexOfSelectedItem. Kemudian tekan NSPopUpButton Class Reference untuk maklumat lebih lanjut tentang class NSPopUpButton ni.

Quick Help

Quick Help