Тенфур ответил, на мой взгляд, лучший , но он / она также должен был объяснить как сделать это, а не просто сказать, что сделать, теперь 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 * либо уничтожено или закрыто (завершено, не будет свернуто или помечено как иконка).