文字列の表示を改善する【実践的Macintoshプログラミング解説】

印刷用表示 |テキストサイズ 小 |中 |大 |

CoreData版 Repeating Motif Generator の開発 Repeating Motif Wonderland CoreData 実践的 Macintosh プログラミング解説

LinkIconホーム

更新日 2009-05-24

リサージュ図形が複数選択された時に、表示が適切になる様にする

文字列の表示を改善する

 複数選択状態で文字列を表示するところまでできましたが、左下に小さく文字列が表示されており、また枠と重なってしまって非常に見栄えが悪い状態になっています。

 そこでattributeを指定して、これを改善します。

フォントを指定する

multipleSelection3.png
 文字列の属性を指定するにはdrawAtPoint:withAttributes:メソッドの第二引数に属性の入った辞書を渡す必要があります。手始めにフォントを指定してみましょう。

 フォントを指定するには、辞書のキーとしてシステムが用意するグローバル変数NSFontAttributeNameの中に入っている文字列を使います。この文字列が具体的に何かを気にする必要はなく、NSFontAttributeNameという変数を使えばOKという事です。

 キーはNSFontAttributeName、値はNSFontクラスのインスタンスを入れます。NSFontのクラスメソッドには様々なシステムフォントを得られるものが用意されていますが、ここでは12ポイントのメッセージフォントを使ってみます。

 すると、右図の様になります。あまり変わらない様に見えますが、フォントが変わって若干横幅が広がっています。

//
//  BezierPathView.m
//

- (void)showMultipleSelectionMessage
{
    NSString    *message = NSLocalizedString(@"multipleSelection",nil);

    [message drawAtPoint:NSMakePoint( 0, 0 )
          withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                          [NSFont messageFontOfSize:12], NSFontAttributeName,
                          nil]];
}

文字列を横幅いっぱいに表示する

 次に12ポイント固定ではなく、ちょうどビューの横幅いっぱいに収まる様に文字列の大きさを調整します。

 これを実現するには文字列の幅を計算する必要があります。NSStringにはsizeWithAttributes:メソッドが用意されているので、これを使います。このメソッドの引数は文字列の属性の入った辞書なので、この辞書で文字列の仮のポイント数を指定します。

 ここで得られた文字列の幅は、仮のポイント数で描画した場合の幅となります。ここから必要なポイント数をビューの幅との比例計算で求めて、最後に指定します。

//
//  BezierPathView.m
//

- (void)showMultipleSelectionMessage
{
    float       fontSize, dummySize = 12.0;
    NSSize      messageSize;
    NSString    *message = NSLocalizedString(@"multipleSelection",nil);

    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:dummySize], NSFontAttributeName,
                                               nil]];
    fontSize = dummySize/messageSize.width*[self bounds].size.width;

    [message drawAtPoint:NSMakePoint( 0, 0 )
          withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                          [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                          nil]];
}

 これを実行すると、以下の様になります。
 同じ大きさでは違いがよくわからないので、ウィンドウを少し大きくしてみました。文字列が大きくなって、ビューの横幅いっぱいになっているのがわかると思います。

multipleSelection4.png

余白を設ける

multipleSelection5.png
 サイズに応じて文字列が大きくなるのはよいのですが、あまりにも横幅いっぱいに表示すると窮屈な感じがします。そこで余白を設ける事にしました。

 余白は横幅の4%としています。固定サイズだとビューのサイズが大きくなった時に余白が足りないような感じがしたので、相対的に決める様にしました。

 文字列のポイント数を計算する時に、ビューのサイズから両脇の余白分を引いている事、文字列の表示位置を余白分だけ右にずらしている事が変更点です。

//
//  BezierPathView.m
//

- (void)showMultipleSelectionMessage
{
    float       fontSize, whiteSpace, dummySize = 12.0;
    NSSize      messageSize;
    NSString    *message = NSLocalizedString(@"multipleSelection",nil);

    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:dummySize], NSFontAttributeName,
                                               nil]];
    whiteSpace = [self bounds].size.width*0.04;
    fontSize = dummySize/messageSize.width*([self bounds].size.width - whiteSpace*2);

    [message drawAtPoint:NSMakePoint( whiteSpace, 0 )
          withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                          [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                          nil]];
}

縦方向の中心に文字列を表示する

multipleSelection6.png
 文字列が下に寄っている事が気になりますので、これを中心に持っていきます。縦方向の表示位置は、ビューの高さから文字列の高さを引いて、それを半分にした座標になります。

 文字列は横長なので、縦方向の余白は考える必要はありません。

 文字列のポイント数を決めた後で、文字列のサイズを再計算しないといけないという点が間違いやすいところです(私も間違いました)。最初に計算した文字列のサイズは仮のポイント数で計算したものなので、再度計算しないと正しいサイズになりません。

//
//  BezierPathView.m
//

- (void)showMultipleSelectionMessage
{
    float       fontSize, whiteSpace, dummySize = 12.0;
    NSSize      messageSize;
    NSString    *message = NSLocalizedString(@"multipleSelection",nil);

    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:dummySize], NSFontAttributeName,
                                               nil]];
    whiteSpace = [self bounds].size.width*0.04;
    fontSize = dummySize/messageSize.width*([self bounds].size.width - whiteSpace*2);
    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                                               nil]];

    [message drawAtPoint:NSMakePoint( whiteSpace, ([self bounds].size.height-messageSize.height)/2 )
          withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                          [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                          nil]];
}

文字列を薄く表示する

multipleSelection7.png
 Interface Builderのインスペクタを見ると、複数選択時に表示される文字列はグレーで薄く表示されています。それに倣ってBezierPathViewでも文字列を薄く表示する事にします。

 NSColorのクラスメソッドで、システムで使われている様々な色を得る事ができます。ここで使う適切な色はdisabledControlTextColorではないかと思います。そこで、この色で文字列を表示する様に変更します。

 変更の結果、右図の様になりました。BezierPathViewの複数選択表示は、これでひとまず完成という事にします。

//
//  BezierPathView.m
//

- (void)showMultipleSelectionMessage
{
    float       fontSize, whiteSpace, dummySize = 12.0;
    NSSize      messageSize;
    NSString    *message = NSLocalizedString(@"multipleSelection",nil);

    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:dummySize], NSFontAttributeName,
                                               nil]];
    whiteSpace = [self bounds].size.width*0.04;
    fontSize = dummySize/messageSize.width*([self bounds].size.width - whiteSpace*2);
    messageSize = [message sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                               [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                                               nil]];

    [message drawAtPoint:NSMakePoint( whiteSpace, ([self bounds].size.height-messageSize.height)/2 )
          withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                          [NSFont messageFontOfSize:fontSize], NSFontAttributeName,
                          [NSColor disabledControlTextColor], NSForegroundColorAttributeName,
                          nil]];
}