为啥将文本添加到 RichEdit 窗口会冻结它?

Posted

技术标签:

【中文标题】为啥将文本添加到 RichEdit 窗口会冻结它?【英文标题】:why adding text to RichEdit window freezes it?为什么将文本添加到 RichEdit 窗口会冻结它? 【发布时间】:2013-01-24 21:35:02 【问题描述】:

在我用鼠标触摸richedit 窗口之前,它的内容是实时更新的,但是将鼠标悬停在它上面会将箭头变成沙漏光标。然后,该窗口不会对随后通过标题栏移动它的三到四次尝试做出反应。当它最终对鼠标拖动做出反应时,它移动正常但停止刷新其内容并且标题栏变为空。类似的效果是当我尝试单击窗口的客户区时。这一次点击几下后没有反应窗口也停止更新并且它的标题栏变成(没有响应)

当循环最终停止时,程序返回窗口更新并“活着”返回。在更新客户区时如何操作窗口(并看到它正在更新内容)?

#include <windows.h>
#include <sstream>

int main() 
  using namespace std;
  LoadLibrary("Msftedit.dll");
  HWND richeditWindow = CreateWindowExW (
    WS_EX_TOPMOST,
    L"RICHEDIT50W", 
    L"window text",
    WS_SYSMENU | WS_VSCROLL | ES_MULTILINE | ES_NOHIDESEL | WS_VISIBLE,
    50, 50, 500, 500,
    NULL, NULL, NULL, NULL
  );

  for (int i = 0 ; i<100000; i++) 
    wstringstream wss;
    wss << i << L", ";
    SendMessageW(richeditWindow, EM_REPLACESEL, FALSE, (LPARAM) wss.str().c_str());
  

  MSG msg;
  while( GetMessageW( &msg, richeditWindow, 0, 0 ) ) 
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
  

【问题讨论】:

【参考方案1】:

您正在一个紧密的循环中填充丰富的编辑窗口,而不是为您的消息队列提供服务。除非您的进程定期处理其消息队列,否则系统会认为您的应用程序已停止响应。好吧,它已经停止响应了!

为了让您的应用程序保持响应,您必须抽取消息队列。我真的不知道您的实际程序正在尝试做什么。如果您想将该文本放入丰富的编辑中,您可以使用单个 EM_REPLACESEL 消息来实现。

如果您确实有一个长时间运行的任务,那么它属于不同的线程。然后你必须处理同步回 GUI 线程。如果您所做的只是调用 SendMessage,那么系统会负责同步。

底线是必须及时抽出您的消息队列。

【讨论】:

【参考方案2】:

找到答案这是我修改后的代码,看看PeekMessageWDispatchMessageW

#include <windows.h>
#include <iostream>
#include <sstream>

int main() 
  using namespace std;
  LoadLibrary("Msftedit.dll");
  HWND richeditWindow = CreateWindowExW (
    WS_EX_TOPMOST,
    L"RICHEDIT50W", 
    L"window text",
    WS_SYSMENU | WS_VSCROLL | ES_MULTILINE | ES_NOHIDESEL | WS_VISIBLE,
    50, 50, 500, 500,
    NULL, NULL, NULL, NULL
  );

  MSG msg;
  for (int i = 0 ; i<100000; i++) 
    wstringstream wss;
    wss << i << L", ";
    SendMessageW(richeditWindow, EM_REPLACESEL, FALSE, (LPARAM) wss.str().c_str());
    if (PeekMessageW(&msg, richeditWindow, 0, 0, PM_REMOVE)) 
      TranslateMessage(&msg);
      DispatchMessageW(&msg);
    
  

  while( GetMessageW( &msg, richeditWindow, 0, 0 ) ) 
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
  

【讨论】:

那个代码全错了。您需要检查 PeekMessage 的返回值。那里可能没有消息。如果那里有任何东西,你真的应该清空队列。否则,您将按下键,然后添加更多文本,然后按下键,依此类推。那会好吗?您应该调用翻译消息。但是,您为什么不一口气添加所有文本呢?更重要的是,像这样乱七八糟的队列是混乱和糟糕的形式。在不同的线程中运行循环。另外,如果用户开始打字怎么办。现在他们的文字和你的混在一起了。 是的,我知道代码看起来不专业,但它确实有效,我并不那么着迷于幕后发生的事情,让计算机感受到痛苦,计算机是为人类而不是其他绕路。无论如何,这只是一个例子。 没有任何改进可以解决这个问题。我很难知道我的答案有什么问题。 我已将 PeekMessage 放入 if 语句中。更好的 ?效果一样。 您仍然需要清空队列。一次发送一条消息是不好的。不管怎样,我已经告诉你了。你明白我的回答了吗?

以上是关于为啥将文本添加到 RichEdit 窗口会冻结它?的主要内容,如果未能解决你的问题,请参考以下文章

将数据加载到数据网格时 C#/WPF 主窗口冻结

将光标定位在 RichEdit 控件中文本的末尾

Richedit更改选择的颜色

Eclipse 在建议弹出窗口中冻结

RichEdit 忽略了不间断的空间

RichEdit 垂直文本对齐