2009年11月26日木曜日

メニューのみのアプリケーションの難しさ

日めくり」に年月の移動用のdatePickerを追加した時のメモ。

「日めくり」は、ステータスバーをメニュー領域に追加してメニューからプルダウンでカレンダーを表示します。

Dockには表示したくないので、Info.plistにNSUIElement=1を追加しています。
こうするとメニューエクストラのように見えます(本当は通常のアプリケーションです)。

一つ問題なのは、メニューから「日めくり」を選んでメニューを表示させても「日めくり」がアクティブなアプリケーションにならないことです(正しい言い方ではないですが...)。

これが問題になったのは、カレンダーの年月の移動用にdatePickerを追加した時でした。
datePickerではテキストフィールドで数値を入力で きますが、テキストフィールドをクリックしても(入力は出来るのに)フォーカスリングとテキストの選択状態のハイライトが表示される時と表示されない時があります。

  • 「日めくり」起動直後は表示される。
  • Finderなどの他のアプリケーションに切り替えてから「日めくり」に戻ると表示されない。
  • 「日めくり」の環境設定ウインドウを表示させた後は表示される。
よくよく検証すると、「日めくり」がアクティブになっていないことが判りました。

自分のアプリケーションをアクティブにするには、[NSApp activateIgnoringOtherApps:YES]を使うという手がありますが、メニューがプルダウンされた状態でこれを呼ぶと一旦メニューが閉じてしまいます(環境設定ウインドウを表示させる時はこれを使っています)。

で、解決策としてdatePickerのサブクラスを作り、drawRectの中でフォーカスリングとテキストの選択状態を自前で表示することにしました。

drawRectの概要

- (void)drawRect:(NSRect)rect

{

// 年か月のハイライト領域を表示

[[[NSColor selectedTextBackgroundColor] set];

NSRectFill(hilightRect);


// 既定のイベント処理を行う(入力した数値の表示)

[super drawRect:rect];


// フォーカスリングを表示

NSSetFocusRingStyle(NSFocusRingOnly);/

//このあと描画した図形の周囲にフォーカスリングが表示される

NSRectFill(NSMakeRect(...);

}

フォーカスリングの表示の前に、[super drawRect:rect]で既定のイベント処理をさせるところがポイントです。これを逆にするとシステムに戻ってから描かれる入力数値にまでフォーカスリングが付いてしまいました。


NSSetFocusRingStyle(NSFocusRingOnly)を無効にする方法があれば[super drawRect:rect]
を最後にできると思うのですが今のところ不明です。これが原因と思われるのですが、自前のフォーカスリングの動作がシステム標準と少し異なります。対象のrectの大きさを調整しましたが十分ではないです。。

ポイント
  1. drawRectの中で、ハイライト領域を色付け→システム側で数値を描画→フォーカスリングを描画の順にすること。
  2. datePickerのBackGroundを透明にしておくこと(InterFace Builder)。
※フォーカスリングについては、ザリガニが見ていた... 。さんの下記リンクが参考になりました。ありがとうございます。

0 件のコメント:

コメントを投稿