NSPopUpButton

NSPopUpButton

Application Kit -NSPopUpButton

ポップアップの枠を消す

Keywords: setBordered

ポップアップメニューには、Aqua の枠が付いているけど、たまにそれがないやつがあるじゃない?下の図の右側のようなやつだ。

borderLess.jpg

これを作るにはどうするか?setBordered: を使うんだ。

Application Kit/NSCell.h

- (void)setBordered:(BOOL)flag;

NSCell の API なんで注意。これを、NSPopUpButtonCell に対して呼んでやるんだ。

(sample)

 NSPopUpButton* popUp;
 [[popUp cell] setBordered:NO];

これで枠が消えるよ。




Application Kit - NSPopUpButton

Cocoa バインディングでエンコーディングメニューを作る

Keywords: Cocoa Bindings, _popUpItemAction:

Cocoa バインディングを利用して、エンコーディングを選択するためのポップアップメニューを作ってみよう。このポップアップメニューは、選択できるエンコーディングの一覧を表示するんだ。で、エンコーディングを選択すると、その値が Cocoa バインディングを利用して、他のオブジェクトに通知される。また、他のオブジェクトからのエンコーディングの変更通知を受け取ると、メニューの選択項目が変わるんだ。

こういうメニューを実装するには、2 つの機能が必要になる。1 つは、エンコーディングのメニューを作るもの。もう 1 つは、選択されたエンコーディングの値を保持するモデルクラスを提供することだ。今回は、この 2 つの機能を 1 つの Encoding というクラスで実装しよう。

Encoding クラスの説明の前に、ポップアップメニューをどうバインディングするのかを考えよう。ポップアップメニューである NSPopUpButton は、Interface Builder で調べてみると、選択された項目に対するバインディングは、selectedIndex、selectedObject、selectedTag、selectedValue といったものがあることが分かる。このメニューでは、ポップアップメニューで選択された項目である NSMenuItem と、エンコーディングを表す NSStringEncoding を関連づける必要がある。NSStringEncoding は、実際のところ unsigned 型なので、ここでは NSMenuItem のタグを使うことにしよう。だから、バインディングする項目は、selectedTag になる。

Encoding クラスは、unsigned 型の encodingValue というプロパティを提供することにしよう。そして、ポップアップメニューは、selectedTag を encodingValue にバインディングする。この設定は、次の図のようになるんだ。

encodingBindings.jpg

次に、エンコーディングのメニューの作成を考えよう。これはバインディングを使うと、NSString でしか設定できなかったり何かと面倒くさいので、手で作ることにする。Encoding クラスには、ポップアップメニューへの参照を持たせる。そして、awakeFromNib メソッドの中で、メニューを作るんだ。たとえば、次のようにする。

EncodingsMenu/Encodings.m

// メニューに表示するエンコーディングです
static CFStringEncodings _cfEncodings[] = {
 kCFStringEncodingShiftJIS, // Japanese (Shift JIS)
 kCFStringEncodingISO_2022_JP, // Japanese (ISO 2022-JP)
 kCFStringEncodingEUC_JP, // Japanese (EUC)
 kCFStringEncodingShiftJIS_X0213_00, // Japanese (Shift JIS X0213)
 kCFStringEncodingInvalidId,
 kCFStringEncodingUTF8, // Unicode (UTF-8)
 kCFStringEncodingInvalidId,
 kCFStringEncodingISOLatin1, // Western (ISO Latin 1)
 kCFStringEncodingMacRoman, // Western (Mac OS Roman)
};

@implementation Encodings

- (void)awakeFromNib
{

    // NSMenuのインスタンスを作ります
 NSMenu* encodingMenu;
 encodingMenu = [[[NSMenu alloc]
      initWithTitle:@"encoding"] autorelease];

 int i;
 for (i = 0; i < sizeof(_cfEncodings) / sizeof(CFStringEncodings); i++) {
    id <NSMenuItem> menuItem;

    if (_cfEncodings[i] == kCFStringEncodingInvalidId) {
      // セパレータアイテムを作ります

            menuItem = [NSMenuItem separatorItem];
    }
    else {
      // CFStringEncodingをNSStringEncodingに変換します
      NSStringEncoding encoding;
      encoding = CFStringConvertEncodingToNSStringEncoding(
         _cfEncodings[i]);

      // エンコーディングの名前を取得します
      NSString* encodingName;
      encodingName = [NSString
          localizedNameOfStringEncoding:encoding];

      // NSMenuItemのインスタンスを作ります

      // Actionには_popupItemAction:を指定します
      menuItem = [[[NSMenuItem alloc]
          initWithTitle:encodingName
          action:@selector(_popUpItemAction:)
          keyEquivalent:@""] autorelease];
      // タグとして、encodingを設定します
      [menuItem setTag:encoding];
  }


        // メニューにアイテムを追加します
  [encodingMenu addItem:menuItem]; 
 }


  // ポップアップメニューに設定します
 [popupButton setMenu:encodingMenu];
}

ここでは、表示するエンコーディングを、あらかじめ static の配列として定義しておく。そして、NSMenu のインスタンスを作り、NSMenuItem を追加していくんだ。NSMenuItem のインスタンスを作るときのポイントは、アクションに _popupItemAction: を設定することだ。これを設定すると、アクションが NSPopUpButtonCell に受け取られて、バインディングの処理が行われるようだ。

こうすると、エンコーディングメニューが実現できる。メニューを選択すると、バインディングを使って、モデルクラスである Encoding の encodingValue プロパティが設定される。

サンプルとして、encodingValue の値を、IANA 名に変換してテキストフィールドに設定するアプリケーションを作ってみた。この変換は、NSValueTransformer のサブクラスを作って実装してみた。メニューからエンコーディングを選択すると、その IANA 名がテキストフィールドに設定される。また、テキストフィールドに適切な IANA エンコーディング名を入れると、ポップアップメニューの選択が変更されるんだ。

iana.jpg


ソースコードはこちらから。

■サンプルダウンロード:
EncodingsMenu.tar

Application Kit