【问题标题】:Adding guidelines to a TextBox/RichTextBox向 TextBox/RichTextBox 添加指南
【发布时间】:2015-08-28 11:52:06
【问题描述】:

有没有办法在多行文本框或富文本框上显示网格线? 也许通过覆盖 OnPaint 事件?

我正在使用文本框插入地址信息,对于每一行,它会是这样的:

街道
城市
国家
等等

我正在使用带有 C# 的 WinForms。

【问题讨论】:

  • 为什么在文本框中需要网格线?文本框不是网格。
  • 只是为了让它看起来更好看。
  • 不太可能。考虑到这些控制的性质,我怀疑任何级别的覆盖都会起作用。他们很固执。你可能不得不发明一种新的控制方式。
  • 你可以为这种情况做一个解决方法,比如取 3 个文本框,每个文本框 Y 位置应立即从前一个框的 Y 轴+2 开始,并将所有文本框的边框样式设置为无。并使用 Graphics Calss 绘制一个矩形并在 OnPaint 中的文本框之间绘制一条线
  • @BhanuChowdary - 可以,但我无法从所有 3 个文本框中一次性复制文本 - 我想保留一个文本框

标签: c# winforms textbox richtextbox


【解决方案1】:

您可以使用以下方法之一:

  • 自定义文本框的绘制
  • 使用 RTF 技巧

这是这两种方式的截图:

如果你真的想要这个功能,我建议使用第一种方法。

1- 自定义TextBox的画图


自定义文本框绘制并不简单。您可以通过不同的方式自定义 TextBox 的绘制。这是自定义TextBox绘制的两种方式。

1-1 使用NativeWindow自定义TextBox的Paint


这样应该使用NativeWindow 子类化一个TextBox 并在窗口过程中处理WM_PAINT。这是实现您需要的完整代码清单。

要使用代码,只需将文本框传递给 CustomPaintTextBox 的实例即可:

var t = new CustomControls.CustomPaintTextBox(this.textBox1);

这里是CustomPaintTextBox的代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace CustomControls
{
    public class CustomPaintTextBox : NativeWindow
    {
        private TextBox parentTextBox;
        private const int WM_PAINT = 15;
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PAINT: 
                    // invalidate textbox to make it refresh
                    parentTextBox.Invalidate();
                    // call default paint
                    base.WndProc(ref m);
                    // draw custom paint
                    this.CustomPaint();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
        public CustomPaintTextBox(TextBox textBox)
        {
            this.parentTextBox = textBox;
            textBox.TextChanged += textBox_TextChanged;
            // subscribe for messages
            this.AssignHandle(textBox.Handle);
        }
        void textBox_TextChanged(object sender, EventArgs e)
        {
            CustomPaint();
        }
        private void CustomPaint()
        {
            var g= this.parentTextBox.CreateGraphics();
            float y = 0;
            var lineHeight = g.MeasureString("X", this.parentTextBox.Font).Height;
            while (y < this.parentTextBox.Height)
            {
                y += lineHeight;
                g.DrawLine(Pens.Red, 0f, y, (float)this.parentTextBox.Width, y);
            }
        }
    }
}

这个解决方案的优点是它非常简单,不需要新的继承文本框。

1-2- 创建透明文本框


这样你应该首先制作一个透明的文本框,然后将它的背景设置为你想要的网格线。由于这种方式也是一种创建自定义绘画文本框的方式,因此您也可以自定义该文本框的绘画并根据您的意愿进行调整。

这里是 2 篇关于透明文本框和透明富文本框的文章的链接:

2- 使用 RTF 技巧


有一些 rtf 技巧可以用来在 RichTextBox 中显示网格线。最好的技巧之一是在 RTF 中使用表格。在下面的代码中,我们使用了 3 行,其中包含一个宽度为 2000 缇的单元格:

this.richTextBox1.SelectAll();
this.richTextBox1.SelectedRtf =
@"{\rtf1\ansi\deff0
{\trowd
\cellx2000
\intbl Street\cell
\row}
{\trowd
\cellx2000
\intbl City\cell
\row}
{\trowd
\cellx2000
\intbl Country\cell
\row}
}";

重要提示:在代码编辑器中粘贴上述代码时,注意不要在富文本字符之前放置缩进。如果 Visual Studio 在它们之前插入缩进,则删除所有缩进。

【讨论】:

  • 感谢 Andrei Alecu 在 2007 年发表的关于文本框自定义绘制的精彩文章,codedblog.com 现已关闭。
  • 非常有趣。所以TextBoxRichTextBox 都有很好的解决方案。谢谢
  • @Reza - 感谢 Reza,这段代码可以正常工作,但是,看起来行高不正确。每条新线都画得太快了。第二种方法的行高是正确的。有没有办法预先用 rtf 画线,而不是使用有行和列的表格?
  • @langjacques 不客气 :) - 关于使用 rtf,Table 方法是最好的技巧之一,同时还有一些我知道的其他技巧不如 table 好或不能显示在 RichTextBox 中,并且只能在写字板中使用。 - 我建议使用第一种方法。屏幕截图是在我的系统上执行的,看起来很正常,但是如果您在渲染文本框时遇到问题,您可以尝试增加高度。
  • @Reza - 很酷,我正在使用您提供的第一种方法,只是从行高中减去 0.8F。我会做更多的测试,但现在看起来不错!
【解决方案2】:

从这段代码开始:

class GridLineTextBox : TextBox
{
    public GridLineTextBox()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var y = 0f;
        var lineHeight = e.Graphics.MeasureString("W", Font).Height;
        while (y < e.ClipRectangle.Height)
        {
            y += lineHeight;
            e.Graphics.DrawLine(System.Drawing.Pens.Aqua, new PointF(0, y), new PointF(e.ClipRectangle.Width, y));
        }
    }
}

【讨论】:

  • 这段代码绘制了线条,但是当我在第一行输入一些文本并回车时,线条向下移动 - 几乎就像文本停留在第一行一样
  • 其实线条不会下移,实际上你画的线条会在GDI+在上面绘制文字时被清除。
  • 嗯,所以每当你输入文字时,线条就会消失,我希望线条留在那儿
  • 是的,现在我找不到更好的方法来做到这一点。有机会用线条覆盖Panel,它是半透明的Textbox,当点击它时,会将焦点指向Textbox。但我发现这样的解决方案比必要的更麻烦。
  • 我同意 - 这么小的事情似乎太费力了,无论如何谢谢
【解决方案3】:

可能是一个 RTF 模板文件:

{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\trowd \trgaph180
\cellx3440\pard\intbl [0]\cell
\row
\trowd \trgaph180
\cellx3440\pard\intbl [1]\cell
\row
\trowd \trgaph180
\cellx3440\pard\intbl [2]\cell
\row
\para}

Dim fileContents As String
fileContents = My.Computer.FileSystem.ReadAllText("C:\temp\template.rtf")
Dim sRTF As String = fileContents.Replace("[0]", "line 1").Replace("[1]", "line 2").Replace("[2]", "line 3")
RichTextBox1.Rtf = sRTF

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-10
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 2019-04-22
    • 2012-10-16
    相关资源
    最近更新 更多