Подтвердить что ты не робот

Пример кода для создания метки "NSTextField"?

В моем рабочем приложении Mac OS X я хотел бы запрограммировать создание метки "NSTextField", которая имеет такое же поведение и свойства, что и типичная метка, созданная в Interface Builder.

Я обычно использую (и очень люблю) IB, но в этом случае он должен выполняться программно.

Попробуйте, как я мог, я не могу найти комбинацию вызовов методов, которые будут программно производить одно и то же поведение метки-y, как "Ярлык", перетаскиваемый из палитры библиотеки IB View.

Может ли кто-нибудь указать или указать примерный код того, как это сделать программно? спасибо.

4b9b3361

Ответ 1

Ярлык фактически является экземпляром NSTextField, подкласса NSView. Итак, поскольку это NSView, его нужно добавить в другое представление.

Здесь рабочий код:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSTextField *textField;

    textField = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, 200, 17)];
    [textField setStringValue:@"My Label"];
    [textField setBezeled:NO];
    [textField setDrawsBackground:NO];
    [textField setEditable:NO];
    [textField setSelectable:NO];
    [view addSubview:textField];
}

Ответ 2

macOS 10.12 Обновление

Начиная с macOS 10.12, есть три новых конструктора NSTextField:

  • NSTextField(labelWithString:), который в комментарии файла заголовка говорит: "Создает невращающееся, редактируемое, неизменяемое текстовое поле, которое отображает текст в системном шрифте по умолчанию".

  • NSTextField(wrappingLabelWithString:), который в комментарии к файлу заголовка говорит: "Создает текстовое поле для печати, не редактируемое, выбираемое, которое отображает текст в системном шрифте по умолчанию".

  • NSTextField(labelWithAttributedString:), который в комментарии файла заголовка говорит: "Создает неизменяемое текстовое поле, не подлежащее выбору, которое отображает атрибутный текст. Режим разрыва строки этого поля определяется атрибутом атрибута NSParagraphStyle."

Я тестировал те, которые принимают простую (непривязанную строку), и создают текстовые поля, которые похожи, но не точно такие же, как текстовые поля, созданные в раскадровке или xib.

Важным отличием является то, что оба конструктора создают текстовое поле с textBackgroundColor (обычно чисто белым) в качестве цвета фона, в то время как текстовое поле раскадровки использует controlColor (обычно около 90% белого).

Неважно, оба конструктора также устанавливают свои шрифты, вызывая NSFont.systemFont(ofSize: 0) (который создает другой объект NSFont, чем мой код выше, но они обертывают тот же основной шрифт Core Text).

Конструктор wrappingLabelWithString: устанавливает поле isSelectable в true. (Это описано в файле заголовка.)


Я сравнил четыре экземпляра NSTextField: один, созданный путем перетаскивания "Ярлык" в раскадровку, другой - путем перетаскивания "Оберточной этикетки" в раскадровку и двух в коде. Затем я тщательно модифицировал свойства созданных кодами ярлыков, пока все их свойства не были точно такими же, как созданные метками раскадровки. Результатом этих двух методов являются:

extension NSTextField {

    /// Return an `NSTextField` configured exactly like one created by dragging a "Label" into a storyboard.
    class func newLabel() -> NSTextField {
        let label = NSTextField()
        label.isEditable = false
        label.isSelectable = false
        label.textColor = .labelColor
        label.backgroundColor = .controlColor
        label.drawsBackground = false
        label.isBezeled = false
        label.alignment = .natural
        label.font = NSFont.systemFont(ofSize: NSFont.systemFontSize(for: label.controlSize))
        label.lineBreakMode = .byClipping
        label.cell?.isScrollable = true
        label.cell?.wraps = false
        return label
    }

    /// Return an `NSTextField` configured exactly like one created by dragging a "Wrapping Label" into a storyboard.
    class func newWrappingLabel() -> NSTextField {
        let label = newLabel()
        label.lineBreakMode = .byWordWrapping
        label.cell?.isScrollable = false
        label.cell?.wraps = true
        return label
    }

}

Если вы используете один из этих методов, не забудьте установить свой фрейм поля или отключить его translatesAutoresizingMaskIntoConstraints и добавить ограничения.


Вот код, который я использовал для сравнения различных текстовых полей, если вы хотите проверить:

import Cocoa

class ViewController: NSViewController {

    @IBOutlet var label: NSTextField!
    @IBOutlet var multilineLabel: NSTextField!

    override func loadView() {
        super.loadView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let codeLabel = NSTextField.newLabel()
        let codeMultilineLabel = NSTextField.newWrappingLabel()

        let labels = [label!, codeLabel, multilineLabel!, codeMultilineLabel]

        for keyPath in [
            "editable",
            "selectable",
            "allowsEditingTextAttributes",
            "importsGraphics",
            "textColor",
            "preferredMaxLayoutWidth",
            "backgroundColor",
            "drawsBackground",
            "bezeled",
            "bezelStyle",
            "bordered",
            "enabled",
            "alignment",
            "font",
            "lineBreakMode",
            "usesSingleLineMode",
            "formatter",
            "baseWritingDirection",
            "allowsExpansionToolTips",
            "controlSize",
            "highlighted",
            "continuous",
            "cell.opaque",
            "cell.controlTint",
            "cell.backgroundStyle",
            "cell.interiorBackgroundStyle",
            "cell.scrollable",
            "cell.truncatesLastVisibleLine",
            "cell.wraps",
            "cell.userInterfaceLayoutDirection"
        ] {
            Swift.print(keyPath + " " + labels.map({ ($0.value(forKeyPath: keyPath) as? NSObject)?.description ?? "nil" }).joined(separator: " "))
        }
    }
}

Ответ 3

Это может быть сложно сделать правильно. У меня нет рецепта для точной копии, но когда я застрял в подобной ситуации, вот что я делаю:

  • Создайте элемент пользовательского интерфейса в IB.
  • Добавьте к нему выход из моего класса контроллера.
  • Перерыв в gdb в awakeFromNib или что-то еще.
  • В приглашении gdb "p * whateverOutlet"... это покажет вам содержимое структуры C метки NSTextField, которую IB настроил.

Посмотрев на все бесчисленные ценности, вы можете получить много догадок о том, что вы пренебрегаете установкой. Обычно это заканчивается тем, что представляет собой волшебную комбинацию настроек рамки и границы, которая позволяет вам, где вы хотите быть.

Ответ 4

Вы можете попробовать nib2objc, чтобы получить все свойства, которые IB устанавливает

Ответ 5

В частности, вы захотите setBordered:NO, и установите стиль рамки в любом стиле, который я забыл. Также setEditable:NO и необязательно setSelectable:NO. Этого должно быть достаточно.

Ответ 6

Разбор AppKit в Objective-C:

BOOL TMPSierraOrLater() {
    static BOOL result = NO;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        result = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){ 10, 12, 0 }];
    });
    return result;
}

@implementation NSTextField (TMP)

+ (instancetype)TMP_labelWithString:(NSString *)stringValue {
    if (TMPSierraOrLater()) {
        return [self labelWithString:stringValue];
    }
    NSParameterAssert(stringValue);
    NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
    label.lineBreakMode = NSLineBreakByClipping;
    label.selectable = NO;
    [label setContentHuggingPriority:(NSLayoutPriorityDefaultLow + 1) forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    label.stringValue = stringValue;
    [label sizeToFit];
    return label;
}

+ (instancetype)TMP_wrappingLabelWithString:(NSString *)stringValue {
    if (TMPSierraOrLater()) {
        return [self wrappingLabelWithString:stringValue];
    }
    NSParameterAssert(stringValue);
    NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
    label.lineBreakMode = NSLineBreakByWordWrapping;
    label.selectable = YES;
    [label setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    label.stringValue = stringValue;
    label.preferredMaxLayoutWidth = 0;
    [label sizeToFit];
    return label;
}

+ (instancetype)TMP_labelWithAttributedString:(NSAttributedString *)attributedStringValue {
    if (CRKSierraOrLater()) {
        return [self labelWithAttributedString:attributedStringValue];
    }
    NSParameterAssert(attributedStringValue);
    NSTextField *label = [NSTextField TMP_newBaseLabelWithoutTitle];
    [label setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
    [label setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationVertical];
    label.attributedStringValue = attributedStringValue;
    [label sizeToFit];
    return label;
}

#pragma mark - Private API

+ (instancetype)TMP_newBaseLabelWithoutTitle {
    NSTextField *label = [[self alloc] initWithFrame:CGRectZero];
    label.textColor = NSColor.labelColor;
    label.font = [NSFont systemFontOfSize:0.0];
    label.alignment = NSTextAlignmentNatural;
    label.baseWritingDirection = NSWritingDirectionNatural;
    label.userInterfaceLayoutDirection = NSApp.userInterfaceLayoutDirection;
    label.enabled = YES;
    label.bezeled = NO;
    label.bordered = NO;
    label.drawsBackground = NO;
    label.continuous = NO;
    label.editable = NO;
    return label;
}

@end