Appending Text to Nstextview in Swift 3

Appending text to NSTextView in Swift 3

I think I got this figured out. I went into the view controller scene and drilled down into the NSScrollView > Clip View > Text View and then created my outlet out of that instead of just manually changing it from NSScrollView to NSTextView.

Once I did that, the following line did me just fine:

myTxtView.textStorage?.append(NSAttributedString(string: "Hello World"))

Append to NSTextView and scroll

After cross-referencing several answers and sources (with some tweaks), here's the answer that does work (given _myTextView is an NSTextView outlet) :

- (void)appendToMyTextView:(NSString*)text
{
dispatch_async(dispatch_get_main_queue(), ^{
NSAttributedString* attr = [[NSAttributedString alloc] initWithString:text];

[[_myTextView textStorage] appendAttributedString:attr];
[_myTextView scrollRangeToVisible:NSMakeRange([[_myTextView string] length], 0)];
});
}

Change the text of a NSTextView programmatically

The right method is "setString" [textView setString:@"the string"];

Scroll an NSTextView to bottom after adding text

NSTextView has an exact action: scrollToEndOfDocument(_ sender: Any?).

So, I suppose the following code is enough.

self.logTextView.string += "\nnew text"
self.logTextView.scrollToEndOfDocument(nil)

NSMutableAttributedString for adding subscript (superscript) for NSTextView from String

I would suggest using a standard NSAttributedString and NSBaselineOffsetAttributeName. Take a look at the example I just put together:

override func viewDidLoad() {
super.viewDidLoad()

let label = NSTextView(frame: CGRect(x: 20, y: 20, width: 100, height: 30))
let str = "A1 = 50 m2"

let aString = NSMutableAttributedString(string: str)

let myFont = NSFont(name: label.font!.fontName, size: 10.0)
let subscriptAttributes: [String : Any] = [ NSBaselineOffsetAttributeName: -5, NSFontAttributeName: myFont! ]
let superscriptAttributes: [String : Any] = [ NSBaselineOffsetAttributeName: 5, NSFontAttributeName: myFont! ]

aString.addAttributes(subscriptAttributes, range: NSRange(location: 1, length: 1))
aString.addAttributes(superscriptAttributes, range: NSRange(location: 9, length: 1))

// Kerning adds a little spacing between all the characters.
aString.addAttribute(NSKernAttributeName, value: 1.5, range: NSRange(location: 0, length: 2))
aString.addAttribute(NSKernAttributeName, value: 1.5, range: NSRange(location: 8, length: 2))

label.textStorage?.append(aString)

view.addSubview(label)
}

Here's the result:

Sample Image

Automatically markup part of NSTextView

Please try the following. My view controller has a single property, textView that points to an NSTextView in my storyboard.

import Cocoa

class ViewController: NSViewController {

@IBOutlet var textView: NSTextView!

override func viewDidLoad() {
super.viewDidLoad()

let text = "This is the string of my #NSTextView. All #hashtags should be displayed in bold."

textView.string = text

let attributes = [NSFontAttributeName : NSFont.systemFont(ofSize: 14.0)]
let range = NSRange(location: 0, length: text.characters.count)
textView.textStorage?.setAttributes(attributes, range: range)

do {

let regexString = "#(\\w*)"
let regex = try NSRegularExpression(pattern: regexString, options: [])

let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.characters.count))

for match in matches {
textView.textStorage?.setAttributes([NSFontAttributeName : NSFont.boldSystemFont(ofSize: 14.0)], range: match.range)
}

} catch let error {
print(error)
}
}
}

Append text to NSScrollView - Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Your issue is in clickOption when you are calling:

let vc = ViewController()
vc.myPrint(string: "This is a test")

When you call this method from code and the ViewController's UIViews are set up in a storyboard, the connection from the storyboard is not made. That is why the notesArea is nil when you call the function myPrint. In this case you are creating a new copy of ViewController and it will not be the same one that created the popover.

There are a few ways you can solve the problem that you are trying to accomplish. One of them is known as a delegate. This is a way for you to to call the ViewController's methods like your popover inherited them. You can check out a tutorial here. The idea is that we want to have a reference to the ViewController in your popover so that you can call the functions in the protocol. Then the ViewController that conforms to the protocol will be responsible for handling the method call.

So let's create a protocol called PrintableDelegate and have your ViewController class conform to it. Then in your popover, you will be able to have a reference to the ViewController as a weak var called delegate (you can use what ever name you want but delegate is standard). Then we can call the methods described in the protocol PrintableDelegate, by simply writing delegate?.myPrint(string: "Test"). I have removed some of your irrelevant code from my example.

protocol PrintableDelegate {
func myPrint(string: String)
}

class ViewController : UIViewController, PrintableDelegate {

func myPrint (string: String){
let mystring = string
let myNotes = notesArea.documentView as? NSTextView
let text = myNotes?.textStorage!
let attr = NSAttributedString(string: mystring)
text?.append(attr)
}

@IBAction func oneClicked(_ sender: NSButton) {
let vc = PopoverVC1.loadView()
// Set the delegate of the popover to this ViewController
vc.delegate = self
vc.showPopover(view: sender)
}
}

class PopoverVC1: NSViewController {

// Delegates should be weak to avoid a retain cycle
weak var delegate: PrintableDelegate?

@IBAction func clickOption(_ sender: NSButton) {
// Use the delegate that was set by the ViewController
// Note that it is optional so if it was not set, then this will do nothing
delegate?.myPrint(string: "This is a test")
}
}


Related Topics



Leave a reply



Submit