Прокрутка при отображении текстового файла в приложении MFC
У меня есть приложение 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, чтобы перерисовать только то, что требуется. Может ли кто-нибудь дать мне предложения о том, как поступить?
Благодарю.
2 ответа
Двойная буферизация здесь вам не поможет, поскольку вы по-прежнему рисуете всю строку в закадровом растровом изображении. Вы хотите нарисовать только ту часть строки, которая на самом деле отображается, что легче сказать, чем сделать.
Во-первых, если каждая строка имеет одинаковую высоту, это облегчает ее в 10 раз (я также предполагаю, что у вас нет таких забавных вещей, как встроенные изображения, форматирование, интервал между абзацами и т. Д.). В основном, что вы хотите сделать, это определить, как далеко вдоль общего количества линий находится ваша полоса прокрутки (скажем, у вас есть 1000 строк, а полоса прокрутки у вас на 50%, это означает, что вам нужно начать рисование с 500-й строки и далее) и сколько строк текста вы можете отобразить (легко рассчитать, разделив высоту элемента управления на высоту каждой строки).
Затем вы извлекаете эти строки из строки и передаете их только DrawText(). Самый простой способ сделать это - сохранить весь текст не как одну строку, а как вектор строк, по одной строке в каждой записи.
Теперь есть еще куча подробностей, которые нужно уточнить, например, что отображать, когда вы прокручиваете весь путь до конца, позволяете ли вы видеть половину строк и т. Д., Но по сути это то, к чему все сводится.
Кроме того, я надеюсь, что вы не читаете текст из файла в каждом OnDraw(), потому что это само по себе может вызвать замедление.
GetClipBox () здесь не совсем уместен, так как вы все равно захотите перерисовать весь контент вашего окна контента, даже если вы прокручиваете только 1 пиксель. Суть заключается в том, чтобы уменьшить количество элементов, которые нужно нарисовать (которые вы передаете DrawText()), а не ограничить объем экранного пространства, на которое рисуется.
Я думаю, что лучшим решением вашей проблемы, вероятно, является двойная буферизация. По сути, делайте рисование за пределами экрана, затем, когда вызывается OnPaint(), просто вызывайте
CRect rcUpdate;
GetClipBox(rcUpdate);
pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);
Который просто скопирует обновленный раздел экрана и должен значительно улучшить вашу производительность.
В предыдущем вопросе я разместил некоторый код, чтобы помочь с двойным буфером, который может помочь. Сюда также входит код GDI+, который вам на самом деле не нужен, и который можно просто пропустить.