Cocoa右クリックメニュー
今回のお遊び実験
目的
- NSViewを継承しているクラスで、右クリックした時にポップアップメニューを表示する。
- NSMenuを少しいじくる
NSViewを継承しているクラスってたくさんあります。
というか、GUIに設置にするものはほとんど(といか全部?)がそうでしょう。
今回はあえてNSButtonでやってみたいと思います。
誰もそんなことしたいと思わないだろうと?
お遊びだからいいのです。
実は実装は簡単です。
+ (NSMenu *)defaultMenu;
をオーバライドすれば、完了です。
その他にも、
- (NSMenu*)menuForEvent:(NSEvent*)event;
をオーバーライドする方法があります。
後者はクリック情報を内部処理で使いたい場合に使います。
例えば、指定した範囲ないでのみポップアップメニューを表示するとか。
@interface PJPopUpMenuButton : NSButton @end @implementation PJPopUpMenuButton + (NSMenu*)defaultMenu { NSMenu * menu = [[[NSMenu alloc] initWithTitle:@"PJPopUpMenu"] autorelease]; [menu addItemWithTitle:@"menu1" action:nil keyEquivalent:@""]; return menu; } @end
なんとも簡単ですね。
NSMenuをいじってみる
次はNSMenuをいじってこんなことをしてみます。
これは、NSMenuItemのsetView:メソッドを使えば実現できます。
ソース
+ (NSMenu*)defaultMenu { NSMenu * menu = [[[NSMenu alloc] initWithTitle:@"PJPopUpMenu"] autorelease]; [menu addItemWithTitle:@"menu1" action:nil keyEquivalent:@""]; // // メニュー内にNSButtonを入れてみる // NSMenuItem *buttonItem = [[[NSMenuItem alloc] initWithTitle:@"buttonItem" action:nil keyEquivalent:@""] autorelease]; NSButton *button = [[[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)] autorelease]; { [button setTitle:@"buttonItem"]; [button setBezelStyle:NSTexturedSquareBezelStyle]; } [buttonItem setView:button]; [menu addItem:buttonItem]; // // メニュー内にNSSliderを入れてみる // NSMenuItem *sliderItem = [[[NSMenuItem alloc] initWithTitle:@"sliderItem" action:nil keyEquivalent:@""] autorelease]; NSSlider *slider = [[[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)] autorelease]; { [slider setMinValue:0.0f]; [slider setMaxValue:100.0f]; [slider setFloatValue:50.0f]; } [sliderItem setView:slider]; [menu addItem:sliderItem]; return menu; }
とまぁ、結構遊べるものです。
NSMenuに関しては別記事にて、もう少し色々してみたい思います。
メニューの表示位置を変えてみる
では、最後に、ポップアップメニューの表示位置を変えてみます。
まずポップアップメニューが表示されるフローについて簡単に説明します。
右クリックが検知された際の動作は
- - (void)rightMouseDown:(NSEvent*)theEvent
- - (NSMenu*)menuForEvent:(NSEvent*)theEvent
- + (NSMenu*)defaultMenu
右クリックが検知されると1が呼び出されます。
1のデフォルト動作は、 2を呼び出し、その返り値がnilでなければ、 クリックされた場所にメニューを表示する 2のデフォルト動作は、3を呼び出す 3のデフォルト動作はnilを返す
という様になっています。
(2のデフォルト動作がもしかしたら違うかもしれませんが、ここではこれで差し支えないので、こうしておきます。中途半端ですみません)
つまり、表示位置をコントロールするには、1までさかのぼる必要があります。
また、表示される位置についてです。
絵にするとこんな感じになっています。
座標系が左下基準というのに、注意する必要があります。
そして、クリックされた場所の情報は、
rightMouseDown:の引数であるNSEventに含まれています。
こいつをいじくってやれば、表示位置を変更できるわけです。NSEventについては割愛します。
というわけで、コードはこんな感じになります。
- (void)rightMouseDown:(NSEvent *)theEvent { // // クリック位置をずらす // NSPoint displayPoint = NSMakePoint([theEvent locationInWindow].x-100, [theEvent locationInWindow].y+100); // // 新しいNSEventを作る // これをもとにポップアップメニューを表示させる // NSEvent * newEvent = [NSEvent mouseEventWithType:[theEvent type] location:displayPoint modifierFlags:[theEvent modifierFlags] timestamp:[theEvent timestamp] windowNumber:[theEvent windowNumber] context:[theEvent context] eventNumber:[theEvent eventNumber] clickCount:[theEvent clickCount] pressure:[theEvent pressure]]; // // 新しく作ったNSEventを使ってポップアップメニューを表示 // デフォルトでは、theEventを使っているのでしょう // [NSMenu popUpContextMenu:[[self class] defaultMenu] withEvent:newEvent forView:self]; }
さぁ、どんな使い道があるのか・・・
僕にはさっぱりです。
CocoBot2を振り返る。そして、ご意見頂戴!
簡単にではありますが、CocoBot2を振り返ってみる。
特徴/機能
- 開発開始当初に設計した機能がまだ何個も手つかず。故に永遠のアルファ
- 簡易IRCクライアント
- 陳腐なボット機能
- Twitterのハッシュタグ検索クライアント
- 上記クライアントのコメントをニコニコ風に表示する
- 上記クライアントのコメント読み上げ(要読み上げソフトウェア)
- 読み上げ時のテキスト置き換え機能(w->わら)
- 作成した読み上げ設定のスイッチング機能
- バグまみれ
だいたいこんな感じでしょうか
利用者の方はどう思っているのでしょうか。
フィードバックをきちんと吸い上げられる機構がないので、確かめようがないのですが。
どうしたらいいですかね?
アプリケーションの使用者がいるのかどうか怪しいという懸念もあります(苦笑)
なのに、なぜ開発を続けているのか。
単に自分の思い描くものが出来上がっていくのが嬉しいから
それだけです。
ところで、そんなことはどうでもいいのです。
今後について、質問してみようと思います。
もし、この記事を目に通してくださった方がいたら、ぜひともご意見を。
今後についての質問
- 他の読み上げアプリケーションへの対応について
- 『ゆっくろいど』というアプリケーションを見つけました。対応してみようと思うのですが、どうでしょうか?
- 読み上げソフトは組み込みにしてほしいですか?(声が多く集まれば、そうするかもしれません。)
- 他のサービスへの対応
- ニコ生やStickam等、対応して欲しい他のサービスはありますか?
- 欲しい機能
- 何か実装して欲しい機能はありますか?
よろしくお願いします。
NSStringをローマ字表記に変換してみる
CFStringTokenizerはトークン分割に非常に役立つAPIです。
分割される様子を見る限り、結構きちんと形態素解析できていると思います。
(もしかしたら、mecab使っているのかな?まぁ、その辺はよくわからないですが、とりあえずおいておきましょう。)
今回そんなCoreFoundationのCFStringTokenizerで、遊んでみます。
目標
すもももももももものうち すもも も もも も もも の うち sumomo mo momo mo momo no uchi
って感じの2項目です。
取得できるローマ字表記は、読み用のものではないので、その点はご留意を。
(助詞の『は』や『へ』は、きちんとトークン分割されますが、『ha』『he』と出力されます)
この点に関しては、もうちょっと調べたいと思います。
ソース
/* * トークン解析に必要なもの */ NSString * testString; CFLocaleRef locale; // ロケール:tokenizer生成に使用 CFRange range; // 解析用範囲:tokenizer生成に使用 : のちに検知されたトークンの範囲用として使用 {//トークン解析に必要なもの:初期化 testString = @"すもももももももものうち"; range = CFRangeMake(0, [testString length]); locale = CFLocaleCopyCurrent();// !!!: 要CFRelease } /* * トークン解析してくれる子 */ CFStringTokenizerRef tokenizer; // トークン解析してくれるよ !!!: 要CFRelease tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (CFStringRef)testString, range, kCFStringTokenizerUnitWordBoundary, locale); CFStringTokenizerTokenType tokenType; // 見つかったトークンの状態 // 最初に見つかったトークンの状態で初期化 tokenType = CFStringTokenizerGoToTokenAtIndex(tokenizer, 0); /* * トークン毎ループ */ while (tokenType != kCFStringTokenizerTokenNone) { // // range を解析用範囲から見つかったトークンの範囲へと使用方法を変更 // range = CFStringTokenizerGetCurrentTokenRange(tokenizer); CFTypeRef latin; // トークンのローマ字表記 !!!: 要CFRelease latin = CFStringTokenizerCopyCurrentTokenAttribute(tokenizer, kCFStringTokenizerAttributeLatinTranscription); NSLog( @"token:%@ => latin:%@",[testString substringWithRange:NSMakeRange(range.location, range.length)], latin); CFRelease(latin); tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer); } CFRelease(locale); CFRelease(tokenizer);
NSStringとswitch 2
switchっぽいものでNSStringを扱うパート2
非常に気持ち悪いですがね
void PJSwitch(NSString * cmpdString, void (^block)(NSString*)) { block(cmpdString); } void PJCase(NSString*constantString,NSString* cmpdString,void (^block)()) { if ([cmpdString isEqualToString:constantString]) block(); }
NSString *fooString = ...; PJSwitch(fooString, ^(NSString *arg1) { // fooString は swith(<ここの部分>) __block BOOL stop = NO; while (1) { PJCase( @"hoge", arg1, ^() { NSLog(@"matched hoge"); stop = YES; }); if (stop) { break; } PJCase(@"fuga", arg1, ^() { NSLog(@"matched fuga"); stop = YES; }); if (stop) { break; } break; } });
NSTableViewいろいろなセルを表示2
前回の記事と内容はほとんど変わりませんが、
また、遊んでみます。
今回の目的
- NSTableViewにいろんなセルを表示
- 他の列に対して動的に変わるセルを表示
- 今回はNSPopUpButtonの選択状態に応じて変わるようにしてみます
- 実用性は考えない
ソースです。
http://dl.dropbox.com/u/28881228/MultipleCellTableView2.zip