How to disable word-wrap of NSTextView?
Asked Answered
A

5

22

NSTextView does word-wrap by default. How can I disable this? I'm making a JSON code viewer, so I have to disable this.

Acolyte answered 4/7, 2010 at 8:15 Comment(1)
While this is an older question, both the OP question and the selected answer still apply in 2021 with AppKit.Phebe
A
33

First, this document explains why and how -- https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextStorageLayer/Tasks/TrackingSize.html#//apple_ref/doc/uid/20000927-CJBBIAAF

I got solution from: http://lists.apple.com/archives/cocoa-dev/2008/May/msg02396.html

You have to set NSTextView's maximum width to very large number to make this work correctly. (Just copy maximum height) And enable horizontal scrolling of NSScrollView which is superview of the NSTextView. See these pictures:

http://www.flickr.com/photos/47601728@N06/4759470529/

alt text

http://www.flickr.com/photos/47601728@N06/4759470533/

alt text

Update

I discovered my old sample code was insufficient to make it fully work correctly. (because of SDK version?) Also Here's my full source code snippet which disables word-wrap in OSX 10.8 SDK.

[self setMaxSize:CGSizeMake(FLT_MAX, FLT_MAX)];    
[self setHorizontallyResizable:YES];               
[[self textContainer] setWidthTracksTextView:NO];  
[[self textContainer] setContainerSize:CGSizeMake(FLT_MAX, FLT_MAX)];  

Update 2

Now Apple is providing an official guide to create NSTextView correctly. I hope this helps.

Update 3

I posted an example project on Github. See this page for specific implementation: https://github.com/Eonil/CocoaProgrammaticHowtoCollection/blob/master/ComponentUsages/TextView/ExampleApplicationController.swift?ts=4

Here's a code snippet from the sample project.

if wordWrap {
    /// Matching width is also important here.
    let sz = scrollView.contentSize
    textView.frame = CGRect(x: 0, y: 0, width: sz.width, height: 0)
    textView.textContainer?.containerSize = CGSize(width: sz.width, height: CGFloat.greatestFiniteMagnitude)
    textView.textContainer?.widthTracksTextView = true
}
else {
    textView.textContainer?.widthTracksTextView = false
    textView.textContainer?.containerSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
}

Acolyte answered 4/7, 2010 at 9:51 Comment(5)
I tried your code, which did indeed disable word wrap, however the scrollview does not seem to allow scrolling to view the non-wrapped text.Janetjaneta
Never mind, I'm just an idiot. I forgot to enable horizontal scrolling on the NSScrollView.Janetjaneta
The 3rd update you added is the only thing that worked for me. Those NSScrollView properties you set there are key.Grimsley
Any idea on how to force refresh when changing that when the NSTextView is already life? I'm making a user default for line wrapping, and need the change to be effective immediately. Tried -layoutSubtreeIfNeeded on the NSScrollView with no luck.Roommate
Already found my answer... you're right, setting the textContainer's containerSize to the scroll view's contentSize is the answer. textView.textContainer.containerSize = NSMakeSize(textView.enclosingScrollView.contentSize.width, FLT_MAX)Roommate
Y
7

The three lines given in the accepted answer by Eonil alone did not work for me, the resulting text view did not scroll horizontally and therefore there was no way to see the clipped part of the long lines.

The full code snippet from the referenced cocoa-dev thread did produce the correct results. Specifically, this set of steps:

NSSize layoutSize = [textView maxSize];
layoutSize.width = layoutSize.height;
[textView setMaxSize:layoutSize];
[[textView textContainer] setWidthTracksTextView:NO];
[[textView textContainer] setContainerSize:layoutSize];
You answered 15/8, 2013 at 2:49 Comment(0)
L
4

I have written an extension on NSTextView.

extension NSTextView {
    var wrapsLines: Bool {
        get {
            return self.textContainer?.widthTracksTextView ?? false
        }
        set {
            guard
                newValue != self.wrapsLines,
                let scrollView = enclosingScrollView,
                let textContainer = self.textContainer
                else { return }

            scrollView.hasHorizontalScroller = !newValue
            isHorizontallyResizable = !newValue
            textContainer.widthTracksTextView = newValue

            if newValue {
                self.frame.size[keyPath: \NSSize.width] = scrollView.contentSize.width
                maxSize = NSSize(width: scrollView.contentSize.width, height: CGFloat.greatestFiniteMagnitude)
                textContainer.size.width = scrollView.contentSize.width
            } else {
                let infiniteSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
                maxSize = infiniteSize
                textContainer.size = infiniteSize
            }
        }
    }
}
Linhliniment answered 5/4, 2020 at 16:51 Comment(0)
E
0

I found this solution did prevent line wrapping, but had some unfortunate drawing consequences for the NSTextView. The problem was that when the NSPanel containing the text views was dragged to be wider than the lines of text, the NSView's bounds rect was adjusted (by the underlying layout manager) to just be slightly longer than the text - revealing the NSPanel's background. Not what I had in mind ...

My solutions was to enable resizing in the NSPanel, constrain it to the horizontal by setting of min and max sizes and turn off horizontal resizing for the text view itself:

// some fragments from the creation of the NSPanel
// resizable NSPanel created
mMonitorPanel = [[NSPanel alloc] initWithContentRect: monitorRect
              styleMask: (NSTitledWindowMask| NSMiniaturizableWindowMask | NSResizableWindowMask)
                backing: NSBackingStoreBuffered defer: NO];

 // constrain resizing to horizontal only, with obvious limits ...
[mMonitorPanel setContentMaxSize: NSMakeSize(1000, 600)];
[mMonitorPanel setContentMinSize: NSMakeSize(300,  600)];

// a fragment from the init that creates an instance of a subclass of NSTextView ...

[self setVerticallyResizable: NO];
[self setHorizontallyResizable: NO];  // rather than YES as prior code snippet

// the rest is the same as above
[[self textContainer] setContainerSize: NSMakeSize(FLT_MAX, FLT_MAX)];
[[self textContainer] setWidthTracksTextView: NO];

This results in a monitor panel that can be horizontally resized, does not wrap lines, and draws properly in it's enclosing NSPanel.

Hope this helps someone - don't know where I'd be without all the good fixes I've found on this site!

Emulation answered 13/4, 2013 at 1:40 Comment(0)
K
-8

Easiest way is in Interface Builder, in the inspector just change the drop-down menu.

Kemeny answered 4/7, 2010 at 10:7 Comment(7)
What's the box to uncheck for this?Acolyte
Sorry, it's actually not a button, it's a drop-down menu. It says "Default Behavior" and you can select Scroll, which would fit your application well.Kemeny
SeniorShizzle: There is no such pop-up menu for NSTextViews as of IB 3.2.1.Desmarais
Oh. Sorry I misread your post, I thought you said NSTextField in which case my answer would work. The above poster's method should work fine then, if not you might either try messing with the "Horizontal Line Scroll" field, (I'm not sure, but it sounds promising) or if your application would allow it just use an NSTextField it's my preferred choice.Kemeny
A text field wouldn't work very well for a code view, as a text field is primarily for single-line values. (As an aside, I actually do let my editors wrap my code.)Desmarais
NSTextField was not suitable for my purpose. There're pretty many limitations to display very large amount of text.Acolyte
Adding why it's easier or steps to reproduce in IB would have been helpful.Phebe

© 2022 - 2024 — McMap. All rights reserved.