- Offizieller Beitrag
Als erstes mag man sich natürlich fragen, wozu man einen Button mit der UDF erstellen sollte. In 99% aller Fälle ist das nicht notwendig und somit sei auch davon abzuraten.
Aber es gibt halt den Fall, dass man z.B. auf einer Rebar einen Button platzieren möchte. Das geht ausschließlich über die Button-UDF (ebenso wie alle Buttontypen wie Radio/Checkbox, Edit und Combo). Das in der Hilfe angeführte Bsp. zur Rebar ist definitiv falsch. Holt man sich, wie dort gezeigt, die Handle von nativ erstellten Ctrl um diese im Rebar einzubetten, werden sie zwar angezeigt, tummeln sich aber alle nach HIDE/SHOW od. MIN/MAX an der Pos. 0,0 übereinander.
Mit den per UDF erstellten Ctrl funktioniert alles wie gewollt.
Aber:
Wie sieht es aus mit Einfärben eines Button? Einfach ID rausfischen mit _WinAPI_GetDlgCtrlID() und auf diese native Colorfunktionen anwenden führt zu nichts.
Hier mal ein Bsp. wie sich das Lösen läßt. Der Style $BS_OWNERDRAW ist dafür erforderlich. Das führt aber auch dazu, dass der Button sich nicht mehr "normal" verhält. Das optische Anklicken habe ich im Bsp. simuliert, kann aber leider auf einer Rebar nicht verwendet werden.
Um ein 3-Dimensionales Aussehen zu erzeugen muss man den linken und oberen Rand hell, den rechten und unteren Rand dunkel färben. Alle wichtigen Details sind im Code kommentiert.
Spoiler anzeigen
#include <ButtonConstants.au3>
#include <FontConstants.au3>
#include <GuiButton.au3>
#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars', 1)
OnAutoItExitRegister('_OnExit')
Global Const $ODA_DRAWENTIRE = 1
Global Const $ODT_BUTTON = 4
Global $hBrush, $hFont, $Gui, $hBtn1, $hBtn2, $bt1, $bt2
Global $sFont = 'Comic Sans MS', $iHeight = 16, $iWidth = 7, $iWeight = $FW_MEDIUM;$FW_SEMIBOLD;$FW_NORMAL
$Gui = GUICreate("Test")
GUISetBkColor(0xD3DAED)
$hBtn1 = _GUICtrlButton_Create($Gui, 'Button-1', 20, 20, 70, 22, BitOR($BS_OWNERDRAW,$BS_NOTIFY))
$hBtn2 = _GUICtrlButton_Create($Gui, 'Button-2', 20, 50, 70, 22, BitOR($BS_OWNERDRAW,$BS_NOTIFY))
Global $aBtnInfo[3][6] = [[2], _ ; == [0][0]=Anzahl, [[Handle-Button, Button-BG-Color, Button-Text-Color(-1=schwarz), Top/Left-Border-Color, Right/Bottom-Border-Color, ArrayPos(rel. in Client)]]
[$hBtn1, 0x00FFFF, 0xFF0000, 0xFAF5F2, 0xC0C0C0, ControlGetPos($Gui, '', _WinAPI_GetDlgCtrlID($hBtn1))], _
[$hBtn2, 0xFF00FF, -1, 0xFAF5F2, 0xC0C0C0, ControlGetPos($Gui, '', _WinAPI_GetDlgCtrlID($hBtn2))]]
; == Man kann das Array auch noch erweitern um Font-Informationen einzeln zu jedem Button zu speichern
$bt1 = GUICtrlCreateDummy()
$bt2 = GUICtrlCreateDummy()
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")
_WinAPI_RedrawWindow($Gui)
GUISetState(@SW_SHOW, $Gui)
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While True
Switch GUIGetMsg()
Case -3
Exit
Case $GUI_EVENT_PRIMARYDOWN ; == DOWN- und UP dienen nur zur optischen Darstellung des Buttonklicks
_Event_PrimaryDownUp(1)
Case $GUI_EVENT_PRIMARYUP
_Event_PrimaryDownUp(0)
Case $bt1
ConsoleWrite('Button-1' & @LF)
Case $bt2
ConsoleWrite('Button-2' & @LF)
EndSwitch
WEnd
Func _OnExit()
_WinAPI_DeleteObject($hBrush)
_WinAPI_DeleteObject($hFont)
EndFunc
; == Man könnte sich die Dummy-Ctrls sparen und hier in der "WM_COMMAND"-Func die Befehle der Button ausführen.
; == Davon ist aber abzuraten! Die Msg-Routinen sollten schnellstmöglich verlassen werden, deshalb besser ein Dummy befeuern
; == und dieses Event in der Standard-Msg-Auswertung abarbeiten.
Func WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
#forceref $hWnd, $Msg
If BitShift($wParam, 16) <> $BN_CLICKED Then Return $GUI_RUNDEFMSG ; == nur Click soll ausgewertet werden
Local $ID
Switch $lParam ; == Button-Handle auswerten
Case $hBtn1
$ID = $bt1 ; == Dummy-ID zuweisen
Case $hBtn2
$ID = $bt2
EndSwitch
; == Nachricht an gewählte Dummy-ID absetzen
DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $Gui, "uint", 273, "wparam", $ID, "lparam", 0)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_COMMAND
Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
Local $DRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _
"hwnd hItm;hwnd hDC;dword itmRect[4];dword itmData", $lParam)
If DllStructGetData($DRAWITEMSTRUCT, "cType") <> $ODT_BUTTON Then Return $GUI_RUNDEFMSG ; == nur OWNERDRAW-Button
If DllStructGetData($DRAWITEMSTRUCT, "itmAction") <> $ODA_DRAWENTIRE Then Return $GUI_RUNDEFMSG ; == nur Neuzeichnen-Event
Local $hDC = DllStructGetData($DRAWITEMSTRUCT, "hDC")
Local $hItm = DllStructGetData($DRAWITEMSTRUCT, "hItm")
Local $sText = _GUICtrlButton_GetText($hItm) ; == Text des zu zeichnenden Button abfragen
Local $iColBG, $iColTxt, $iColBorderLT, $iColBorderRB, $iIndex ; == Variablen für Buttonfarben u. Index im Array
_GetBtnColor($hItm, $iColBG, $iColTxt, $iColBorderLT, $iColBorderRB, $iIndex) ; == Farben für diesen Button aus Array abfragen
Local $tRECT = DllStructCreate('int;int;int;int;', DllStructGetPtr($DRAWITEMSTRUCT, "itmRect")) ; == Rect des Button
_WinAPI_SetBkMode($hDC, $TRANSPARENT)
$hBrush = _WinAPI_CreateSolidBrush($iColBG)
Local $hBrushOld = _WinAPI_SelectObject($hDC, $hBrush)
_WinAPI_FillRect($hDC, DllStructGetPtr($DRAWITEMSTRUCT, "itmRect"), $hBrush) ; == Button-Hintergrundfarbe zeichnen
Local $iColOld = _WinAPI_SetTextColor($hDC, $iColTxt) ; == Textfarbe anwählen
; == Infos für Font könnten auch einzeln für jeden Button im Array hinterlegt werden
Local $nHeight = $iHeight, $nWidth = $iWidth, $nEscape = 0, $nOrientn = 0, $fnWeight = $iWeight, $bItalic = False, $bUnderline = False
Local $bStrikeout = False, $nCharset = $DEFAULT_CHARSET, $nOutputPrec = $OUT_DEFAULT_PRECIS, $nClipPrec = $CLIP_DEFAULT_PRECIS
Local $nQuality = $DEFAULT_QUALITY, $nPitch = 0, $szFace = $sFont
$hFont = _WinAPI_CreateFont($nHeight, $nWidth, $nEscape, $nOrientn, $fnWeight, $bItalic, $bUnderline, _
$bStrikeout, $nCharset, $nOutputPrec, $nClipPrec, $nQuality, $nPitch, $szFace)
Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)
_WinAPI_DrawText($hDC, $sText, $tRECT, BitOR($DT_CENTER,$DT_VCENTER,$DT_SINGLELINE)) ; == Button-Text schreiben
_WinAPI_SetTextColor($hDC, $iColOld) ; == Textfarbe zurücksetzen
_WinAPI_DrawButtonRect($hDC, $tRECT, $iColBorderLT, $iColBorderRB, 1) ; == Button-Ränder zeichnen (Left u. Top hell / Right u. Bottom dunkel)
_WinAPI_SelectObject($hDC, $hBrushOld)
_WinAPI_SelectObject($hDC, $hOldFont)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_DRAWITEM
Func _Event_PrimaryDownUp($_iDown)
Local $oldMode = Opt('MouseCoordMode', 2), $aSize[4], $aMouse = MouseGetPos()
Local $hWndBtn = _GetBtnHwndFromMouse($aMouse[0], $aMouse[1], $aSize)
Opt('MouseCoordMode', $oldMode)
If $hWndBtn = 0 Then Return
Switch $_iDown
Case 0
ControlMove($Gui, '', _WinAPI_GetDlgCtrlID($hWndBtn), $aSize[0]-1, $aSize[1]-1)
Case 1
ControlMove($Gui, '', _WinAPI_GetDlgCtrlID($hWndBtn), $aSize[0]+1, $aSize[1]+1)
EndSwitch
EndFunc ;==>_Event_PrimaryDownUp
Func _GetBtnColor($_hWnd, ByRef $_iColBG, ByRef $_iColTxt, ByRef $_iColBorderLT, ByRef $_iColBorderRB, ByRef $_iIndex)
For $i = 1 To $aBtnInfo[0][0]
If $aBtnInfo[$i][0] = $_hWnd Then
$_iColBG = $aBtnInfo[$i][1]
$_iColTxt = $aBtnInfo[$i][2]
If $aBtnInfo[$i][2] = -1 Then $aBtnInfo[$i][2] = 0x000000
$_iColBorderLT = $aBtnInfo[$i][3]
$_iColBorderRB = $aBtnInfo[$i][4]
$_iIndex = $aBtnInfo[$i][5]
Return
EndIf
Next
EndFunc ;==>_GetBtnColor
Func _GetBtnHwndFromMouse($_iX, $_iY, ByRef $_aSize)
Local $aCtrl
For $i = 1 To $aBtnInfo[0][0]
$aCtrl = $aBtnInfo[$i][5]
If ($aCtrl[0] <= $_iX And $_iX <= $aCtrl[2]+$aCtrl[0]) And ($aCtrl[1] <= $_iY And $_iY <= $aCtrl[3]+$aCtrl[1]) Then
$_aSize = $aCtrl
Return $aBtnInfo[$i][0]
EndIf
Next
Return 0
EndFunc ;==>_GetBtnHwndFromMouse
Func _WinAPI_DrawButtonRect(ByRef $_hDC, $_tpRECT, $_iPenColorLT, $_iPenColorRB, $_iPenSize=1)
Local $tRECT
If IsDllStruct($_tpRECT) Then
$tRECT = $_tpRECT
ElseIf IsPtr($_tpRECT) Then
$tRECT = DllStructCreate('int;int;int;int;', $_tpRECT)
EndIf
Local $hPenLT = _WinAPI_CreatePen($PS_SOLID, $_iPenSize, $_iPenColorLT)
Local $hPenRB = _WinAPI_CreatePen($PS_SOLID, $_iPenSize, $_iPenColorRB)
Local $left = DllStructGetData($tRECT, 1), $top = DllStructGetData($tRECT, 2), $right = DllStructGetData($tRECT, 3), $bottom = DllStructGetData($tRECT, 4)
_WinAPI_SelectObject($_hDC, $hPenLT)
_WinAPI_DrawLine($_hDC, $left, $top, $left, $bottom-$_iPenSize) ; == Left
_WinAPI_DrawLine($_hDC, $left, $top, $right, $top) ; == Top
_WinAPI_SelectObject($_hDC, $hPenRB)
_WinAPI_DrawLine($_hDC, $right-$_iPenSize, $top, $right-$_iPenSize, $bottom-$_iPenSize) ; == Right
_WinAPI_DrawLine($_hDC, $left, $bottom-$_iPenSize, $right-$_iPenSize, $bottom-$_iPenSize) ; == Bottom
_WinAPI_DeleteObject($hPenLT)
_WinAPI_DeleteObject($hPenRB)
EndFunc ;==>_WinAPI_DrawButtonRect