在NSTokenField

时间:2016-07-29 00:20:34

标签: macos cocoa nstokenfield

我想要一个包含纯文本和令牌的NSTokenField。这与this question中的问题相同,但那里的答案并没有为我解决。也许我错过了一些东西,或者自从那些答案发布以来,苹果公司在5年内改变了一些东西。

具体来说,假设我要键入“hello%tok%”并将其转换为:

image of text "hello" and token "TOKEN"

为了尝试消除混淆的机会,我总是使用以下类之一的自定义表示对象,而不是普通字符串......

@interface Token : NSObject
@end

@implementation Token
@end


@interface WrappedString : NSObject
@property (retain) NSString* text;
@end

@implementation WrappedString
@end

以下是我的委托方法:

- (NSString *)tokenField:(NSTokenField *)tokenField
    displayStringForRepresentedObject:(id)representedObject
{
    NSString * displayString = nil;
    if ([representedObject isKindOfClass: [WrappedString class]])
    {
        displayString = ((WrappedString*)representedObject).text;
    }
    else
    {
        displayString = @"TOKEN";
    }
    return displayString;
}

- (NSTokenStyle)tokenField:(NSTokenField *)tokenField
                styleForRepresentedObject:(id)representedObject
{
    NSTokenStyle theStyle = NSPlainTextTokenStyle;
    if ([representedObject isKindOfClass: [Token class]])
    {
        theStyle = NSRoundedTokenStyle;
    }

    return theStyle;
}

- (NSString *)tokenField:(NSTokenField *)tokenField
        editingStringForRepresentedObject:(id)representedObject
{
    NSString * editingString = representedObject;
    if ([representedObject isKindOfClass: [Token class]])
    {
        editingString = nil;
    }
    else
    {
        editingString = ((WrappedString*)representedObject).text;
    }
    return editingString;
}

- (id)tokenField:(NSTokenField *)tokenField
    representedObjectForEditingString:(NSString *)editingString
{
    id repOb = nil;
    if ([editingString isEqualToString:@"tok"])
    {
        repOb = [[[Token alloc] init] autorelease];
    }
    else
    {
        WrappedString* wrapped = [[[WrappedString alloc]
            init] autorelease];
        wrapped.text = editingString;
        repOb = wrapped;
    }
    return repOb;
}

当我输入“hello”时,没有调用任何委托方法,这似乎是合理的。当我输入第一个“%”时,有3个委托调用:

  1. tokenField:representedObjectForEditingString:获取字符串“hello”并将其转换为WrappedString表示。
  2. tokenField:styleForRepresentedObject:获取WrappedString并返回NSPlainTextTokenStyle
  3. tokenField:editingStringForRepresentedObject:获取WrappedString并返回“hello”。
  4. 前两个电话看似合理。我不确定3号,因为令牌应该是可编辑的,但它还没有被编辑。我原以为tokenField:displayStringForRepresentedObject:会被调用,但事实并非如此。

    当我输入“tok”时,不会调用任何委托方法。当我键入第二个“%”时,tokenField:representedObjectForEditingString:收到字符串“hellotok”,我本来希望看到“tok”。所以我永远不会有机会创建圆形标记。

    如果我按照其他顺序键入文本“%tok%hello”,那么我确实得到了预期的结果,一个圆形标记后跟普通的“你好”。

    顺便说一下,Token Field Programming Guide

      

    请注意,每个标记字段只能有一个标记为纯文本标记样式配置。

    这似乎意味着不可能自由地混合纯文本和令牌。

1 个答案:

答案 0 :(得分:1)

我问自己,我是否在标准应用程序的任何地方都看到了混合文本和标记,而且我有。在语言&文本 系统偏好设置面板,在格式标签下,点击其中一个"自定义..."按钮会弹出一个包含令牌字段的对话框。这是其中的一部分。

enter image description here

在这里,您不能通过键入标记字符来创建标记,而是拖放原型标记。

要创建其中一个原型令牌,请创建另一个NSTokenField并将其设置为没有背景或边框,并且可以选择但不可编辑。加载窗口后,可以使用objectValue属性初始化原型字段,例如

self.protoToken.objectValue = @[[[[Token alloc] init] autorelease]];

您需要为每个原型令牌字段以及可编辑令牌字段设置委托。为了能够拖放令牌,您的代理人必须实施tokenField:writeRepresentedObjects:toPasteboard:tokenField:readFromPasteboard: