Что нового

WS_EX_LAYERED со стандартными элементами

FlatX007

Tattoo!
Сообщения
197
Репутация
35
Тема перенесена отсюда.

Как у окна калькулятора получаются закруглённые края и тень под окном ?

Я пробовал через _WinAPI_CreateRoundRectRgn ... фигня получается :-X
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
FlatX007 сказал(а):
Как у окна калькулятора получаются закруглённые края и тень под окном?

Дело в том, что если ты хочешь использовать скиновое GUI (WS_EX_LAYERED), то лучше бы сразу позабыть про все стандартные элементы (GUICtrlCreate...) и реализовывать все на уровне скина. Поясняю, создаешь подложку (PNG c звкругленными краями, тенями и т.д.), это будет основное окно. Затем ляпаешь на эту подложку все, для чего сможешь реализовать необходимое поведение, например у кнопки может быть 3 состояния (standby, over и hold), у checkbox'а немного больше. Таким образом придется запрограммировать все элементы (группы элементов). При изменении состояния любого элемента (например мышь наведена на кнопку) перерисовываешь полностью GUI (создаешь HBITMAP) и вызываешь _WinAPI_UpdateLayeredWindowEx(). В принципе делаешь все тоже самое, что и Windows со стандартными элементами, но только самостоятельно. Да, задачка не самая простая, но...



Добавлено:
Сообщение автоматически объединено:

Кстати, вот один из способов совместить WS_EX_LAYERED с "нормальными" элементами (не забудь скачать bg_440x440.png).

Код:
#Include <GDIPlus.au3>
#Include <GUIConstantsEx.au3>
#Include <WinAPIEx.au3>
#Include <WindowsConstants.au3>

_GDIPlus_Startup()

$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\bg_440x440.png')
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)

$hForm = GUICreate('', 440, 440, 200, 200, $WS_POPUPWINDOW, $WS_EX_LAYERED)
_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, 127)
$hPopup = GUICreate('', 380, 380, 200 + 30, 200 + 30, $WS_POPUP, $WS_EX_LAYERED, $hForm)
GUISetBkColor(0xABABAB)
$Edit = GUICtrlCreateEdit('', 20, 20, 340, 250)
$Slider = GUICtrlCreateSlider(20, 286, 340, 32)
GUICtrlSetLimit(-1, 100, 0)
GUICtrlSetData(-1, 50)
$Button = GUICtrlCreateButton('OK', 155, 344, 70, 23)
_WinAPI_SetLayeredWindowAttributes($hPopup, 0xABABAB, 0, $LWA_COLORKEY)

GUIRegisterMsg($WM_MOVE, 'WM_MOVE')
GUIRegisterMsg($WM_NCHITTEST, 'WM_NCHITTEST')

GUISetState(@SW_SHOW, $hForm)
GUISetState(@SW_SHOW, $hPopup)

While 1
	$Msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE, $Button
			ExitLoop
		Case $Slider
			_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, 255 / 100 * GUICtrlRead($Slider))
	EndSwitch
WEnd

_GDIPlus_Shutdown()

Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
	Switch $hWnd
		Case $hForm
			WinMove($hPopup, '', BitAND($lParam, 0xFFFF) + 30, BitShift($lParam, 16) + 30)
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

Func WM_NCHITTEST($hWnd, $iMsg, $iwParam, $ilParam)
	Switch $hWnd
		Case $hForm
			Switch $iMsg
				Case $WM_NCHITTEST
					Return $HTCAPTION
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NCHITTEST
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Тема перенесена.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
FlatX007
Закругленные края у окна еще так можно сделать:
Код:
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
$my_gui = GUICreate("MyGUI", 300, 200, -1, -1, $WS_POPUP)
_GuiRoundCorners($my_gui, 0, 0, 30, 30)
GUISetBkColor(0x85BBDD)
GUIRegisterMsg($WM_NCHITTEST, 'WM_NCHITTEST')
$Button1 = GUICtrlCreateButton("Выход", 20, 100, 80, 20)
GUISetState()
While 1
	$msg = GUIGetMsg()
	Switch $msg
		Case $GUI_EVENT_CLOSE
			ExitLoop
		Case $Button1
			ExitLoop
	EndSwitch

WEnd
Exit

Func _GuiRoundCorners($h_win, $i_x1, $i_y1, $i_x3, $i_y3)
	Dim $pos, $ret, $ret2
	$pos = WinGetPos($h_win)
	$ret = DllCall("gdi32.dll", "long", "CreateRoundRectRgn", "long", $i_x1, "long", $i_y1, "long", $pos[2], "long", $pos[3], "long", $i_x3, "long", $i_y3)
	If $ret[0] Then
		$ret2 = DllCall("user32.dll", "long", "SetWindowRgn", "hwnd", $h_win, "long", $ret[0], "int", 1)
		If $ret2[0] Then
			Return 1
		Else
			Return 0
		EndIf
	Else
		Return 0
	EndIf
EndFunc   ;==>_GuiRoundCorners

Func WM_NCHITTEST($hWnd, $msg, $wParam, $lParam)
	Local $iProc = DllCall('user32.dll', 'int', 'DefWindowProc', 'hwnd', $hWnd, 'int', _
			$msg, 'wparam', $wParam, 'lparam', $lParam)
	If $iProc[0] = $HTCLIENT Then Return $HTCAPTION
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NCHITTEST
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Ну так он же написал "...фигня получается".

;)
 

SECTOR

Продвинутый
Сообщения
399
Репутация
59
Yashied
Класный пример! Но можно как нибудь сделать, чтоб
картика фона подгонялась под размер окна?
А то если картинка меньше или больше размеров окна,
получается не корректно. :smile:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Что значит подгонялась? Ты сам рисуешь скин и определяешься с размерами. Это просто пример.
 

SECTOR

Продвинутый
Сообщения
399
Репутация
59
Yashied сказал(а):
Что значит подгонялась? Ты сам рисуешь скин и определяешься с размерами. Это просто пример.
Ну допустим у меня много окон разного размера и я хочу чтоб к ним применялся один и тот же скин(?)
:smile:
Просто не силён в GDI+ и WinAPI
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Это делается очень просто с помощью _GDIPlus_ImageGetThumbnail() из этой библиотеки.

Код:
#Include <GDIP.au3>

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\bg_440x440.png')
$hThumb = _GDIPlus_ImageGetThumbnail($hImage, $Width, $Height)
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hThumb)
_GDIPlus_ImageDispose($hThumb)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
...
 
Автор
F

FlatX007

Tattoo!
Сообщения
197
Репутация
35
madmasles - Yashied, отличные примеры спасибо. :-[
 

SECTOR

Продвинутый
Сообщения
399
Репутация
59
Вот тщательно изучил пример, вроде получается. Но не как не могу добавить анимацию появления и исчезания такого окна. Подскажите пожалуйста, как такое осуществить?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
SECTOR
Анимация окон GUI, с помощью WinApi
Использование:
DllCall("User32.dll","long","AnimateWindow","hwnd",Идентификатор окна,"long",Продолжительность в миллисекундах,"long",Эффект)
Эффекты:
Эффекты имеет смысл задавать в качестве констант: Const $AW_ACTIVATE = 0x20000
AW_ACTIVATE = 0x20000 (Активирует окно, конфликтует с AW_HIDE)
AW_BLEND = 0x80000 (Постепенное исчезновение-появление)
AW_CENTER = 0x10 (Разворачивает окно из центра)
AW_HOR_POSITIVE = 0x1 (Слева направо)
AW_HOR_NEGATIVE = 0x2 (Справа налево)
AW_SLIDE = 0x40000 (Прокрутка)
AW_VER_POSITIVE = 0x4 (Сверху в низ)
AW_VER_NEGATIVE = 0x8 (Снизу в верх)
AW_HIDE = 0x10000 (Скрывает окно)
Эффекты по умолчанию ориентированны на появление окна, для скрытия окна используйте их совместно с AW_HIDE.
Можно получить интересные результаты комбинируя эффекты между собой. Например: 0x4 + 0x1 (анимация по диагонали)
Код:
#include <Guiconstants.au3>

Opt("GUIOnEventMode", 1)

$test = GUICreate("WinApi_test", 400, 300)
GUISetOnEvent($GUI_EVENT_CLOSE, "ExitGui")
DllCall("User32.dll", "long", "AnimateWindow", "hwnd", $test, "long", 700, "long", 0x8 + 0x40000)
GUISetState()

While 1
	Sleep(100)
WEnd

Func ExitGui()
	DllCall("User32.dll", "long", "AnimateWindow", "hwnd", $test, "long", 500, "long", 0x10 + 0x10000)
	Exit
EndFunc   ;==>ExitGui

PS
Это не мое, это с Ru-board.
 

SECTOR

Продвинутый
Сообщения
399
Репутация
59
madmasles
Я так пробовал, не выходит, если использовать этот метод то картинка пропадает...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
SECTOR сказал(а):
Вот тщательно изучил пример, вроде получается. Но не как не могу добавить анимацию появления и исчезания такого окна. Подскажите пожалуйста, как такое осуществить?

Код:
#Include <GDIPlus.au3>
#Include <GUIConstantsEx.au3>
#Include <WinAPIEx.au3>
#Include <WindowsConstants.au3>

_GDIPlus_Startup()

$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\bg_440x440.png')
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)

$hForm = GUICreate('', 440, 440, 200, 200, $WS_POPUPWINDOW, $WS_EX_LAYERED)
_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, 0)
$hPopup = GUICreate('', 380, 380, 200 + 30, 200 + 30, $WS_POPUP, $WS_EX_LAYERED, $hForm)
GUISetBkColor(0xABABAB)
$Edit = GUICtrlCreateEdit('', 20, 20, 340, 250)
$Button = GUICtrlCreateButton('Exit', 155, 344, 70, 23)
_WinAPI_SetLayeredWindowAttributes($hPopup, 0xABABAB, 0, BitOR($LWA_ALPHA, $LWA_COLORKEY))

GUIRegisterMsg($WM_MOVE, 'WM_MOVE')
GUIRegisterMsg($WM_NCHITTEST, 'WM_NCHITTEST')

GUISetState(@SW_SHOW, $hForm)
GUISetState(@SW_SHOW, $hPopup)

For $i = 5 To 255 Step 10
	_WinAPI_SetLayeredWindowAttributes($hPopup, 0xABABAB, $i, BitOR($LWA_ALPHA, $LWA_COLORKEY))
	_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
Next

While 1
    $Msg = GUIGetMsg()
    Switch $Msg
		Case $GUI_EVENT_CLOSE, $Button
			For $i = 255 To 5 Step -10
				_WinAPI_SetLayeredWindowAttributes($hPopup, 0xABABAB, $i, BitOR($LWA_ALPHA, $LWA_COLORKEY))
				_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
			Next
            ExitLoop
    EndSwitch
WEnd

_GDIPlus_Shutdown()

Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
	$X = BitAND($lParam, 0xFFFF)
	If $X > 0x7FFF Then
		$X -= 0x10000
	EndIf
	$Y = BitShift($lParam, 16)
	If $Y > 0x7FFF Then
		$Y -= 0x10000
	EndIf
    Switch $hWnd
		Case 0

        Case $hForm
            WinMove($hPopup, '', $X + 30, $Y + 30)
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE

Func WM_NCHITTEST($hWnd, $iMsg, $iwParam, $ilParam)
    Switch $hWnd
        Case $hForm
            Switch $iMsg
                Case $WM_NCHITTEST
                    Return $HTCAPTION
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NCHITTEST


bg_440x440.png
 
Автор
F

FlatX007

Tattoo!
Сообщения
197
Репутация
35
Кстати функцию "WM_MOVE" можно заменить на эту, я целый час промучился думал почему у меня элементы пропадают если переместить окно за пределы рабочего стола с лева.

Код:
Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam)
    Switch $hWnd
		Case $hForm
			$aWinPos = WinGetPos($hWnd)
            WinMove($hPopup, '', $aWinPos[0] + 30, $aWinPos[1] + 30)
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOVE
 
Верх