【问题标题】:Scrolling while displaying a text file in an mfc application在 mfc 应用程序中显示文本文件时滚动
【发布时间】:2012-07-04 05:46:10
【问题描述】:

我有一个 mfc 应用程序,我必须在其中显示文本。每当我使用滚动条时,都会调用 OnDraw() 函数。这是我的 OnDraw() 函数:

CString fileText = pDoc->GetFileText();   //get text from file
CRect rect;
GetClientRect(&rect);

pDC->DrawText(fileText.GetString(), &rect, DT_LEFT|DT_NOCLIP);

这似乎效率低下,因为滚动需要很长时间。问题是我正在重新绘制整个文本文件。我想使用 GetClipBox 函数仅重绘所需的内容。谁能给我建议如何进行?

谢谢。

【问题讨论】:

    标签: mfc cview


    【解决方案1】:

    双缓冲在这里对您没有帮助,因为您仍在将整个字符串绘制到屏幕外位图。您想要的是只绘制实际显示的字符串部分,这说起来容易做起来难。

    首先,如果每行都具有相同的高度,这会使它变得容易 10 倍(我还假设您没有有趣的东西,例如内嵌图像、格式、段落间距等)。基本上你想要做的是推导出滚动条的总行数(假设你有 1000 行,滚动条为 50%,这意味着你需要从第 500 行开始绘制)和您可以显示多少行文本(通过将控件的高度除以每行的高度很容易计算)。

    然后,从字符串中提取这些行,然后只将它们传递给 DrawText()。最简单的方法是不将全部文本存储为一个字符串,而是存储为一个字符串向量,每个条目一行。

    现在还有很多细节需要解决,比如当你一直滚动到最后时要显示什么,你是否允许看到半行等等,但基本上以上就是它归结为的内容到。

    此外,我希望您不要在每个 OnDraw() 上从文件中读取文本,因为仅此一项可能会导致速度变慢。

    GetClipBox() 在这里并不真正相关,因为您无论如何都想重绘内容窗口的全部内容,即使您只滚动 1 个像素。关键是要减少要绘制的东西(传递给 DrawText())的数量,而不是限制要绘制到的屏幕空间量。

    【讨论】:

    • 当您重绘整个字符串时,我同意如果您要绘制整个字符串,双缓冲仍然会很慢。但是,只是为了滚动,您根本不需要重绘字符串 - 只需将您的内存位图 BitBlt 到屏幕上,这应该很快。不过我同意你的看法——为了加快完整的重绘速度,你需要将文本分成几部分并确定你需要绘制哪些部分。这很棘手。
    • 好吧,我想前进的方向是把文本分成几行,只画相关的。就像你说的,这会很棘手。另外,谢谢你的回答。
    【解决方案2】:

    我认为解决您的问题的最佳方法可能是双缓冲。基本上,对屏幕外位图进行绘画,然后在调用 OnPaint() 时,只需调用

    CRect rcUpdate;
    GetClipBox(rcUpdate);
    pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
                            m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);
    

    这只会复制屏幕的更新部分,应该会大大提高你的表现。

    我在上一个问题here 中发布了一些代码来帮助处理双缓冲区,这可能会有所帮助。这还包括您实际上不需要的 GDI+ 代码,可以省略。

    【讨论】:

    • 感谢您的回答。尝试了双缓冲。遵循指示here。它不起作用。事实上,情况更糟。我正在处理每个大约 10mb 的文本文件。 GetClipBox() 似乎是唯一的方法(我知道)。但是,我不知道该怎么做。
    • 我很惊讶双缓冲变慢了——我只能假设某处的实现存在问题。但是,渲染这么大的文本文件可能需要不同的方法。您可能是对的,您需要使用 GetClipBox()。然后,您需要以某种方式确定该 CRect 需要重绘哪些文本,并且只将该部分绘制到屏幕而不是整个文档。我认为您需要将该字符串分解为子字符串并维护一个 CRect 列表,它们被吸引到其中来解决这个问题,但其他人可能会提出更好的方法。
    • 另外,当我尝试按照您提到的链接中的代码进行操作时,我遇到了图形错误。 VS2010 说它是一个未知的标识符。这是为什么呢?
    • 您不需要图形部件 - 仅适用于 GDI+ 部件。要绕过它,您需要“使用命名空间 Gdiplus”,并且还记得在启动应用程序时初始化 GDI+。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多