如何重新布局 NSTextView 的内容,以便我的制表符以 4 个字符的宽度绘制

发布于 2024-08-21 12:42:31 字数 1815 浏览 4 评论 0原文

我正在使用 NSTextView,我的要求之一是制表符“\t”的宽度应与四个空格相同。

因此,文本内容将如下所示:

AAAA
    AAAA - 1 tab
    AAAA - 4 spaces

这就是我实现此目的的方法:

// done when NSTextView first loaded and when
// delegate's textDidBeginEditing gets called: (perhaps overkill, but is a work in progress).
- (void)updateMyTextViewTextAttributes
{
    NSMutableParagraphStyle* paragraphStyle = [[myTextView defaultParagraphStyle] mutableCopy];
    if (paragraphStyle == nil) {
        paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    }
    float charWidth = [[myFont screenFontWithRenderingMode:NSFontDefaultRenderingMode] advancementForGlyph:(NSGlyph) ' '].width;
    [paragraphStyle setDefaultTabInterval:(charWidth * 4)];
    [paragraphStyle setTabStops:[NSArray array]];
    [myTextView setDefaultParagraphStyle:paragraphStyle];

    NSMutableDictionary* typingAttributes = [[myTextView typingAttributes] mutableCopy];
    [typingAttributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    [typingAttributes setObject:scriptFont forKey:NSFontAttributeName];
    [myTextView setTypingAttributes:typingAttributes];
}

这允许使用初始文本显示适当的布局,并保持键入属性相同。

问题是最终用户可以更改字体。当这种情况发生时,示例文本就会变得不对齐。很像下面的内容:

[smaller font]
AAAA
     AAAA - 1 tab
    AAAA - 4 spaces


[larger font]
AAAA
   AAAA - 1 tab
    AAAA - 4 spaces

我尝试调用 myTextView 的 setNeedsDisplay:YES ,因为我读到它最终调用 NSTextView 的 setNeedsDisplayInRect:avoidAdditionalLayout ,并且避免附加布局参数为 NO 。这并没有改变任何事情。

当 myTextView 设置了新的 myFont 时,我尝试调用 updateMyTextViewTextAttributes 调用。这并没有改变什么。

我还尝试告诉myTextView 的layoutManager 为myTextView 的textContainer 确保LayoutForTextContainer。没有变化。

此时,我不确定下一步要尝试什么。有什么建议吗?

I'm working with an NSTextView and one of the requirements I have is that a tab character, '\t', shall have the same width as four spaces.

So the text-content would look like this:

AAAA
    AAAA - 1 tab
    AAAA - 4 spaces

And this is how I accomplish this:

// done when NSTextView first loaded and when
// delegate's textDidBeginEditing gets called: (perhaps overkill, but is a work in progress).
- (void)updateMyTextViewTextAttributes
{
    NSMutableParagraphStyle* paragraphStyle = [[myTextView defaultParagraphStyle] mutableCopy];
    if (paragraphStyle == nil) {
        paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    }
    float charWidth = [[myFont screenFontWithRenderingMode:NSFontDefaultRenderingMode] advancementForGlyph:(NSGlyph) ' '].width;
    [paragraphStyle setDefaultTabInterval:(charWidth * 4)];
    [paragraphStyle setTabStops:[NSArray array]];
    [myTextView setDefaultParagraphStyle:paragraphStyle];

    NSMutableDictionary* typingAttributes = [[myTextView typingAttributes] mutableCopy];
    [typingAttributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    [typingAttributes setObject:scriptFont forKey:NSFontAttributeName];
    [myTextView setTypingAttributes:typingAttributes];
}

This allows the appropriate layout to be shown with the initial text as well as keep the typing attributes the same.

The problem is that the end-user can change the font. And when that happens, the sample text becomes misaligned. Much like the below:

[smaller font]
AAAA
     AAAA - 1 tab
    AAAA - 4 spaces

[larger font]
AAAA
   AAAA - 1 tab
    AAAA - 4 spaces

I've tried calling myTextView's setNeedsDisplay:YES as I read that it ends up calling NSTextView's setNeedsDisplayInRect:avoidAdditionalLayout with a NO for the avoidAdditionalLayout parameter. This didn't change anything.

I've tried calling my updateMyTextViewTextAttributes call when myTextView has the new myFont set. That doesn't change a thing.

I've also tried telling the layoutManager of myTextView to ensureLayoutForTextContainer for the textContainer of myTextView. No change.

At this point, I'm not sure what to try next. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

So要识趣 2024-08-28 12:42:31

Apple 的 Douglas Davidson 为我提供了线索通过[email protected]电子邮件列表找到答案。

我通过更新 updateMyTextViewTextAttributes 函数解决了该问题,如下所示:

- (void)updateMyTextViewTextAttributes
{
   NSMutableParagraphStyle* paragraphStyle = [[myTextView defaultParagraphStyle] mutableCopy];

   if (paragraphStyle == nil) {
       paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
   }

   float charWidth = [[myFont screenFontWithRenderingMode:NSFontDefaultRenderingMode] advancementForGlyph:(NSGlyph) ' '].width;
   [paragraphStyle setDefaultTabInterval:(charWidth * 4)];
   [paragraphStyle setTabStops:[NSArray array]];

   [myTextView setDefaultParagraphStyle:paragraphStyle];

   NSMutableDictionary* typingAttributes = [[myTextView typingAttributes] mutableCopy];
   [typingAttributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
   [typingAttributes setObject:scriptFont forKey:NSFontAttributeName];
   [myTextView setTypingAttributes:typingAttributes];

   /** ADDED CODE BELOW **/
   NSRange rangeOfChange = NSMakeRange(0, [[myTextView string] length]);
   [myTextView shouldChangeTextInRange:rangeOfChange replacementString:nil];
   [[myTextView textStorage] setAttributes:typingAttributes range:rangeOfChange];
   [myTextView didChangeText];

   [paragraphStyle release];
   [typingAttributes release];
}

Douglas Davidson of Apple provided me with the clues to get to the answer via the [email protected] email list.

I've resolved the problem by updating the updateMyTextViewTextAttributes function like so:

- (void)updateMyTextViewTextAttributes
{
   NSMutableParagraphStyle* paragraphStyle = [[myTextView defaultParagraphStyle] mutableCopy];

   if (paragraphStyle == nil) {
       paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
   }

   float charWidth = [[myFont screenFontWithRenderingMode:NSFontDefaultRenderingMode] advancementForGlyph:(NSGlyph) ' '].width;
   [paragraphStyle setDefaultTabInterval:(charWidth * 4)];
   [paragraphStyle setTabStops:[NSArray array]];

   [myTextView setDefaultParagraphStyle:paragraphStyle];

   NSMutableDictionary* typingAttributes = [[myTextView typingAttributes] mutableCopy];
   [typingAttributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
   [typingAttributes setObject:scriptFont forKey:NSFontAttributeName];
   [myTextView setTypingAttributes:typingAttributes];

   /** ADDED CODE BELOW **/
   NSRange rangeOfChange = NSMakeRange(0, [[myTextView string] length]);
   [myTextView shouldChangeTextInRange:rangeOfChange replacementString:nil];
   [[myTextView textStorage] setAttributes:typingAttributes range:rangeOfChange];
   [myTextView didChangeText];

   [paragraphStyle release];
   [typingAttributes release];
}
戒ㄋ 2024-08-28 12:42:31

您是否尝试过直接在字体而不是屏幕字体上使用 advancementForGlyph: 来计算空间进度?

float charWidth = [myFont advancementForGlyph:(NSGlyph) ' '].width;

屏幕字体不应该直接在窗口服务器外部使用:

屏幕字体可直接使用
仅限窗口服务器。切勿使用它们
与应用程序工具包对象,例如
在 setFont: 方法中。在内部,
应用程序工具包自动使用
字体对应的屏幕字体
只要视图不是对象
旋转或缩放。

Have you tried to compute space advancement with advancementForGlyph: directly on the font instead of the screen font ?

float charWidth = [myFont advancementForGlyph:(NSGlyph) ' '].width;

Screen font are not meant to be used directly outside the window server:

Screen fonts are for direct use with
the window server only. Never use them
with Application Kit objects, such as
in setFont: methods. Internally, the
Application Kit automatically uses the
corresponding screen font for a font
object as long as the view is not
rotated or scaled.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文