Главное, что вам нужно сделать, это отключить ваш интерфейс от вашего набора данных. Я бы сказал, что способ сделать это - поместить слой между ними.
Вам нужно будет спроектировать структуру данных, подготовленных для отображения. Скорее всего, он будет содержать копии некоторых ваших внутренних данных, но «приготовленные», чтобы их было легко извлечь. Основная идея здесь заключается в том, что это быстро и легко рисовать. Вы даже можете иметь эту структуру данных, содержащую рассчитанные позиции на экране битов данных, чтобы ее можно было быстро извлечь.
Всякий раз, когда вы получаете сообщение WM_PAINT, вы должны получить самую последнюю полную версию этой структуры и использовать ее. Если вы сделаете это правильно, вы сможете обрабатывать несколько сообщений WM_PAINT в секунду, потому что код рисования никогда не ссылается на ваши внутренние данные вообще. Это просто вращается через приготовленную структуру. Идея в том, что лучше рисовать устаревшие данные быстрее, чем вешать ваш пользовательский интерфейс.
Тем временем ...
У вас должно быть 2 полных копии этой готовой к показу структуры. Одним из них является то, на что смотрит сообщение WM_PAINT. (назовите это cfd_A ) Другое - это то, что вы передаете своей функции CookDataForDisplay (). (назовите это cfd_B ). Ваша функция CookDataForDisplay () выполняется в отдельном потоке и работает над сборкой / обновлением cfd_B в фоновом режиме. Эта функция может занять столько времени, сколько ей нужно, потому что она никак не взаимодействует с дисплеем. Как только вызов вернется, cfd_B будет самой последней версией структуры.
Теперь поменяйте местами cfd_A и cfd_B и InvalidateRect в окне вашего приложения.
Упрощенный способ сделать это состоит в том, чтобы ваша структура готовой к отображению была растровым, и это могло бы быть хорошим способом добиться успеха, но я уверен, что если немного подумать, то вы можете сделать гораздо лучшую работу с более сложной структурой.
Итак, вернемся к вашему примеру.
- В методе рисования он вызывает метод GetData, часто сотни раз для сотен бит данных в одной операции рисования
Теперь это 2 потока, метод рисования ссылается на cfd_A и выполняется в потоке пользовательского интерфейса. Тем временем cfd_B создается фоновым потоком с использованием вызовов GetData.
Быстрый и грязный способ сделать это
- Возьмите ваш текущий код WM_PAINT, вставьте его в функцию под названием PaintIntoBitmap ().
- Создайте растровое изображение и DC памяти, это cfd_B.
- Создать поток и передать его cfd_B и вызвать его PaintIntoBitmap ()
- Когда этот поток завершится, поменяйте местами cfd_B и cfd_A
Теперь ваш новый метод WM_PAINT просто берет предварительно обработанный растровый рисунок в cfd_A и выводит его на экран. Ваш пользовательский интерфейс теперь отключен от вашей внутренней функции GetData ().
Теперь настоящая работа начинается, потому что быстрый и грязный способ не очень хорошо справляется с изменением размера окна. Оттуда вы можете уточнить, каковы ваши структуры cfd_A и cfd_B, пока вы не достигнете точки, когда вы будете удовлетворены результатом.