Запретить перерисовку окна в C ++ - PullRequest
7 голосов
/ 24 ноября 2010

Я пишу глобальную подключаемую DLL-библиотеку, которая должна рисовать с помощью GDI + в окне в ответ на событие. Моя проблема в том, что нарисованное окно продолжает перерисовывать себя, поэтому то, что я рисую, стирается раньше, чем я этого хочу. Есть ли какой-нибудь способ, которым я могу помешать окну что-либо рисовать столько, сколько мне нужно?

Мой хук в настоящее время является WH_CALLWNDPROC хуком. Рисование выполняется с использованием GDI + в ответ на сообщение WM_SIZING. Я рисую, используя GDI + на DC окна (т.е. GetWindowDC). То, что я рисую, рисуется правильно, но стирается почти мгновенно, когда клиентская область окна перерисовывается. Программа, которая создала окно, на котором я рисую, - это Блокнот. Когда курсор мигает, то, что я нарисовал, стирается.

Кто-нибудь знает, как я могу временно приостановить покраску окна?

Спасибо!

Ответы [ 4 ]

5 голосов
/ 24 ноября 2010

Я бы предложил поместить вашу графику в многослойное окно, перекрывающее целевое окно. Это кажется самым чистым способом. В конце концов, на определенном уровне, это цель оконного менеджера:)

3 голосов
/ 25 августа 2014

Тенфур ответил, на мой взгляд, лучший , но он / она также должен был объяснить как сделать это, а не просто сказать, что сделать, теперь I объяснит как:

ПРИМЕЧАНИЕ: Если вы хотите, чтобы основная идея была в моем решении, то вы можете перейти к последнему шагу 9, намного ниже (начать поиск с снизу вверх, пока не найдешь).

Извините, если я преувеличил свой ответ и объяснил и слишком подробно изложил, но я обещаю, что если вы будете читать правильно, вы поймете и будете удовлетворены.

Шаг 1: Создайте новую структуру WNDCLASSEX, а затем установите для ее члена cbSize размер этой структуры в байтах, используя ключевое слово sizeof, и установите lpszClassName участник того, что вы хотите. Также установите для элемента hbrBackground возвращаемое значение либо GetStockObject, чтобы получить либо черную, или белую или серую кисть , ИЛИ CreateSolidBrush функция, чтобы получить кисть любого цвета, который вы хотите. очень важно выбрать цвет, который все ваши рисунки не используют вообще !!! И не только для вашего удовольствия!

Например:

WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = "myNewClassName";
HBRUSH background_brush = GetStockObject(BLACK_BRUSH);
wcex.hbrBackground = background_brush;

Шаг 2: Определите новую функцию, которая является оконной процедурой, а затем создайте ее указатель на новую функцию. Затем установите lpfnWndProc член wcex на указатель на эту функцию.

Шаг 3: В новом определении функции процедуры окна добавьте return 0;, что является строкой кода last .

Над ним переключите параметр uMsg и, по крайней мере, добавьте регистр WM_PAINT. В этом случае определите новую переменную PAINTSTRUCT и вызовите функции BeginPaint и EndPaint. В обеих функциях вы ссылаетесь на переменную как &ps, если ps является именем переменной PAINTSTRUCT.

После , когда вы вызываете функцию BeginPaint, добавьте все нужные функции рисования в целевом окне, но убедитесь, что HDC во всех функциях рисования , а не , принадлежат к целевому окну, но к окну, у которого есть дескриптор в параметре first оконной процедуры, т.е. hWnd !!! Вызовите или GetDC или GetWindowDC, чтобы получить hDC first of all.

ПРИМЕЧАНИЕ: Вам вообще не нужно извлекать hDc целевого окна!

Не забудьте добавить следующую строку кода: default: return DefWindowProc(hWnd, uMsg, wParam, lParam); внутри блока оператора switch.

Шаг 4: Зарегистрируйте класс с помощью функции RegisterClassEx.

Например: RegisterClassEx(&wcex);

Шаг 5: В вашем приложении создайте новое многоуровневое окно с помощью функции CreateWindowEx. очень важно , чтобы вы установили параметр first этой функции на WS_EX_LAYERED, чтобы объявить, что новое окно, которое вы создаете, является слоистым.

Установите для параметра second имя нового зарегистрированного класса, например, "myNewClassName", игнорируйте параметр третий (установите его на NULL) и в четвертый параметр, установите следующие флаги: WS_POPUP | WS_VISIBLE

NOTE : WS_POPUP создаст новое окно без границы . По этой причине я проигнорировал hIcon член wcex, а также третий параметр, установленный на NULL Вместо этого вы можете заменить WS_POPUP на WS_POPUPWINDOW. Результат будет таким же, но WS_POPUPWINDOW также рисует выделенный серый прямоугольник, тонкий с толщиной всего 1 пиксель по всей клиентской области. WS_POPUP не рисует что-либо в отличие от WS_POPUPWINDOW, , просто удаляет границу, как это.

Я также установил флаг WS_VISIBLE, чтобы показать окно. Если вы не установите этот флаг, то вам придется вызвать функцию ShowWindow после CreateWindowEx, чтобы показать многоуровневое окно.

Шаг 6: Вызвать функцию SetLayeredWindowAttributes после CreateWindowEx.Установите параметр first в качестве дескриптора вновь созданного многоуровневого окна, возвращенного функцией CreateWindowEx.

Установите для параметра second цвет фона вашего окна.клиента, т.е. к цвету вашей сплошной кисти, сохраненной в переменной background_brush примера, который вы использовали для установки члена hbrBackground wcex, тип которого WNDCLASSEX.

Примечание что тип данных этого параметра COLORREF, а не HBRUSH, т.е. он не принимает сплошную кисть, а просто цвет!

Если вы знаете цветиз сплошной кисти, которую вы выбрали в функции GetStockObject, вы знаете, как создать ее структуру COLORREF.

Если вы вместо этого вызвали функцию CreateSolidBrush, то перед ее вызовом определите новую переменнуюCOLORREF структура, которая будет хранить цвет сплошной кисти и ключ в будущем.Позже вы можете использовать переменную в обеих функциях: CreateSolidBrush и SetLayeredWindowAttributes (во втором параметре, т.е. crKey).

Если вы следовали моему примеру выше, и вы только есть переменная background_brush, тип которой HBRUSH, которая хранит сплошную кисть для члена hbrBackground wcex, и у вас нет есть какой-либо правильный COLORREF для параметра crKey, тогда:

Чтобы получить цвет сплошной кисти, тип которой имеет структуру от HBRUSH до COLORREF, тогда:

Вы можете использовать функцию GetObject, чтобы получить информацию LOGBRUSH кисти,Компонент lbColor, который даст значение цвета в COLORREF.Вы можете использовать функции GetRValue, GetGValue и GetBValue для получения отдельных цветовых компонентов.

Ответ Правина кому-то, кто должен был знать, как получить COLORREF из HBRUSH как сплошную кисть.

Вот ссылка для получения дополнительной информации:

http://forums.codeguru.com/showthread.php?423605-Color-of-HBRUSH

Если вы хотите другой способ получить правильную структуру COLORREF для параметра crKey параметра SetLayeredWindowAttributes функция, затем вы можете попробовать функцию GetBkColor после того, как вы сначала получите hDc нового созданного многоуровневого окна. или вместо этого вызовите функцию SelectObject.Задайте для параметра first значение постоянного тока нового многоуровневого окна и для параметра second значение hbrBackground члена wcex или bakcground_brush в приведенном выше примере.

Тогдапросто вызовите функцию GetDCBrushColor, чтобы получить структуру COLORREF для параметра crKey функции SetLayeredWindowAttributes.

Игнорировать третий параметр (установите bAlpha в NULL), а в четвертом параметре устанавливается только флаг LWA_COLORKEY.crKey - это цвет hbrBackground, весь клиент многослойного окна не будет отрисован, за исключением других пикселей, цвет которых не равен crKey.Теперь все, что вам нужно сделать, это привязать многоуровневое окно к клиенту целевого окна.

Шаг 7: Позвонить или FindWindow или FindWindowEx функция для извлечения дескриптора целевого окна, если у вас его еще нет.

Шаг 8: Написать цикл сообщений (или выбрать и скопировать фрагменткода ниже и вставьте его в свой):

MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Шаг 9 (последний): В цикле сообщений (внутри блока while) независимо от того, где (до TranslateMessageили после DispatchMessage или между ними), напишите другой фрагмент кода, который будет каждый момент привязывать многоуровневое окно к клиенту целевого окна:

Прежде всего create newPOINT, и установите его координаты в (0; 0) (установите для его членов x и y значение 0).

Затем вызовите функцию ClientToScreen.Задайте для параметра first дескриптор целевого окна (возвращаемого функцией FindWindow или FindWindowEx), а в параметре second укажите ссылку на созданную вами структуру POINT.до этого.

После вызова функции ClientToScreen ваша структура POINT хранит координаты самого левого верхнего края целевого окна (в экранных координатах, измеренных в пиксельных единицах).

Теперь вам нужно получить размер клиента целевого окна. Для этого определим новую переменную, тип которой является структурой RECT.

Затем вызовите функцию GetClientRect. Установите для параметра first дескриптор целевого окна, а в параметре second укажите переменную, тип которой является структурой RECT.

После вызова функции GetClientRect переменная RECT хранит ширину и высоту клиента целевого окна, измеренную в пиксельных единицах. Элемент right хранит width , а элемент bottom хранит height . Игнорировать left и top члены переменной, тип которой является структурой RECT. Они не используются и не установлены, и всегда будут иметь свои значения по умолчанию, т. Е. Только 0 в этом случае.

После того, как у вас есть позиция клиента целевого окна (местоположение и размер), теперь вы можете привязать свое многоуровневое окно к клиенту целевого окна, вызвав либо MoveWindow или SetWindowPos функция, как это:

MoveWindow(hWnd, point.x, point.y, rect.right, rect.bottom, TRUE);
//If you want, you can set the last parameter to FALSE.
//OR
SetWindowPos(hWnd, hTargetWnd, point.x, point.y, rect.right, rect.bottom, NULL);
//If you want, you can specify some flags in the last parameter.
//Where hWnd is the handle of the layered window returned from CreateWindowEx function, and hTargetWnd is the handle of the target window returned from either FindWindow or FindWindowEx function.

Если вы решили использовать функцию MoveWindow, и у вас есть проблема с тем, что вы не видите свои картины в целевом окне, потому что многослойное окно на ниже целевого окна. Вместо этого вам придется изменить вызов на функцию SetWindowPos, чтобы решить эту проблему. Во втором параметре я вызвал систему, в которой я хочу разместить ограниченное многослойное окно над целевым окном. Если он по-прежнему не работает, вы можете изменить этот параметр и установить для него или HWND_TOP или HWND_TOPMOST flag.

Я уверен, что после этого все должно работать нормально. Не забывайте иногда отменять или перерисовывать или обновлять многоуровневое окно, чтобы обновить ваши рисунки в целевом окне. Вы можете вызвать или InvalidateRect или RedrawWindow или UpdateWindow, чтобы сделать это.

Например:

POINT point;
ClientToScreen(hTargetWnd, &point);

RECT rect;
GetClientRect(hTargetWnd, &rect);

MoveWindow(hWnd, point.x, point.y, rect.right, rect.bottom, TRUE);
//OR
SetWindowPos(hWnd, hTargetWnd, point.x, point.y, rect.right, rect.bottom, NULL);

InvalidateRect(hWnd, NULL, TRUE);
//If you want, you can set the third parameter to FALSE.

(Вы можете выбрать и скопировать приведенный выше пример кода, а также вставить его в свой):

Пример кода может быть в цикле сообщений, это означает, что многоуровневое окно будет связано и обновлено каждый момент , но если вы сделаете не хотите каждый момент, но каждый раз Вы делаете что-то или каждый раз, когда что-то происходит, с целевым окном, которое не принадлежит вашему приложению, например, Блокнот, тогда вам придется вызывать функцию SetWindowsHookEx. Вы можете получить дополнительную информацию об этой функции на сайте MSDN и других сайтах в Интернете.

Если вы хотите, чтобы это происходило каждый момент, но не в цикле сообщений, то вы можете сделать это в другом цикле while другого потока, но вам нужно будет создать для него функцию и вызвать функцию CreateThread. Опять же, вы также можете получить информацию об этой функции на сайте MSDN и других сайтах в Интернете

Убедитесь, что цикл while потока заканчивается, когда процесс вашего приложения или завершен или завершен.

Вы также можете попробовать либо функцию IsWindow, либо IsWindowVisible в состоянии цикла while, чтобы определить, останавливаться ли когда многоуровневое окно или / и целевое окно / 1380 * либо уничтожено или закрыто (завершено, не будет свернуто или помечено как иконка).

2 голосов
/ 24 ноября 2010

Вы можете попробовать отправить WM_SETREDRAW сообщения в окно, для wParam установлено значение FALSE для приостановки рисования, затем значение TRUE для восстановления нормального поведения.

Это довольно навязчивое решение.

2 голосов
/ 24 ноября 2010

Нет.

Вместо этого, почему бы не зацепить WM_PAINT, чтобы вы рисовали, когда они рисуют?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...