0

NSArrayController一連の列を含むテーブルを動的に作成していますが、そのうちの 1 つにポップアップ ボタンがあります。ポップアップ ボタン セルのコンテンツを使用するNSAttributedString必要があるのは、科学変数を下付き文字 (たとえば、1 を下げた X1) で表示する必要があるためです。

ポップアップ セルcontent valuesを配列にバインドすると、プレーンなオブジェクトNSAttributedStringしか理解できないため、UI が意味不明になります。NSString

ポップアップ ボタンのメニューはバインドできません (つまり、バインドを介して動的に割り当てることはできません)。

ポップアップ ボタン メニューのコンテンツも動的にバインドできません。

NSPopUpButtonCellメニューにNSAttributedStringオブジェクトを動的に追加する方法 (少なくとも残りのテーブル コンテンツのバインディングに固執する) を誰かが提案できますか?

4

1 に答える 1

2

ポップアップされたときにメニューに属性付き文字列を表示するには、ポップアップセルを含むテーブル列を設定して、それ自体がすべてのオプションを含むにバインドされているをContent指すようにバインドしてから、デリゲートを配置することをお勧めします。ポップアップセルに含まれ、デリゲートで次のようなことを行います。NSArrayControllerNSArrayNSAttributedStringsNSMenu

- (void)menuNeedsUpdate:(NSMenu*)menu
{
    for (NSMenuItem* item in menu.itemArray)
        if ([item.representedObject isKindOfClass: [NSAttributedString class]])
        {
            item.attributedTitle = item.representedObject;
        }
}

バインディングは、痴漢NSAttributedStringされていないものをのrepresentedObjectプロパティに入れNSMenuItemます。そこで見つけてプロパティに入れるとattributedTitle、メニューに属性付きの文字列が表示されます。attributedTitleつまり、プロパティが適切に設定されたメニューに描画されるメニュー項目は、スタイル付きテキストを描画します。

もう少し複雑なのは、メニューがポップアップされていないときに、ポップアップセルで意図したとおりに属性付きの文字列を描画することです。NSPopUpButtonCellそれを描画することによってレンダリングするように見えますNSMenuItem。残念ながら、その特定の作成には、NSMenuItem痴漢されていない価値をそれに押し込むことは含まれていないようです。代わりに、タイトルはプレーンな、属性のない文字列として送信されているようです。私はこれに対するエレガントな解決策を考案することができませんでしたが、私はエレガントでない回避策を思いつきました:

まず、現在選択されている属性付き文字列を正しく(つまり属性付きで)描画するNSTextField列をに追加します。NSTableViewその列を非表示にします。サブクラスNSPopUpButtonCell化するか、カテゴリと関連するストレージを使用して、新しいプライベートプロパティをに追加しNSPopUpButtonCellます。このプロパティは、描画時に非表示の列から対応するセルをフェッチするために使用できるブロックを保持します。を追加しNSTableViewDelegate、を実装し-tableView:dataCellForTableColumn:row:ます。それがポップアップ列に対して呼び出されたら、非表示の列からセルをフェッチするブロックを作成し、それをサブクラスのプロパティに押し込みます。次に、描画時に、セルフェッチャーブロックがある場合はtitlemenuItem通常はレンダリングに使用し、superを呼び出し(ポップアップの小さな矢印を取得するため)、代理セルをフェッチして、それも描画します。コードは次のようになります。

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

@property (assign) IBOutlet NSTableColumn *popUpColumn;
@property (assign) IBOutlet NSTableColumn *surrogateColumn;

// ...snip...

@end

@interface SOPopUpButtonCell : NSPopUpButtonCell

typedef NSTextFieldCell* (^CellFetcher)();
@property (nonatomic, copy, readwrite) CellFetcher cellFetcherBlock;

@end

@implementation AppDelegate

// ...snip...

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    if (nil == tableColumn || self.popUpColumn != tableColumn)
        return nil;

    SOPopUpButtonCell* defaultCell = (SOPopUpButtonCell*)[tableColumn dataCellForRow: row];
    const NSUInteger columnIndex = [[tableView tableColumns] indexOfObject: self.surrogateColumn];
    CellFetcher f = ^{
        return (NSTextFieldCell*)[tableView preparedCellAtColumn: columnIndex row: row];
    };
    defaultCell.cellFetcherBlock = f;

    return defaultCell;
}

@end

@implementation SOPopUpButtonCell

- (void)setCellFetcherBlock:(CellFetcher)cellFetcherBlock
{
    if (_cellFetcherBlock != cellFetcherBlock)
    {
        if (_cellFetcherBlock) 
            Block_release(_cellFetcherBlock);

        _cellFetcherBlock = cellFetcherBlock ? Block_copy(cellFetcherBlock) : nil;
    }
}

- (void)dealloc
{
    if (_cellFetcherBlock) 
        Block_release(_cellFetcherBlock);
    [super dealloc];
}

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    CellFetcher f = self.cellFetcherBlock;
    if (f)
        self.menuItem.title = @"";

    [super drawWithFrame:cellFrame inView:controlView];

    if (f)
        NSTextFieldCell* surrogateCell = f();
        [surrogateCell drawWithFrame: cellFrame inView: controlView];
}

@end

私はこれが私を少し汚く感じることを認めなければなりません、しかしそれは仕事を成し遂げたようです。関連するすべてのバインディングを含むxibを含むすべてのコードをgithubに投稿しました: サンプルプロジェクト

お役に立てば幸いです。

于 2012-12-04T12:40:21.910 に答える