繁体   English   中英

在富文本框中包装文本,但不包装它

[英]Wrapping Text in a rich textbox, but not word wrapping it

我在窗体上有一个带有Rich Textbox控件的Windows窗体。 我想要做的是使每行只接受32个字符的文本。 在32个字符之后,我希望文本流到下一行(我不想插入任何回车符)。 WordWrap属性几乎可以执行此操作,除了它将所有输入的文本移动到文本中的最后一个空格并将其全部移动。 我只想在32个字符后整齐地包裹文本。 我怎样才能做到这一点? 我正在使用C#。

好的,我已经找到了一种方法(在经过大量的谷歌搜索和Windows API引用之后),我发布了一个解决方案,以防其他任何人需要解决这个问题。 没有干净的.NET解决方案,但幸运的是,Windows API允许您覆盖处理自动换行时调用的默认过程。 首先,您需要导入以下DLL:

[DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

然后你需要定义这个常量:

 const uint EM_SETWORDBREAKPROC = 0x00D0;

然后创建一个委托和事件:

    delegate int EditWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);

    event EditWordBreakProc myCallBackEvent;

然后创建我们的新函数来处理自动换行(在这种情况下我不希望它做任何事情):

     private int myCallBack(IntPtr text, int pos_in_text, int bCharSet, int action)

    {

        return 0;

    }

最后,在您的表单的已显示事件中:

        myCallBackEvent = new EditWordBreakProc(myCallBack);

        IntPtr ptr_func = Marshal.GetFunctionPointerForDelegate(myCallBackEvent);

        SendMessage(txtDataEntry.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, ptr_func);

如果在富文本框中仅为文本使用(一个)固定宽度字体,则可以使用MeasureString计算32个字符所需的宽度,然后相应地调整富文本框宽度。 这应该包装在32个字符以内。

我自己一直在研究这个问题,并找到了解决这个问题的简单方法。 您需要在TextBox或RichTextBox控件的Key_Down事件中放置一小段代码。

确保Word Wrap和Multiline属性仍然设置为true,然后,您只需要检查KeyCode.Return&Keycode.Enter的按键。

如下: -

private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
            {
                e.Handled = true;
            }

        }

将此处的处理值设置为true,发回我们处理Key Press事件的消息,并且没有任何反应。 文本控件继续使用Word Wrap并阻止回车。

希望这可以帮助。

接受的答案几乎可行,但由于不必要地使用event ,显式委托实例化和非静态回调方法,因此有点尴尬。

我说“差不多”,因为它也有一个微妙的错误:为回调创建的委托不存储在任何变量中,这使得它有资格进行垃圾收集。 垃圾收集器没有任何方法可以知道你已经将委托包装在指针中的窗口对象,因此最终将能够丢弃委托,这会导致应用程序崩溃下次TextBox控件需要包装任何文本。

这是一个更符合我的喜好的版本:

public partial class Form1 : Form
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

    private const uint EM_SETWORDBREAKPROC = 0x00D0;

    private delegate int SetWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);
    private readonly SetWordBreakProc _wordBreakCallback = (text, pos_in_text, bCharSet, action) => 0;

    public Form1()
    {
        InitializeComponent();
        textBox1.HandleCreated += TextBox1_HandleCreated;
    }

    private void TextBox1_HandleCreated(object sender, EventArgs e)
    {
        IntPtr callback = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_wordBreakCallback);

        SendMessage(((Control)sender).Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, callback);
    }
}

另一个区别是我在TextBox.HandleCreated事件处理程序中初始化word-break proc。 这完成了两件事:首先,在控件的句柄有效之后立即进行初始化,其次,如果已经设置了TextBox.Text属性,则在过程的早期进行初始化,例如在Designer中或者表单的构造函数,即使对于那个初始文本,包装仍然会正确完成。

稍后粘贴的文本仍然可以正常使用,当然您甚至可以在初始化后暂时重置文本以强制重新计算包装。 但恕我直言,最好早点让它早点工作。

另请注意,上面要求显式初始化您添加到表单中的每个TextBox 显然,如果你想将这种技术应用于多个TextBox ,那么创建一个新的TextBox子类是有意义的,它在自己的OnHandleCreated()覆盖方法中进行初始化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM