如何使用显式 NSLayoutManager、NSTextStorage、NSTextContainer 以编程方式设置 NSTextView?
How to set up an NSTextView programmatically with explicit NSLayoutManager, NSTextStorage, NSTextContainer?
根据苹果文档,我试图通过它的两个构造方法来设置一个简单的 NSTextView
。
我将下面的代码放在内容视图的视图控制器的 viewDidAppear
方法中。 textView是NSTextView
的实例,frameRect是content view的frame
以下 Swift 代码有效(给我一个可编辑的 textView,文本显示在屏幕上):
textView = NSTextView(frame: frameRect!)
self.view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello"))
以下不起作用(文本视图不可编辑且屏幕上不显示文本):
var textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: frameRect!.size)
layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: frameRect!, textContainer: textContainer)
textView.editable = true
textView.selectable = true
self.view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))
第二个例子我做错了什么?我正在尝试遵循 Apple "Cocoa Text Architecture Guide" 中给出的示例,他们在其中讨论通过显式实例化其帮助对象网络来设置 NSTextView
。
您需要保留对您创建的 NSTextStorage
变量的引用。我不太确定这一切的机制,但看起来文本视图只保留对其文本存储对象的弱引用。一旦这个对象超出范围,它就不再可用于文本视图。我想这与 MVC 设计模式保持一致,其中视图(本例中的 NSTextView
)应该独立于它们的模型(NSTextStorage
对象)。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var textView: NSTextView!
var textStorage: NSTextStorage! // STORE A REFERENCE
func applicationDidFinishLaunching(aNotification: NSNotification) {
var view = window.contentView as NSView
textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: view.bounds.size)
layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: view.bounds, textContainer: textContainer)
textView.editable = true
textView.selectable = true
view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))
}
}
#import <Cocoa/Cocoa.h>
@interface TextViewController : NSObject {
NSLayoutManager *secondLayout;
IBOutlet NSSplitView *columnView;
IBOutlet NSTextView *bottomView;
}
- (IBAction) addColumn: (id)sender;
@end
#import "TextViewController.h"
@implementation TextViewController
- (void)awakeFromNib
{
NSTextStorage *storage = [bottomView textStorage];
secondLayout = [NSLayoutManager new];
[storage addLayoutManager: secondLayout];
[secondLayout release];
[self addColumn: nil];
[self addColumn: nil];
}
- (IBAction) addColumn: (id)sender
{
NSRect frame = [columnView frame];
NSTextContainer *container = [[NSTextContainer alloc]
initWithContainerSize: frame.size];
[container setHeightTracksTextView: YES];
[container setWidthTracksTextView: YES];
[secondLayout addTextContainer: container];
[container release];
NSTextView *newView = [[NSTextView alloc] initWithFrame: frame
textContainer: container];
[columnView addSubview: newView];
[newView release];
}
@end
在 Xcode 12.4 下测试。在游乐场中:
import Cocoa
import AppKit
let textViewFrame = CGRect(x: 0, y: 0, width: 250, height: 90)
let textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: textViewFrame.size)
layoutManager.addTextContainer(textContainer)
let textView = NSTextView(frame: textViewFrame, textContainer: textContainer)
textView.isEditable = true
textView.isSelectable = true
textView.textColor = NSColor.red
textView.string = "Why is this so complicated..."
根据苹果文档,我试图通过它的两个构造方法来设置一个简单的 NSTextView
。
我将下面的代码放在内容视图的视图控制器的 viewDidAppear
方法中。 textView是NSTextView
的实例,frameRect是content view的frame
以下 Swift 代码有效(给我一个可编辑的 textView,文本显示在屏幕上):
textView = NSTextView(frame: frameRect!)
self.view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello"))
以下不起作用(文本视图不可编辑且屏幕上不显示文本):
var textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: frameRect!.size)
layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: frameRect!, textContainer: textContainer)
textView.editable = true
textView.selectable = true
self.view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))
第二个例子我做错了什么?我正在尝试遵循 Apple "Cocoa Text Architecture Guide" 中给出的示例,他们在其中讨论通过显式实例化其帮助对象网络来设置 NSTextView
。
您需要保留对您创建的 NSTextStorage
变量的引用。我不太确定这一切的机制,但看起来文本视图只保留对其文本存储对象的弱引用。一旦这个对象超出范围,它就不再可用于文本视图。我想这与 MVC 设计模式保持一致,其中视图(本例中的 NSTextView
)应该独立于它们的模型(NSTextStorage
对象)。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var textView: NSTextView!
var textStorage: NSTextStorage! // STORE A REFERENCE
func applicationDidFinishLaunching(aNotification: NSNotification) {
var view = window.contentView as NSView
textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: view.bounds.size)
layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: view.bounds, textContainer: textContainer)
textView.editable = true
textView.selectable = true
view.addSubview(textView)
textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))
}
}
#import <Cocoa/Cocoa.h>
@interface TextViewController : NSObject {
NSLayoutManager *secondLayout;
IBOutlet NSSplitView *columnView;
IBOutlet NSTextView *bottomView;
}
- (IBAction) addColumn: (id)sender;
@end
#import "TextViewController.h"
@implementation TextViewController
- (void)awakeFromNib
{
NSTextStorage *storage = [bottomView textStorage];
secondLayout = [NSLayoutManager new];
[storage addLayoutManager: secondLayout];
[secondLayout release];
[self addColumn: nil];
[self addColumn: nil];
}
- (IBAction) addColumn: (id)sender
{
NSRect frame = [columnView frame];
NSTextContainer *container = [[NSTextContainer alloc]
initWithContainerSize: frame.size];
[container setHeightTracksTextView: YES];
[container setWidthTracksTextView: YES];
[secondLayout addTextContainer: container];
[container release];
NSTextView *newView = [[NSTextView alloc] initWithFrame: frame
textContainer: container];
[columnView addSubview: newView];
[newView release];
}
@end
在 Xcode 12.4 下测试。在游乐场中:
import Cocoa
import AppKit
let textViewFrame = CGRect(x: 0, y: 0, width: 250, height: 90)
let textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: textViewFrame.size)
layoutManager.addTextContainer(textContainer)
let textView = NSTextView(frame: textViewFrame, textContainer: textContainer)
textView.isEditable = true
textView.isSelectable = true
textView.textColor = NSColor.red
textView.string = "Why is this so complicated..."