RichTextBox语法实时高亮--禁用重绘

发布于 2024-09-10 15:22:39 字数 668 浏览 3 评论 0原文

我正在创建一个函数,它接受 RichTextBox 并可以访问关键字和关键字列表。 ‘脏话’。我需要突出显示任何关键字和当用户输入时,我在 RichTextBox 中发现了坏词,这意味着每次释放编辑键时都会调用该函数。

我已经编写了这个函数,但是框中的单词和光标闪烁太多,不舒服。

我发现了一个解决方案——在编辑和格式化文本时禁用 RichTextBox 重新绘制自身的能力。但是,我知道执行此操作的唯一方法是覆盖“WndProc”函数并拦截(我要收集的是)重绘消息,如下所示:

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg == 0x00f) {
         if (paint)
            base.WndProc(ref m);
         else
            m.Result = IntPtr.Zero;
    }
    else
         base.WndProc(ref m);
}

其中布尔“paint”在我之前设置为 false开始突出显示,当我完成时变为 true。但正如我所说,我创建的函数必须采用 RichTextBox;我不能使用子类。

那么,有没有办法“从外部”禁用 RichTextBox 的自动重绘?

I'm creating a function that takes a RichTextBox and has access to a list of keywords & 'badwords'. I need to highlight any keywords & badwords I find in the RichTextBox while the user is typing, which means the function is called every time an editing key is released.

I've written this function, but the words and cursor in the box flicker too much for comfort.

I've discovered a solution--to disable the RichTextBox's ability to repaint itself while I'm editing and formatting its text. However, the only way I know to do this is to override the "WndProc" function and intercept (what I've been about to gather is) the repaint message as follows:

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg == 0x00f) {
         if (paint)
            base.WndProc(ref m);
         else
            m.Result = IntPtr.Zero;
    }
    else
         base.WndProc(ref m);
}

Where the boolean 'paint' is set to false just before I start highlighting and to true when I finish. But as I said, the function I make must take in a RichTextBox; I cannot use a subclass.

So, is there a way to disable the automatic repainting of a RichTextBox 'from the outside?'

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

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

发布评论

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

评论(3

日裸衫吸 2024-09-17 15:22:39

这是 RichTextBox 类中的一个疏忽。其他控件(如 ListBox)支持 BeginUpdate 和 EndUpdate 方法来抑制绘制。这些方法生成 WM_SETREDRAW 消息。 RTB实际上支持这个消息,但是他们忘记添加方法了。

只需自己添加即可。项目+添加类,粘贴如下所示的代码。编译控件并将其从工具箱顶部拖放到窗体上。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class MyRichTextBox : RichTextBox {
    public void BeginUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
    }
    public void EndUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero); 
        this.Invalidate();
    }
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    private const int WM_SETREDRAW = 0x0b;
}

或者在更新文本之前/之后直接 P/Invoke SendMessage。

It is an oversight in the RichTextBox class. Other controls, like ListBox, support the BeginUpdate and EndUpdate methods to suppress painting. Those methods generate the WM_SETREDRAW message. RTB in fact supports this message, but they forgot to add the methods.

Just add them yourself. Project + Add Class, paste the code shown below. Compile and drop the control from the top of the toolbox onto your form.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class MyRichTextBox : RichTextBox {
    public void BeginUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
    }
    public void EndUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero); 
        this.Invalidate();
    }
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    private const int WM_SETREDRAW = 0x0b;
}

Or P/Invoke SendMessage directly before/after you update the text.

゛清羽墨安 2024-09-17 15:22:39

我还没有积累足够的积分来修改汉斯的建议。因此,我添加了这个Answer来提及可能需要通过调用InvalidateRect来请求重新绘制。某些开始/结束更新实现会在更新锁最终释放时自动执行此操作。类似地,在 .Net 中,可以调用 Control.Invalidate() 来调用本机 InvalidateRect 函数。

MSDN:最后,应用程序可以调用 InvalidateRect 函数来重新绘制列表框。

请参阅WM_SETREDRAW

I haven't accumulated enough points to amend Hans' recommendation. So I added this Answer to mention that it may be necessary to request a repaint by calling InvalidateRect. Some Begin/End Update implementations do this automatically upon the final release of the update lock. Similarly in .Net, Control.Invalidate() can be called which invokes the native InvalidateRect function.

MSDN: Finally, the application can call the InvalidateRect function to cause the list box to be repainted.

See WM_SETREDRAW

眼眸 2024-09-17 15:22:39

完成您想要做的事情的最佳选择是创建一个多线程应用程序。您需要创建一个线程来根据您的列表检查文本。该线程会将其找到的任何实例放入队列中。您还需要创建另一个线程来实际突出显示单词。因为您需要使用 BeginInvoke() 和 Invoke() 来更新 UI,所以您需要确保限制调用该函数的速率。我每秒不会超过 20 次。为此,您可以使用如下代码:

DateTime lastInvoke=DateTime.Now;

if ((DateTime.Now - lastInvoke).TotalMilliseconds >=42)
{
    lastInvoke=DateTime.Now;
    ...Do your highlighting here...
}

该线程将检查您的队列中是否有需要突出显示或重新突出显示的单词,并将不断检查队列中是否有任何新的更新。希望这是有道理的!

Your best bet to accomplish what you are trying to do is to create a multithreaded application. You'll want to create one thread that checks the text against your list. This thread will put any instances it finds into a queue. You'll also want to create another thread that does the actual highlighting of the words. Because you'll need to use BeginInvoke() and Invoke() to update the UI, you'll want to make sure you throttle the rate at which this gets called. I'd so no more then 20 times per second. To do this, you'd use code like this:

DateTime lastInvoke=DateTime.Now;

if ((DateTime.Now - lastInvoke).TotalMilliseconds >=42)
{
    lastInvoke=DateTime.Now;
    ...Do your highlighting here...
}

This thread will check your queue for words that need to be highlighted or re-highlighted and will constantly check the queue for any new updates. Hope this makes sense!

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