API и FreeBasic. (замена стиля окна часть 2)

У многих приложений реализовано свойство, когда окно встает поверх всех окон. Это не всегда конечно нужно, но иногда очень полезно. Представьте себе, вы сделали себе красивые анимированные часики. И вот если ваша программа не будет иметь свойство поверх всех окон, при открытии нескольких окон, вам придется отыскивать это окошко, чтобы посмотреть время. Не знаю как вам, но мне это кажется очень неудобным.

Для того чтобы сделать окно поверх всех окон при создании окна, достаточно у функции CreateWindowEx первым параметром передать константу: WS_EX_TOPMOST

Однако часто требуется данную возможность устанавливать во время выполнения программы. На помощь придет функция "SetWindowPos" . Ее характеристики:

  • hWnd  -  хендл окна
  • hWndInsertAfter  -  константа, связанная с  порядком размещения
    • HWND_BOTTOM  -  помещает окно самым нижним в Z порядке, сразу после рабочего стола
    • HWND_NOTOPMOST  - помещает окно позади всех самых верхних окон.
    • HWND_TOP  -  помещает окно поверх всех окон.
    • HWND_TOPMOST  -  помещает окно поверх всех окон. Окно сохраняет свою самую верхнюю позицию даже тогда, когда оно теряет активность.
  • x  -  позиция по горизонтали
  • y  -  позиция по вертикали
  • cx  -  ширина
  • cy  -  высота
  • uFlags  -  флаги позиционирования окна
    • SWP_ASYNCWINDOWPOS  -  если вызывающий поток и поток, который владеет окном, подключены к разным очередям ввода данных, система посылает запрос потоку, который владеет окном. Это не допускает блокирования работы вызывающего потока, в то время пока другие потоки обрабатывают запрос.
    • SWP_DEFERERASE  -  препятствует созданию сообщения WM_SYNCPAINT.
    • SWP_DRAWFRAME  -  выводит рамку (определенную в описании класса окна) вокруг окна.
    • SWP_FRAMECHANGED  -  применяет новую установку стилей рамок, используя функцию SetWindowLong. Отправляет сообщение WM_NCCALCSIZE окну, даже тогда, когда размер окна не изменяется. Если этот флажок не установлен,  WM_NCCALCSIZE отправляется только тогда, когда размер окна изменяется.
    • SWP_HIDEWINDOW  -  скрывает окно.
    • SWP_NOACTIVATE  -  не активизирует окно. Если этот флажок не установлен, окно активизируется и перемещается в верхнюю часть или самой верхней, или не самой верхней группы (в зависимости от установки параметра hWndInsertAfter.)
    • SWP_NOCOPYBITS  -  сбрасывает все содержание рабочей области. Если этот флажок не установлен, допустимое содержание рабочей области сохраняется и копируется обратно в рабочую область после того, как окно изменило размер или переустановлено.
    • SWP_NOMOVE  -  сохраняет текущую позицию (игнорирует X и Y параметры).
    • SWP_NOOWNERZORDER  -  не изменяет позицию окна владельца в Z-последовательности.
    • SWP_NOREDRAW  -  не перерисовывает изменения. Если этот флажок установлен, то не происходит никакой перерисовки любого вида. Это применяется к рабочей области, нерабочей области (включая строку заголовка и линейки прокрутки) и любую часть родительского окна, раскрытого в результате перемещения окна. Когда этот флажок установлен, прикладная программа должна явно признать недействительной или перерисовать любые части окна и родительского окна, которые требуют перерисовки.
    • SWP_NOREPOSITION  -  то же самое, что и флажок SWP_NOOWNERZORDER.
    • SWP_NOSENDCHANGING  -  предохраняет окно от приема сообщения WM_WINDOWPOSCHANGING.
    • SWP_NOSIZE  -  сохраняет текущий размер (игнорирует cx и cy параметры).
    • SWP_NOZORDER  -  сохраняет текущую  Z-последовательность (игнорирует параметр hWndInsertAfter).
    • SWP_SHOWWINDOW  -  отображает окно на экране.

Давайте выполним задачу: сделать окно верхним даже тогда когда оно не активно и для этого мы применим флаг HWND_TOPMOST. Как вы наверно заметили, эта функция еще способна позиционировать и изменять размеры окна и для этого у нее есть соответствующие параметры. Но нам сейчас это не требуется, поэтому мы установим эти параметры в ноль. Однако в последнем параметре укажем флаги: SWP_NOMOVE и SWP_NOSIZE . Эти флаги сообщат системе, что параметры с 3 по 6 изменять не нужно (игнорировать). А теперь пример:

#INCLUDE "windows.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля

' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Select Case msg
        Case WM_DESTROY
            PostQuitMessage(0)
        Case WM_LBUTTONDOWN
            'Установка окна поверх всех окон
            SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE Or SWP_NOSIZE)
        Case WM_RBUTTONDOWN
            'Отмена установки окна поверх всех окон
            SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE Or SWP_NOSIZE)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function
' Заполнение структуры WNDCLASSEX
With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_HELP)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif
'Создание окна
CreateWindowEx(0,NameClass,"Первое окно",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,300,300,0,0,Hinst,0)

' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend



В данном примере если кликнуть по клиентской области окна левой кнопкой мыши, окно будет поверх всех окон, если правой , то окно станет с обычным свойством.

Иногда требуется сделать окно лишь временно поверх всех окон, для этого используйте флаг: HWND_TOP . Для того, чтобы окно оказалось самым нижним (но выше рабочего стола) используйте флаг: HWND_BOTTOM

Теперь давайте сделаем окно полупрозрачным. Для того, чтобы этого достичь, нужно при создании окна указать в первом параметре функции флаг WS_EX_LAYERED и дальше с помощью функции SetLayeredWindowAttributes выставить нужные аттрибуты прозрачности.

Характеристики функции SetLayeredWindowAttributes:

  • hwnd  -  дескриптор многослойного окна. Многослойное окно создается, при помощи определения флажка WS_EX_LAYERED при создании окна функцией CreateWindowEx или, при помощи установки флажка WS_EX_LAYERED через посредство функции SetWindowLong после того, как окно было создано.
  • crKey  -  указатель на значение COLORREF, которое устанавливает прозрачность окраски клавиши, которая будет использована при создании многослойного окна. Все пиксели, рисуемые окном в этом цвете, должны быть прозрачными. Чтобы создать COLORREF, используйте макрокоманду  RGB.
  • bAlpha  -  Alpha-значение используется для описания непрозрачность многослойного окна. Подобен члену SourceConstantAlpha структуры BLENDFUNCTION. Когда bAlpha - 0, окно полностью прозрачно. Когда bAlpha - 255, окно непрозрачно.
  • dwFlags  -  устанавливает предпринимаемое действие. Этот параметр может быть одно или несколько нижеследующих значений
    • LWA_COLORKEY  -  использовать параметр crKey как цвет прозрачности.
    • LWA_ALPHA  -  используйте bAlpha, чтобы выяснить непрозрачность многослойного окна.

В нашем случае для установки полупрозрачности необходимо выбрать флаг LWA_ALPHA , а в значение bAlpha записать уровень прозрачности (от 0 до 255).

Пример:

#INCLUDE "windows.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля
Dim As HWND hwnd ' хендл нашего окна

' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Select Case msg
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function
' Заполнение структуры WNDCLASSEX
With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_HELP)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif
'Создание окна
hwnd=CreateWindowEx(WS_EX_LAYERED,NameClass,"Первое окно",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,300,300,0,0,Hinst,0)
'устанавливаем прозрачность
SetLayeredWindowAttributes(hwnd, 0, 130, LWA_ALPHA)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend



Если вам нужно сделать прозрачным определенный цвет окна (например сделать прозрачной клиентскую часть), то для этого нужно попросту выкрасить окно в любой цвет и передать функции SetLayeredWindowAttributes во втором параметре значение этого цвета. В итоге она пиксели данного цвета превратит в прозрачные. Конечно же в четвертом параметре функции уже надо переадть флаг LWA_COLORKEY

Пример:

#INCLUDE "windows.bi"

Dim msg As MSG 'структурированная переменная MSG
Dim hwnd As HWND  'хендл окна
Dim hbr As  HBRUSH 'кисть

' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger, wparam As WPARAM, lparam As LPARAM) As Integer
    Select Case msg
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function

'Создание окна
hwnd=CreateWindowEx(WS_EX_LAYERED,"#32770","Первое окно",WS_VISIBLE Or WS_OVERLAPPEDWINDOW, _
100,100,300,300,0,0,0,0)

'Заменяем процедуру на свою
SetWindowLong(hwnd,GWL_WNDPROC,Cast(Long,@wndproc))

'Создаем кисть синего цвета
hbr=CreateSolidBrush(&hff0000)

'Меняем цвет окна
SetClassLong(hwnd,GCL_HBRBACKGROUND,Cast(Long,hbr))
'Перерисовываем окно
InvalidateRect (hwnd,NULL,TRUE)
' делаем клиентскую часть прозрачной
SetLayeredWindowAttributes(hwnd, &hff0000, 0, LWA_COLORKEY)

'Обработка сообщений в цикле
While GetMessage(@msg,0,0,0)
    DispatchMessage(@msg)
Wend
'удаляем кисть
DeleteObject(hbr)

Пожалуй это все для данной статьи. Всего доброго!

содержание | назад | вперед