将文本换行到富文本框中,但不进行自动换行

发布于 2024-09-27 17:01:40 字数 181 浏览 0 评论 0原文

我有一个 Windows 窗体,窗体上带有富文本框控件。我想做的是让每行只接受 32 个字符的文本。在 32 个字符之后,我希望文本流到下一行(我不想插入任何回车符)。 WordWrap 属性几乎可以做到这一点,只不过它将所有输入的文本移动到文本中的最后一个空格并将其全部移动。我只是想在 32 个字符之后整齐地换行。我该怎么做?我正在使用 C#。

I have a Windows Form with a Rich Textbox control on the form. What I want to do is make it so that each line only accepts 32 characters of text. After 32 characters, I want the text to flow to the next line (I do NOT want to insert any carriage returns). The WordWrap property almost does this, except that it moves all the text entered, up to the last space in the text and moves it all. I just want to neatly wrap the text right after 32 characters. How can I do this? I'm using C#.

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

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

发布评论

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

评论(4

凉城已无爱 2024-10-04 17:01:40

好吧,我已经找到了一种方法来做到这一点(经过大量谷歌搜索和 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;

    }

最后,在您表格的 Shown 事件中:

        myCallBackEvent = new EditWordBreakProc(myCallBack);

        IntPtr ptr_func = Marshal.GetFunctionPointerForDelegate(myCallBackEvent);

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

Ok, I have found a way to do this (after a lot of googling and Windows API referencing) and I am posting a solution here in case anyone else ever needs to figure this out. There is no clean .NET solution to this, but fortunately, the Windows API allows you to override the default procedure that gets called when handling word wrapping. First you need to import the following DLL:

[DllImport("user32.dll")]

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

Then you need to define this constant:

 const uint EM_SETWORDBREAKPROC = 0x00D0;

Then create a delegate and event:

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

    event EditWordBreakProc myCallBackEvent;

Then create our new function to handle word wrap (which in this case I don't want it to do anything):

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

    {

        return 0;

    }

Finally, in the Shown event of your form:

        myCallBackEvent = new EditWordBreakProc(myCallBack);

        IntPtr ptr_func = Marshal.GetFunctionPointerForDelegate(myCallBackEvent);

        SendMessage(txtDataEntry.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, ptr_func);
相对绾红妆 2024-10-04 17:01:40

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

If you are using only (one) fixed width font for text within rich text box then you can use MeasureString to count the width needed for 32 characters and then adjust rich text box width accordingly. Thats should do wrapping within 32 characters.

冷︶言冷语的世界 2024-10-04 17:01:40

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

确保 Word Wrap 和 Multiline 属性仍然设置为 true,然后,您只需检查 KeyCode.Return 和 KeyCode.Return 的按键按下情况即可。键码。输入。

如下所示:-

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

        }

将此处的处理值设置为 true,发送回我们已处理按键事件的消息,但什么也没有发生。文本控件继续使用自动换行并阻止回车。

希望这有帮助。

I've been looking into this problem myself and have found a really easy way to get around this. You need to place a small piece of code in the Key_Down Event on your TextBox or RichTextBox control.

Ensure that both Word Wrap and Multiline properties are still set to true, then, you just need to check for the Key Press of KeyCode.Return & Keycode.Enter.

Like Below :-

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

        }

Setting the handled value you here to true, sends back the message that we have dealt with the Key Press event, and nothing happens. The Text Control continues to use Word Wrap and blocks the carriage return.

Hope this helps.

情丝乱 2024-10-04 17:01:40

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

我说“几乎”,因为它还有一个微妙的错误:为回调创建的委托不存储在任何变量中,这使得它有资格进行垃圾收集。垃圾收集器没有任何方法知道您已将委托包装在指针中传递给窗口对象,因此最终将能够丢弃该委托,这将导致应用程序崩溃下次 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 事件处理程序中初始化分词过程。这完成了两件事:首先,在控件句柄有效之后尽快进行初始化,其次,如果 TextBox.Text 属性为已经设置,例如在设计器或表单的构造函数中,即使对于初始文本,包装仍将正确完成。

稍后粘贴的文本仍然可以,当然,您甚至可以在初始化后临时重置文本以强制重新计算换行。但恕我直言,最好一开始就让它发挥作用。

另请注意,上述内容需要对添加到表单的每个 TextBox 进行显式初始化。显然,如果您想将此技术应用于多个 TextBox,那么创建一个新的 TextBox 子类并在其自己的 OnHandleCreated 中执行此初始化是有意义的() 重写方法。

The accepted answer almost works, but is a bit awkward, due to the unnecessary use of event, explicit delegate instantiation, and non-static callback method.

I say "almost", because it also has a subtle bug: the delegate that is created for the callback is not stored in any variable, which makes it eligible for garbage collection. The garbage collector doesn't have any way to know that you've handed the delegate-wrapped-in-a-pointer to the window object, and so would eventually be able to discard the delegate which would then cause the application to crash the next time the TextBox control needed to wrap any text.

Here is a version that is more to my liking:

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);
    }
}

The other difference here is that I initialize the word-break proc in the TextBox.HandleCreated event handler. This accomplishes two things: first, the initialization happens as soon as possible, right after the control's handle is valid, and second, by doing the initialization this early in the process, if the TextBox.Text property was already set, e.g. in the Designer or the form's constructor, the wrapping will still be done correctly even for that initial text.

Text pasted in later would still be fine, and of course you could even just temporarily reset the text after initialization to force recomputation of the wrapping. But IMHO it's better to just get it to work early enough in the first place.

Also note that the above require explicit initialization of each TextBox you've added to the form. Obviously, if you wanted to apply this technique to more than one TextBox, it would make sense to create a new TextBox subclass that does this initialization within its own OnHandleCreated() override method.

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