【问题标题】:NSPredicateEditor & NSExpression - Can the display be different than the value for the predicate?NSPredicateEditor & NSExpression - 显示可以不同于谓词的值吗?
【发布时间】:2012-12-06 18:02:25
【问题描述】:

我有一个谓词编辑器,模板是通过以下方式生成的:

    NSArray * test = [NSArray arrayWithObjects:
                      [NSExpression expressionForKeyPath: @"Abc"],
                      [NSExpression expressionForKeyPath: @"Def"],
                      nil];


    NSPredicateEditorRowTemplate * template = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: test
                                   rightExpressionAttributeType: NSStringAttributeType
                                                       modifier: NSDirectPredicateModifier
                                                      operators: [NSArray arrayWithObject:
                                                                 [NSNumber numberWithUnsignedInteger:NSContainsPredicateOperatorType]]
                                                        options:(NSCaseInsensitivePredicateOption|NSDiacriticInsensitivePredicateOption)];

所以如果我这样填写谓词编辑器:

当我注销生成的谓词时,我得到:

Abc CONTAINS[cd] "abc" OR Def CONTAINS[cd] "def"

我想知道的是,我是否可以让谓词编辑器模板显示与生成的谓词中设置的值不同。

EX:我希望输出谓词具有:

Field1 CONTAINS[cd] "abc" OR Field2 CONTAINS[cd] "def"

即使编辑器仍将abcdef 显示为字段。这可能吗?

【问题讨论】:

    标签: objective-c cocoa nspredicate nspredicateeditor nsexpression


    【解决方案1】:

    是的,你可以这样做。

    您希望左表达式数组成为最终谓词中的实际 keyPaths。在您的情况下,"Field1""Field2"

    至于在弹出窗口中显示不同的值,这里有一个令人费解的概念:

    您要将谓词编辑器本地化为英语

    有两种方法可以做到这一点。

    1. 带有 .strings 文件
    2. 带有NSDictionary

    带有 .strings 文件

    在您的来源中,您可以在评论中包含以下内容:

    // NSLocalizedStringFromTable(@"%[Field1,Field2]@ %[contains]@ %@", @"PredicateEditor", @"")
    

    当您在源代码上运行genstrings 时,这将生成一个包含以下条目的PredicateEditor.strings 文件:

    "%[Field1]@ %[contains]@ %@" = "%[Field1]@ %[contains]@ %@";
    "%[Field2]@ %[contains]@ %@" = "%[Field2]@ %[contains]@ %@";
    

    您可以将值更改为:

    "%[Field1]@ %[contains]@ %@" = "%[Abc]@ %[contains]@ %@";
    "%[Field2]@ %[contains]@ %@" = "%[Def]@ %[contains]@ %@";
    

    然后,当您创建您的NSPredicateEditor 时,您会将formattingStringsFileName 属性设置为"PredicateEditor",然后编辑器会处理其余的事情。

    NSDictionary

    这将遵循与 .strings 选项相同的基本概念,但您基本上会这样做:

    NSDictionary *formatting = @{
      @"%[Field1]@ %[contains]@ %@" : @"%[Abc]@ %[contains]@ %@",
      @"%[Field2]@ %[contains]@ %@" : @"%[Def]@ %[contains]@ %@"
    }
    [myPredicateEditor setFormattingDictionary:formatting];
    

    这就是你所要做的。

    很久以前我blogged about this,其中包含更多您可能会发现有用的信息。

    【讨论】:

    • 需要注意的是,在上述情况下,您不能更改修饰符,在更改的情况下,%[contains]@ 需要保留所有可能出现的选项。对我来说,要获得每个选项的本地化,我需要将其修改为:%[is less than, is less than or equal to, is greater than, is greater than or equal to, is, is not, contains, begins with, ends with]@
    【解决方案2】:

    基本上,您想修改弹出按钮中菜单项的标题。这就是你需要做的。它不应该影响您返回的基础谓词。如果您在界面生成器中创建它,则可以轻松获取模板的菜单项并设置其标题。但是由于您是在代码中执行此操作的,因此您必须在代码中对其进行修复。

    您可以这样做。在我的行模板类中,我想更改我的 NSTextFields 的宽度。所以在我的行模板类中,我寻找它们并像这样修改它们......

    - (void)awakeFromNib {
        NSArray* views = [self templateViews];
        for (id view in views) {
            if ([[view class] isEqual:[NSTextField class]]) {
                NSRect tfFrame = [view frame];
                tfFrame.size.width = 600;
                [view setFrame:tfFrame];
            }
        }
    }
    

    你可以看到我得到了 templateViews 并寻找 NSTextFields...然后修改它们。你可以做类似的事情来寻找 NSPopupButtons。找到一个后,检查他们的菜单项标题并查找标题为“abc”和“def”的菜单项,并将其标题分别更改为“Field1”和“Field2”。

    【讨论】:

      【解决方案3】:

      与其使用带有特定格式的选项文字的NSLocalizedStringgenstrings 来生成本地化字符串,不如自己生成最终的本地化.strings 文件字符串似乎更容易/更干净。

      From this blog post,我们可以使用 Private API _generateFormattingDictionaryStringsFile 从 NSPredicateEditor 本身获取格式化字符串:

      extension NSPredicateEditor {
      
          func formattingDictionaryStrings() -> String? {
              var strings: String? = nil
      
              if let formattingDictionaryData = self.perform(Selector("_generateFormattingDictionaryStringsFile"))?.takeRetainedValue() as? Data {
                  strings = String(data: formattingDictionaryData, encoding: .utf16)
              }
      
              return strings
          }
      
      }
      

      这会生成所有排列,而无需 genstrings。然后,您将 = 右侧的标记替换为用户显示的字符串。

      "%[ABC]@ %[is]@ %[123]@" = "%1$[ABC]@ %2$[is]@ %3$[123]@";
      "%[ABC]@ %[is]@ %[456]@" = "%1$[ABC]@ %2$[is]@ %3$[456]@";
      "%[ABC]@ %[is]@ %[789]@" = "%1$[ABC]@ %2$[is]@ %3$[789]@";
      "%[ABC]@ %[contains]@ %[123]@" = "%1$[ABC]@ %2$[contains]@ %3$[123]@";
      "%[ABC]@ %[contains]@ %[456]@" = "%1$[ABC]@ %2$[contains]@ %3$[456]@";
      "%[ABC]@ %[contains]@ %[789]@" = "%1$[ABC]@ %2$[contains]@ %3$[789]@";
      

      更好的是,您可以构建构建每个 NSPredicateEditorRowTemplate 的代码,以将谓词内部使用的键路径和该选项的本地化字符串作为输入。

      然后您的方法可以生成上面的字符串,但已经插入了正确的本地化。

      注意:调用此 _generateFormattingDictionaryStringsFile 私有 API 方法似乎会导致 NSPredicateEditor 内随机崩溃:

      这个类与键 rowType 的键值编码不兼容。

      因此,请务必在需要时运行一次,但不要在正常运行或测试应用时将其保持激活状态。

      【讨论】:

        【解决方案4】:

        是的,这完全是本地化问题,这要归功于对象是菜单项这一事实。而且他们很容易被这样对待。

        你需要做的就是……

        • 本地化您的应用程序。
        • 然后进入.strings文件,把值改成你想要显示的 或者... 使用管理/翻译本地化应用的工具。

        这是一个直接在 .strings 文件中更改内容的示例: 将 is 更改为 ist 并将 booktitle 更改为 Buchtitel

        /* Class = "NSMenuItem"; title = "is"; ObjectID = "G1c-st-GEK"; */
        "G1c-st-GEK.title" = "ist";
        
        /* Class = "NSMenuItem"; title = "booktitle"; ObjectID = "nQh-54-5Nx"; */
        "nQh-54-5Nx.title" = "Buchtitel";
        

        备注:查找要更改的行的最佳方法是查找 ObjectID。 UIB 身份检查器可以为每个 MenuItem 找到此信息:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-29
          • 2014-08-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多