【问题标题】:Measure String inside RichTextBox Control在 RichTextBox 控件中测量字符串
【发布时间】:2011-01-22 19:49:15
【问题描述】:

谁能解释一下我将如何测量richtextbox控件中的字符串,以便我可以根据其内容自动调整richtextbox控件的大小?

谢谢

编辑:

我已经考虑过了,因为如果 RichTextBox 控件中有不同的字体,下面的答案将不起作用,如果我可以得到richtextbox 控件的左上角坐标然后得到底部- rtb 中最后一行文本的右坐标。这基本上会给我 RichTextBox 控件中字符串的宽度和高度。这可能吗?还是这样做是个坏主意?

【问题讨论】:

    标签: c# winforms richtextbox autoresize measure


    【解决方案1】:

    加入 Bathineni 的精彩回答:

    背景:我需要测量 RTF 输出高度以渲染到纸上,因为我有自定义动态页眉/页脚,所以我需要控制分页)。

    (RichTextBox.GetLineFromCharIndex 因为复杂的 RTF 而让我失望;包括带有自动换行的行和多列表格)。

    无论如何,一切工作正常,直到其他人使用我的应用程序和可怕的窗口“使文本和其他项目更大或更小”(DPI 设置。) - 简而言之,现在测量更大尺寸的字体它搞砸了页面长度计算。 (打印机仍然正确地渲染了文本和列 - 只有页面长度现在都是错误的。)

    只有考虑 DPI 差异的因素失败了,因为简短较大的文本不能正确地适合源 RTF tx 和 cellx 值。

    无论如何,如果其他人正在做类似的疯狂事情,经过反复试验后,我们对 Bathineni CalculateRichTextHeight 方法提出了以下(最终很少)修改:

    RichTextBox richTextBox = new RichTextBox();     // same as original
    int dpix = richTextBox.CreateGraphics().DpiX;    // get dpi
    richTextBox.WordWrap = true;                     // I needed this, you many not
      // ... set size etc - same as original answer
    richTextBox.Scale(new System.Drawing.SizeF(dpix / 96, dpix / 96));  // scale RTB
      // ...
      // 96? my original calculations based on windows default 96dpi settings.
    

    似乎原本晦涩难懂的 Control.Scale(sizef) 毕竟对某些东西很有用。

    注意:如果将结果转换为实际打印的行,(在我的情况下,我的所有 \pard 都是“\sl-240\slmult0”,每行输出 16 个(像素?))还记得重新考虑除数. 即在我的情况下:

    lines = height / (int)(16 * (dpix / 96))
    

    【讨论】:

      【解决方案2】:

      我找到了富文本框高度问题的解决方案。我已将其修改为一般用途。

      在您的应用程序中创建以下结构......

      [StructLayout(LayoutKind.Sequential)]
          public struct RECT {
              public Int32 left;
              public Int32 top;
              public Int32 right;
              public Int32 bottom;
          }
      
          [StructLayout(LayoutKind.Sequential)]
          public struct SCROLLBARINFO {
              public Int32 cbSize;
              public RECT rcScrollBar;
              public Int32 dxyLineButton;
              public Int32 xyThumbTop;
              public Int32 xyThumbBottom;
              public Int32 reserved;
              [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
              public Int32[] rgstate;
          }
      

      在您的类中为表单创建以下私有变量(您需要计算富文本高度)

      private UInt32 SB_VERT = 1;
              private UInt32 OBJID_VSCROLL = 0xFFFFFFFB;
      
              [DllImport("user32.dll")]
              private static extern
                  Int32 GetScrollRange(IntPtr hWnd, UInt32 nBar, out Int32 lpMinPos, out Int32 lpMaxPos);
      
              [DllImport("user32.dll")]
              private static extern
                  Int32 GetScrollBarInfo(IntPtr hWnd, UInt32 idObject, ref SCROLLBARINFO psbi);
      

      为表单添加以下方法

      private int CalculateRichTextHeight(string richText) {
                  int height = 0;
                  RichTextBox richTextBox = new RichTextBox();
                  richTextBox.Rtf = richText;
                  richTextBox.Height = this.Bounds.Height;
                  richTextBox.Width = this.Bounds.Width;
                  richTextBox.WordWrap = false;
                  int nHeight = 0;
                  int nMin = 0, nMax = 0;
      
                  SCROLLBARINFO psbi = new SCROLLBARINFO();
                  psbi.cbSize = Marshal.SizeOf(psbi);
      
                  richTextBox.Height = 10;
                  richTextBox.ScrollBars = RichTextBoxScrollBars.Vertical;
      
                  int nResult = GetScrollBarInfo(richTextBox.Handle, OBJID_VSCROLL, ref psbi);
                  if (psbi.rgstate[0] == 0) {
                      GetScrollRange(richTextBox.Handle, SB_VERT, out nMin, out nMax);
                      height = (nMax - nMin);
                  }
      
                  return height;
              }
      

      您可能需要修改上述方法以使其按照您的要求工作... 确保将 Rtf 字符串作为参数发送给方法不是普通文本,并确保将可用宽度和高度分配给方法中的 Richtextbox 变量...

      您可以根据自己的要求使用 WordWrap...

      【讨论】:

      • 这不起作用。高度总是太短。
      【解决方案3】:

      将以下代码放入ContentsResized事件中:

      Private Sub rtb_ContentsResized(ByVal sender As Object, ByVal e As System.Windows.Forms.ContentsResizedEventArgs) Handles txtQuestion.ContentsResized
              Dim h = e.NewRectangle.Height, w = e.NewRectangle.Width
              h = Math.Max(h, sender.Font.Height)
              h = Math.Min(h, Me.ClientSize.Height - 10 - sender.Top)
              h += sender.Height - sender.ClientSize.Height + 1
              sender.Height = h
      End Sub
      

      【讨论】:

      • ContentsResizede.NewRectangle 为我解决了问题。其他常见的嫌疑人,例如AutoSizeGetPreferredSize 似乎不适用于 RichTextBox
      • 这不起作用。高度最终太短了,即使我将其修改为设置 sender.Width = w,宽度也不会改变。
      【解决方案4】:

      尝试拨打GetPreferredSize(Size.Empty)。它是在 Control 类中定义的,如果 RichTextBoxControl 覆盖了该属性,应该会为您提供所需的内容。

      如果您将 Size.Empty 以外的内容传递给该方法,那么它将使用该值作为最大约束。使用 Size.Empty 意味着潜在的大小是无限的。

      【讨论】:

      • 您甚至可以使用宽度GetPreferredSize(new Size(width, 0)) 调用它,并且您可以从该调用的返回大小中获取高度
      • 这不起作用。 GetPerferredSize 返回的高度和宽度都太短了。
      【解决方案5】:

      假设有人在控件中键入内容,您可以使用事件在每次输入字符时触发(递增计数器)并在删除字符时递减。这会给你一个真实的计数。

      编辑:

      你试过这个来调整高度吗?

      richTextBox1.Height = (int)(1.5 * richTextBox1.Font.Height) + richTextBox1.GetLineFromCharIndex(richTextBox1.Text.Length + 1) * richTextBox1.Font.Height + 1 + richTextBox1.Margin.Vertical;
      
      richTextBox1.SelectionStart = 0;
      
      richTextBox1.SelectionStart = richTextBox1.Text.Length;
      

      或者你可以使用宽度来做到这一点:

      Graphics g = Graphics.FromHwnd(richTextBox1.Handle);
      
      SizeF f = g.MeasureString(richTextBox1.Text, richTextBox1.Font);
      richTextBox1.Width = (int)(f.Width)+5;
      

      【讨论】:

      • 这就是我目前正在做的事情,虽然你不能以这种方式考虑字体样式/大小,最终 rtb 将无法跟上并且文本会溢出
      • 无意冒犯,但这会产生非常难看的结果。必须有一种方法可以做到这一点,而且看起来 RichTextBox 会在我的显示器中爆炸。
      • 嗯,它在这里似乎工作正常,但我没有应用任何字体样式
      • 这可能适用于简单的文本框,但不适用于可以包含粗体字、使用多种字体和多种字体大小的 RichTextBox。
      【解决方案6】:

      您可以通过调用TextRenderer.MeasureText来测量字符串。

      但是,如果文本包含多种字体,这将不起作用。

      编辑:您正在寻找GetPositionFromCharIndex 方法。
      请注意,如果有多行,则应取每行最后一个字符的 X 坐标的最大值。

      【讨论】:

      • 谢谢。我不太明白那个页面。为什么会画文字?它可以只向我发送一个宽度和高度值,以便我可以将 RichTextBox 的大小重置为新大小吗?
      • TextRenderer.MeasureText 不画任何东西;它只是以像素为单位返回文本的大小。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      相关资源
      最近更新 更多