다른 명령
새 문서: == 플랫 버튼 스타일 == ## 1. BS_FLAT 스타일 (가장 간단) <source lang=autoit> #include <GUIConstantsEx.au3> #include <ButtonConstants.au3> $hGUI = GUICreate("Flat Button", 300, 200) GUISetBkColor(0xFFFFFF) $hBtn = GUICtrlCreateButton("클릭", 50, 50, 200, 40, $BS_FLAT) GUISetState() While GUIGetMsg() <> $GUI_EVENT_CLOSE WEnd </source> 3D 테두리가 제거되지만, 마우스 오버 시 테두리가 살아나서 완전한 플랫은 아닙니다. ## 2. Lab... |
편집 요약 없음 |
||
| 238번째 줄: | 238번째 줄: | ||
**방법 3 (GDI+ Owner-Draw)** — 가장 자유도가 높습니다. 둥근 모서리, 호버 색상 변화, 프레스 효과까지 완전히 커스텀 가능합니다. 코드량이 많지만 SQL*KEY처럼 UI를 세밀하게 제어해야 하는 프로그램에 적합합니다. | **방법 3 (GDI+ Owner-Draw)** — 가장 자유도가 높습니다. 둥근 모서리, 호버 색상 변화, 프레스 효과까지 완전히 커스텀 가능합니다. 코드량이 많지만 SQL*KEY처럼 UI를 세밀하게 제어해야 하는 프로그램에 적합합니다. | ||
=== 플랫한 버튼 스타일 예제 === | |||
<source lang=autoit> | |||
#include <GUIConstantsEx.au3> | |||
#include <WindowsConstants.au3> | |||
#include <GDIPlus.au3> | |||
#include <WinAPI.au3> | |||
; ── Tab Control 스타일 상수 ── | |||
Global Const $TCS_MULTILINE = 0x0200 | |||
Global Const $TCS_BUTTONS = 0x0100 | |||
Global Const $TCS_FLATBUTTONS = 0x0008 | |||
Global Const $TCS_OWNERDRAWFIXED = 0x2000 | |||
Global Const $ODT_TAB = 101 | |||
Global Const $ODS_SELECTED = 0x0001 | |||
; ── 색상 설정 ── | |||
Global Const $CLR_TAB_SELECTED_BG = 0x2196F3 ; 선택된 탭 배경 (파란색) | |||
Global Const $CLR_TAB_SELECTED_TEXT = 0xFFFFFF ; 선택된 탭 텍스트 (흰색) | |||
Global Const $CLR_TAB_NORMAL_BG = 0xE0E0E0 ; 일반 탭 배경 (밝은 회색) | |||
Global Const $CLR_TAB_NORMAL_TEXT = 0x333333 ; 일반 탭 텍스트 (진한 회색) | |||
Global Const $CLR_TAB_HOVER_BG = 0xBBDEFB ; 호버 탭 배경 (연한 파란색) | |||
Global Const $CLR_TAB_HOVER_TEXT = 0x1565C0 ; 호버 탭 텍스트 | |||
Global Const $CLR_GUI_BG = 0xFAFAFA ; GUI 배경 | |||
Global Const $CLR_CONTENT_BG = 0xFFFFFF ; 탭 콘텐츠 영역 배경 | |||
; ── 폰트 설정 ── | |||
Global Const $TAB_FONT_NAME = "맑은 고딕" | |||
Global Const $TAB_FONT_SIZE = 10 | |||
; ── 탭 데이터 ── | |||
Global $g_aTabNames[] = [ _ | |||
"환경설정", "단축키 관리", "실행파일", "후킹설정", _ | |||
"Direct Key", "매크로", "히스토리", "도움말" _ | |||
] | |||
Global $g_hGUI, $g_hTab | |||
Global $g_aTabItems[UBound($g_aTabNames)] | |||
Global $g_aTabLabels[UBound($g_aTabNames)] ; 탭별 콘텐츠 라벨 | |||
Global $g_iHoverTab = -1 | |||
; ── GUI 생성 ── | |||
$g_hGUI = GUICreate("SQL*KEY - Flat Tab Demo", 700, 500) | |||
GUISetBkColor($CLR_GUI_BG) | |||
GUISetFont($TAB_FONT_SIZE, 400, 0, $TAB_FONT_NAME) | |||
; ── Tab 컨트롤 생성 ── | |||
; TCS_OWNERDRAWFIXED: 직접 그리기 | |||
; TCS_BUTTONS: 버튼 스타일 | |||
; TCS_MULTILINE: 다중 행 | |||
; TCS_FLATBUTTONS: 플랫 버튼 (owner-draw와 함께 사용) | |||
$g_hTab = GUICtrlCreateTab(10, 10, 680, 480, _ | |||
BitOR($TCS_OWNERDRAWFIXED, $TCS_BUTTONS, $TCS_MULTILINE, $TCS_FLATBUTTONS)) | |||
GUICtrlSetFont($g_hTab, $TAB_FONT_SIZE, 400, 0, $TAB_FONT_NAME) | |||
; ── TabItem 생성 ── | |||
For $i = 0 To UBound($g_aTabNames) - 1 | |||
$g_aTabItems[$i] = GUICtrlCreateTabItem($g_aTabNames[$i]) | |||
; 각 탭의 콘텐츠 예시 | |||
$g_aTabLabels[$i] = GUICtrlCreateLabel( _ | |||
"[ " & $g_aTabNames[$i] & " ] 탭 콘텐츠 영역", _ | |||
30, 80, 640, 380) | |||
GUICtrlSetFont($g_aTabLabels[$i], 14, 400, 0, $TAB_FONT_NAME) | |||
GUICtrlSetColor($g_aTabLabels[$i], 0x757575) | |||
GUICtrlSetBkColor($g_aTabLabels[$i], $CLR_CONTENT_BG) | |||
Next | |||
GUICtrlCreateTabItem("") ; 탭 아이템 종료 | |||
; ── WM_DRAWITEM 등록 (탭 커스텀 그리기) ── | |||
GUIRegisterMsg($WM_DRAWITEM, "_WM_DRAWITEM") | |||
; ── WM_MOUSEMOVE 등록 (호버 효과) ── | |||
GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") | |||
GUISetState(@SW_SHOW) | |||
; ── 메인 루프 ── | |||
While 1 | |||
Switch GUIGetMsg() | |||
Case $GUI_EVENT_CLOSE | |||
Exit | |||
EndSwitch | |||
WEnd | |||
; ══════════════════════════════════════════════════════ | |||
; WM_DRAWITEM 핸들러 - 탭을 플랫 스타일로 직접 그리기 | |||
; ══════════════════════════════════════════════════════ | |||
Func _WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) | |||
; DRAWITEMSTRUCT 구조체 파싱 | |||
Local $tDRAWITEM = DllStructCreate( _ | |||
"uint CtlType;" & _ | |||
"uint CtlID;" & _ | |||
"uint itemID;" & _ | |||
"uint itemAction;" & _ | |||
"uint itemState;" & _ | |||
"hwnd hwndItem;" & _ | |||
"handle hDC;" & _ | |||
"long rcLeft;long rcTop;long rcRight;long rcBottom;" & _ | |||
"ulong_ptr itemData", _ | |||
$lParam) | |||
Local $iCtlType = DllStructGetData($tDRAWITEM, "CtlType") | |||
If $iCtlType <> $ODT_TAB Then Return $GUI_RUNDEFMSG | |||
Local $iItemID = DllStructGetData($tDRAWITEM, "itemID") | |||
Local $iState = DllStructGetData($tDRAWITEM, "itemState") | |||
Local $hDC = DllStructGetData($tDRAWITEM, "hDC") | |||
Local $iLeft = DllStructGetData($tDRAWITEM, "rcLeft") | |||
Local $iTop = DllStructGetData($tDRAWITEM, "rcTop") | |||
Local $iRight = DllStructGetData($tDRAWITEM, "rcRight") | |||
Local $iBottom = DllStructGetData($tDRAWITEM, "rcBottom") | |||
Local $bSelected = BitAND($iState, $ODS_SELECTED) | |||
; ── 색상 결정 ── | |||
Local $iBgColor, $iTextColor | |||
If $bSelected Then | |||
$iBgColor = $CLR_TAB_SELECTED_BG | |||
$iTextColor = $CLR_TAB_SELECTED_TEXT | |||
ElseIf $iItemID = $g_iHoverTab Then | |||
$iBgColor = $CLR_TAB_HOVER_BG | |||
$iTextColor = $CLR_TAB_HOVER_TEXT | |||
Else | |||
$iBgColor = $CLR_TAB_NORMAL_BG | |||
$iTextColor = $CLR_TAB_NORMAL_TEXT | |||
EndIf | |||
; ── 배경 채우기 (1px 간격으로 버튼 분리) ── | |||
Local $tRect = DllStructCreate("long Left;long Top;long Right;long Bottom") | |||
DllStructSetData($tRect, "Left", $iLeft + 1) | |||
DllStructSetData($tRect, "Top", $iTop + 1) | |||
DllStructSetData($tRect, "Right", $iRight - 1) | |||
DllStructSetData($tRect, "Bottom", $iBottom - 1) | |||
Local $hBrush = _WinAPI_CreateSolidBrush($iBgColor) | |||
_WinAPI_FillRect($hDC, $tRect, $hBrush) | |||
_WinAPI_DeleteObject($hBrush) | |||
; ── 선택된 탭 하단 액센트 라인 ── | |||
If $bSelected Then | |||
Local $tAccent = DllStructCreate("long Left;long Top;long Right;long Bottom") | |||
DllStructSetData($tAccent, "Left", $iLeft + 1) | |||
DllStructSetData($tAccent, "Top", $iBottom - 4) | |||
DllStructSetData($tAccent, "Right", $iRight - 1) | |||
DllStructSetData($tAccent, "Bottom", $iBottom - 1) | |||
Local $hAccentBrush = _WinAPI_CreateSolidBrush(0x0D47A1) ; 진한 파란 액센트 | |||
_WinAPI_FillRect($hDC, $tAccent, $hAccentBrush) | |||
_WinAPI_DeleteObject($hAccentBrush) | |||
EndIf | |||
; ── 텍스트 그리기 ── | |||
Local $sText = "" | |||
If $iItemID >= 0 And $iItemID < UBound($g_aTabNames) Then | |||
$sText = $g_aTabNames[$iItemID] | |||
EndIf | |||
; 폰트 생성 | |||
Local $hFont = _WinAPI_CreateFont($TAB_FONT_SIZE + 3, 0, 0, 0, _ | |||
($bSelected ? 700 : 400), _ ; 선택 시 Bold | |||
False, False, False, _ | |||
$DEFAULT_CHARSET, 0, 0, 5, 0, $TAB_FONT_NAME) | |||
Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) | |||
; 텍스트 색상 및 배경 모드 | |||
DllCall("gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", 1) ; TRANSPARENT | |||
DllCall("gdi32.dll", "int", "SetTextColor", "handle", $hDC, _ | |||
"int", $iTextColor) | |||
; 텍스트 중앙 정렬 출력 | |||
Local $tTextRect = DllStructCreate("long Left;long Top;long Right;long Bottom") | |||
DllStructSetData($tTextRect, "Left", $iLeft) | |||
DllStructSetData($tTextRect, "Top", $iTop) | |||
DllStructSetData($tTextRect, "Right", $iRight) | |||
DllStructSetData($tTextRect, "Bottom", $iBottom) | |||
; DT_CENTER=1, DT_VCENTER=4, DT_SINGLELINE=32 | |||
DllCall("user32.dll", "int", "DrawTextW", _ | |||
"handle", $hDC, _ | |||
"wstr", $sText, _ | |||
"int", -1, _ | |||
"struct*", $tTextRect, _ | |||
"uint", BitOR(1, 4, 32)) | |||
_WinAPI_SelectObject($hDC, $hOldFont) | |||
_WinAPI_DeleteObject($hFont) | |||
Return True ; 그리기 처리 완료 | |||
EndFunc | |||
; ══════════════════════════════════════════════════════ | |||
; WM_NOTIFY 핸들러 - 호버 효과를 위한 마우스 추적 | |||
; ══════════════════════════════════════════════════════ | |||
Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) | |||
Local $tNMHDR = DllStructCreate("hwnd hWndFrom;uint_ptr IDFrom;int Code", $lParam) | |||
Local $iCode = DllStructGetData($tNMHDR, "Code") | |||
; TCN_SELCHANGE = -551 (탭 변경 시 강제 다시 그리기) | |||
If $iCode = -551 Then | |||
_WinAPI_InvalidateRect(GUICtrlGetHandle($g_hTab)) | |||
EndIf | |||
Return $GUI_RUNDEFMSG | |||
EndFunc | |||
; ══════════════════════════════════════════════════════ | |||
; WinAPI 보조 함수 | |||
; ══════════════════════════════════════════════════════ | |||
Func _WinAPI_CreateSolidBrush($iColor) | |||
Local $aRet = DllCall("gdi32.dll", "handle", "CreateSolidBrush", "int", $iColor) | |||
Return $aRet[0] | |||
EndFunc | |||
Func _WinAPI_FillRect($hDC, $tRect, $hBrush) | |||
DllCall("user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush) | |||
EndFunc | |||
</source> | |||
[[category:autoit]] | [[category:autoit]] | ||
2026년 5월 15일 (금) 17:59 기준 최신판
플랫 버튼 스타일
- 1. BS_FLAT 스타일 (가장 간단)
#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
$hGUI = GUICreate("Flat Button", 300, 200)
GUISetBkColor(0xFFFFFF)
$hBtn = GUICtrlCreateButton("클릭", 50, 50, 200, 40, $BS_FLAT)
GUISetState()
While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd
3D 테두리가 제거되지만, 마우스 오버 시 테두리가 살아나서 완전한 플랫은 아닙니다.
- 2. Label + 색상 조합 (완전 플랫)
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
$hGUI = GUICreate("Flat Button", 400, 300)
GUISetBkColor(0xFFFFFF)
; 버튼처럼 동작하는 Label
$hBtn1 = _CREATE_FLAT_BUTTON("저장", 30, 50, 150, 45, 0x2196F3, 0xFFFFFF)
$hBtn2 = _CREATE_FLAT_BUTTON("취소", 210, 50, 150, 45, 0xF44336, 0xFFFFFF)
$hBtn3 = _CREATE_FLAT_BUTTON("설정", 30, 120, 150, 45, 0x4CAF50, 0xFFFFFF)
$hBtn4 = _CREATE_FLAT_BUTTON("닫기", 210, 120, 150, 45, 0x757575, 0xFFFFFF)
GUISetState()
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
Case $hBtn1
MsgBox(0, "", "저장 클릭")
Case $hBtn2
MsgBox(0, "", "취소 클릭")
Case $hBtn3
MsgBox(0, "", "설정 클릭")
Case $hBtn4
MsgBox(0, "", "닫기 클릭")
EndSwitch
WEnd
Func _CREATE_FLAT_BUTTON($sText, $iX, $iY, $iW, $iH, $iBgColor, $iFontColor)
Local $hLabel = GUICtrlCreateLabel($sText, $iX, $iY, $iW, $iH, _
BitOR($SS_CENTER, $SS_CENTERIMAGE))
GUICtrlSetBkColor($hLabel, $iBgColor)
GUICtrlSetColor($hLabel, $iFontColor)
GUICtrlSetFont($hLabel, 11, 600, 0, "맑은 고딕")
GUICtrlSetCursor($hLabel, 0) ; 손가락 커서
Return $hLabel
EndFunc
- 3. GDI+ Owner-Draw (호버 효과 포함)
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <StaticConstants.au3>
Global Const $FLAT_COLOR_NORMAL = 0xFF2196F3 ; 파란색
Global Const $FLAT_COLOR_HOVER = 0xFF1976D2 ; 진한 파란색
Global Const $FLAT_COLOR_PRESS = 0xFF0D47A1 ; 더 진한 파란색
Global Const $FLAT_COLOR_TEXT = 0xFFFFFFFF ; 흰색
Global $g_aBtns[0][6] ; [n][CtrlID, X, Y, W, H, Text]
Global $g_iHoverIdx = -1
Global $g_iPressIdx = -1
Global $g_hGUI
_GDIPlus_Startup()
$g_hGUI = GUICreate("GDI+ Flat Buttons", 400, 300)
GUISetBkColor(0xF5F5F5)
; GDI+ 그리기용 Pic 컨트롤 (전체 영역)
Global $g_hPic = GUICtrlCreatePic("", 0, 0, 400, 300)
GUICtrlSetState($g_hPic, $GUI_DISABLE)
; 버튼 등록
_ADD_FLAT_BUTTON(30, 50, 150, 45, "저장")
_ADD_FLAT_BUTTON(210, 50, 150, 45, "취소")
_ADD_FLAT_BUTTON(30, 120, 150, 45, "설정")
_ADD_FLAT_BUTTON(210, 120, 150, 45, "닫기")
_DRAW_ALL_BUTTONS()
GUISetState()
GUIRegisterMsg($WM_MOUSEMOVE, "_WM_MOUSEMOVE")
GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN")
GUIRegisterMsg($WM_LBUTTONUP, "_WM_LBUTTONUP")
While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd
_GDIPlus_Shutdown()
; ── 버튼 추가 ──
Func _ADD_FLAT_BUTTON($iX, $iY, $iW, $iH, $sText)
Local $iIdx = UBound($g_aBtns)
ReDim $g_aBtns[$iIdx + 1][6]
$g_aBtns[$iIdx][0] = $iIdx
$g_aBtns[$iIdx][1] = $iX
$g_aBtns[$iIdx][2] = $iY
$g_aBtns[$iIdx][3] = $iW
$g_aBtns[$iIdx][4] = $iH
$g_aBtns[$iIdx][5] = $sText
EndFunc
; ── 전체 버튼 그리기 ──
Func _DRAW_ALL_BUTTONS()
Local $hBitmap = _GDIPlus_BitmapCreateFromScan0(400, 300)
Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap)
_GDIPlus_GraphicsSetSmoothingMode($hGfx, 4)
_GDIPlus_GraphicsSetTextRenderingHint($hGfx, 5)
_GDIPlus_GraphicsClear($hGfx, 0xFFF5F5F5)
Local $hFontFamily = _GDIPlus_FontFamilyCreate("맑은 고딕")
Local $hFont = _GDIPlus_FontCreate($hFontFamily, 12, 1)
Local $hFormat = _GDIPlus_StringFormatCreate()
_GDIPlus_StringFormatSetAlign($hFormat, 1) ; 가로 중앙
_GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; 세로 중앙
Local $hTextBrush = _GDIPlus_BrushCreateSolid($FLAT_COLOR_TEXT)
For $i = 0 To UBound($g_aBtns) - 1
; 상태별 색상 결정
Local $iColor = $FLAT_COLOR_NORMAL
If $i = $g_iPressIdx Then
$iColor = $FLAT_COLOR_PRESS
ElseIf $i = $g_iHoverIdx Then
$iColor = $FLAT_COLOR_HOVER
EndIf
; 둥근 사각형 배경
Local $hPath = _GDIPlus_PathCreate()
Local $r = 8 ; 둥근 반지름
Local $bX = $g_aBtns[$i][1], $bY = $g_aBtns[$i][2]
Local $bW = $g_aBtns[$i][3], $bH = $g_aBtns[$i][4]
_GDIPlus_PathAddArc($hPath, $bX, $bY, $r * 2, $r * 2, 180, 90)
_GDIPlus_PathAddArc($hPath, $bX + $bW - $r * 2, $bY, $r * 2, $r * 2, 270, 90)
_GDIPlus_PathAddArc($hPath, $bX + $bW - $r * 2, $bY + $bH - $r * 2, $r * 2, $r * 2, 0, 90)
_GDIPlus_PathAddArc($hPath, $bX, $bY + $bH - $r * 2, $r * 2, $r * 2, 90, 90)
_GDIPlus_PathCloseFigure($hPath)
Local $hBrush = _GDIPlus_BrushCreateSolid($iColor)
_GDIPlus_GraphicsFillPath($hGfx, $hPath, $hBrush)
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_PathDispose($hPath)
; 텍스트
Local $tRect = _GDIPlus_RectFCreate($bX, $bY, $bW, $bH)
_GDIPlus_GraphicsDrawStringEx($hGfx, $g_aBtns[$i][5], $hFont, $tRect, $hFormat, $hTextBrush)
Next
; Pic에 적용
Local $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
_WinAPI_DeleteObject(GUICtrlSendMsg($g_hPic, 0x0172, 0, $hHBmp)) ; STM_SETIMAGE
_WinAPI_DeleteObject($hHBmp)
_GDIPlus_BrushDispose($hTextBrush)
_GDIPlus_FontDispose($hFont)
_GDIPlus_FontFamilyDispose($hFontFamily)
_GDIPlus_StringFormatDispose($hFormat)
_GDIPlus_GraphicsDispose($hGfx)
_GDIPlus_BitmapDispose($hBitmap)
EndFunc
; ── 마우스 위치로 버튼 인덱스 찾기 ──
Func _HIT_TEST($iMX, $iMY)
For $i = 0 To UBound($g_aBtns) - 1
If $iMX >= $g_aBtns[$i][1] And $iMX <= $g_aBtns[$i][1] + $g_aBtns[$i][3] And _
$iMY >= $g_aBtns[$i][2] And $iMY <= $g_aBtns[$i][2] + $g_aBtns[$i][4] Then
Return $i
EndIf
Next
Return -1
EndFunc
; ── 마우스 이동 ──
Func _WM_MOUSEMOVE($hWnd, $iMsg, $wParam, $lParam)
Local $iMX = BitAND($lParam, 0xFFFF)
Local $iMY = BitShift(BitAND($lParam, 0xFFFF0000), 16)
Local $iIdx = _HIT_TEST($iMX, $iMY)
If $iIdx <> $g_iHoverIdx Then
$g_iHoverIdx = $iIdx
_DRAW_ALL_BUTTONS()
EndIf
Return $GUI_RUNDEFMSG
EndFunc
; ── 마우스 누름 ──
Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam)
Local $iMX = BitAND($lParam, 0xFFFF)
Local $iMY = BitShift(BitAND($lParam, 0xFFFF0000), 16)
$g_iPressIdx = _HIT_TEST($iMX, $iMY)
If $g_iPressIdx >= 0 Then _DRAW_ALL_BUTTONS()
Return $GUI_RUNDEFMSG
EndFunc
; ── 마우스 뗌 ──
Func _WM_LBUTTONUP($hWnd, $iMsg, $wParam, $lParam)
Local $iMX = BitAND($lParam, 0xFFFF)
Local $iMY = BitShift(BitAND($lParam, 0xFFFF0000), 16)
Local $iIdx = _HIT_TEST($iMX, $iMY)
If $iIdx >= 0 And $iIdx = $g_iPressIdx Then
; 버튼 클릭 이벤트
MsgBox(0, "클릭", $g_aBtns[$iIdx][5] & " 버튼 클릭!")
EndIf
$g_iPressIdx = -1
_DRAW_ALL_BUTTONS()
Return $GUI_RUNDEFMSG
EndFunc
세 방식의 차이를 정리하면 다음과 같습니다.
- 방법 1 (BS_FLAT)** — 코드 한 줄이면 되지만 Windows 기본 버튼 렌더링에 의존하므로 완전한 플랫이 아닙니다. 마우스 오버 시 3D 테두리가 나타납니다.
- 방법 2 (Label 활용)** — Label에 배경색과 폰트색을 입히는 방식으로, 코드가 간결하면서도 완전 플랫합니다. 다만 호버/프레스 시 색상 변화를 주려면 타이머나 메시지 처리를 추가해야 합니다.
- 방법 3 (GDI+ Owner-Draw)** — 가장 자유도가 높습니다. 둥근 모서리, 호버 색상 변화, 프레스 효과까지 완전히 커스텀 가능합니다. 코드량이 많지만 SQL*KEY처럼 UI를 세밀하게 제어해야 하는 프로그램에 적합합니다.
플랫한 버튼 스타일 예제
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
; ── Tab Control 스타일 상수 ──
Global Const $TCS_MULTILINE = 0x0200
Global Const $TCS_BUTTONS = 0x0100
Global Const $TCS_FLATBUTTONS = 0x0008
Global Const $TCS_OWNERDRAWFIXED = 0x2000
Global Const $ODT_TAB = 101
Global Const $ODS_SELECTED = 0x0001
; ── 색상 설정 ──
Global Const $CLR_TAB_SELECTED_BG = 0x2196F3 ; 선택된 탭 배경 (파란색)
Global Const $CLR_TAB_SELECTED_TEXT = 0xFFFFFF ; 선택된 탭 텍스트 (흰색)
Global Const $CLR_TAB_NORMAL_BG = 0xE0E0E0 ; 일반 탭 배경 (밝은 회색)
Global Const $CLR_TAB_NORMAL_TEXT = 0x333333 ; 일반 탭 텍스트 (진한 회색)
Global Const $CLR_TAB_HOVER_BG = 0xBBDEFB ; 호버 탭 배경 (연한 파란색)
Global Const $CLR_TAB_HOVER_TEXT = 0x1565C0 ; 호버 탭 텍스트
Global Const $CLR_GUI_BG = 0xFAFAFA ; GUI 배경
Global Const $CLR_CONTENT_BG = 0xFFFFFF ; 탭 콘텐츠 영역 배경
; ── 폰트 설정 ──
Global Const $TAB_FONT_NAME = "맑은 고딕"
Global Const $TAB_FONT_SIZE = 10
; ── 탭 데이터 ──
Global $g_aTabNames[] = [ _
"환경설정", "단축키 관리", "실행파일", "후킹설정", _
"Direct Key", "매크로", "히스토리", "도움말" _
]
Global $g_hGUI, $g_hTab
Global $g_aTabItems[UBound($g_aTabNames)]
Global $g_aTabLabels[UBound($g_aTabNames)] ; 탭별 콘텐츠 라벨
Global $g_iHoverTab = -1
; ── GUI 생성 ──
$g_hGUI = GUICreate("SQL*KEY - Flat Tab Demo", 700, 500)
GUISetBkColor($CLR_GUI_BG)
GUISetFont($TAB_FONT_SIZE, 400, 0, $TAB_FONT_NAME)
; ── Tab 컨트롤 생성 ──
; TCS_OWNERDRAWFIXED: 직접 그리기
; TCS_BUTTONS: 버튼 스타일
; TCS_MULTILINE: 다중 행
; TCS_FLATBUTTONS: 플랫 버튼 (owner-draw와 함께 사용)
$g_hTab = GUICtrlCreateTab(10, 10, 680, 480, _
BitOR($TCS_OWNERDRAWFIXED, $TCS_BUTTONS, $TCS_MULTILINE, $TCS_FLATBUTTONS))
GUICtrlSetFont($g_hTab, $TAB_FONT_SIZE, 400, 0, $TAB_FONT_NAME)
; ── TabItem 생성 ──
For $i = 0 To UBound($g_aTabNames) - 1
$g_aTabItems[$i] = GUICtrlCreateTabItem($g_aTabNames[$i])
; 각 탭의 콘텐츠 예시
$g_aTabLabels[$i] = GUICtrlCreateLabel( _
"[ " & $g_aTabNames[$i] & " ] 탭 콘텐츠 영역", _
30, 80, 640, 380)
GUICtrlSetFont($g_aTabLabels[$i], 14, 400, 0, $TAB_FONT_NAME)
GUICtrlSetColor($g_aTabLabels[$i], 0x757575)
GUICtrlSetBkColor($g_aTabLabels[$i], $CLR_CONTENT_BG)
Next
GUICtrlCreateTabItem("") ; 탭 아이템 종료
; ── WM_DRAWITEM 등록 (탭 커스텀 그리기) ──
GUIRegisterMsg($WM_DRAWITEM, "_WM_DRAWITEM")
; ── WM_MOUSEMOVE 등록 (호버 효과) ──
GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
GUISetState(@SW_SHOW)
; ── 메인 루프 ──
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
; ══════════════════════════════════════════════════════
; WM_DRAWITEM 핸들러 - 탭을 플랫 스타일로 직접 그리기
; ══════════════════════════════════════════════════════
Func _WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam)
; DRAWITEMSTRUCT 구조체 파싱
Local $tDRAWITEM = DllStructCreate( _
"uint CtlType;" & _
"uint CtlID;" & _
"uint itemID;" & _
"uint itemAction;" & _
"uint itemState;" & _
"hwnd hwndItem;" & _
"handle hDC;" & _
"long rcLeft;long rcTop;long rcRight;long rcBottom;" & _
"ulong_ptr itemData", _
$lParam)
Local $iCtlType = DllStructGetData($tDRAWITEM, "CtlType")
If $iCtlType <> $ODT_TAB Then Return $GUI_RUNDEFMSG
Local $iItemID = DllStructGetData($tDRAWITEM, "itemID")
Local $iState = DllStructGetData($tDRAWITEM, "itemState")
Local $hDC = DllStructGetData($tDRAWITEM, "hDC")
Local $iLeft = DllStructGetData($tDRAWITEM, "rcLeft")
Local $iTop = DllStructGetData($tDRAWITEM, "rcTop")
Local $iRight = DllStructGetData($tDRAWITEM, "rcRight")
Local $iBottom = DllStructGetData($tDRAWITEM, "rcBottom")
Local $bSelected = BitAND($iState, $ODS_SELECTED)
; ── 색상 결정 ──
Local $iBgColor, $iTextColor
If $bSelected Then
$iBgColor = $CLR_TAB_SELECTED_BG
$iTextColor = $CLR_TAB_SELECTED_TEXT
ElseIf $iItemID = $g_iHoverTab Then
$iBgColor = $CLR_TAB_HOVER_BG
$iTextColor = $CLR_TAB_HOVER_TEXT
Else
$iBgColor = $CLR_TAB_NORMAL_BG
$iTextColor = $CLR_TAB_NORMAL_TEXT
EndIf
; ── 배경 채우기 (1px 간격으로 버튼 분리) ──
Local $tRect = DllStructCreate("long Left;long Top;long Right;long Bottom")
DllStructSetData($tRect, "Left", $iLeft + 1)
DllStructSetData($tRect, "Top", $iTop + 1)
DllStructSetData($tRect, "Right", $iRight - 1)
DllStructSetData($tRect, "Bottom", $iBottom - 1)
Local $hBrush = _WinAPI_CreateSolidBrush($iBgColor)
_WinAPI_FillRect($hDC, $tRect, $hBrush)
_WinAPI_DeleteObject($hBrush)
; ── 선택된 탭 하단 액센트 라인 ──
If $bSelected Then
Local $tAccent = DllStructCreate("long Left;long Top;long Right;long Bottom")
DllStructSetData($tAccent, "Left", $iLeft + 1)
DllStructSetData($tAccent, "Top", $iBottom - 4)
DllStructSetData($tAccent, "Right", $iRight - 1)
DllStructSetData($tAccent, "Bottom", $iBottom - 1)
Local $hAccentBrush = _WinAPI_CreateSolidBrush(0x0D47A1) ; 진한 파란 액센트
_WinAPI_FillRect($hDC, $tAccent, $hAccentBrush)
_WinAPI_DeleteObject($hAccentBrush)
EndIf
; ── 텍스트 그리기 ──
Local $sText = ""
If $iItemID >= 0 And $iItemID < UBound($g_aTabNames) Then
$sText = $g_aTabNames[$iItemID]
EndIf
; 폰트 생성
Local $hFont = _WinAPI_CreateFont($TAB_FONT_SIZE + 3, 0, 0, 0, _
($bSelected ? 700 : 400), _ ; 선택 시 Bold
False, False, False, _
$DEFAULT_CHARSET, 0, 0, 5, 0, $TAB_FONT_NAME)
Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)
; 텍스트 색상 및 배경 모드
DllCall("gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", 1) ; TRANSPARENT
DllCall("gdi32.dll", "int", "SetTextColor", "handle", $hDC, _
"int", $iTextColor)
; 텍스트 중앙 정렬 출력
Local $tTextRect = DllStructCreate("long Left;long Top;long Right;long Bottom")
DllStructSetData($tTextRect, "Left", $iLeft)
DllStructSetData($tTextRect, "Top", $iTop)
DllStructSetData($tTextRect, "Right", $iRight)
DllStructSetData($tTextRect, "Bottom", $iBottom)
; DT_CENTER=1, DT_VCENTER=4, DT_SINGLELINE=32
DllCall("user32.dll", "int", "DrawTextW", _
"handle", $hDC, _
"wstr", $sText, _
"int", -1, _
"struct*", $tTextRect, _
"uint", BitOR(1, 4, 32))
_WinAPI_SelectObject($hDC, $hOldFont)
_WinAPI_DeleteObject($hFont)
Return True ; 그리기 처리 완료
EndFunc
; ══════════════════════════════════════════════════════
; WM_NOTIFY 핸들러 - 호버 효과를 위한 마우스 추적
; ══════════════════════════════════════════════════════
Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
Local $tNMHDR = DllStructCreate("hwnd hWndFrom;uint_ptr IDFrom;int Code", $lParam)
Local $iCode = DllStructGetData($tNMHDR, "Code")
; TCN_SELCHANGE = -551 (탭 변경 시 강제 다시 그리기)
If $iCode = -551 Then
_WinAPI_InvalidateRect(GUICtrlGetHandle($g_hTab))
EndIf
Return $GUI_RUNDEFMSG
EndFunc
; ══════════════════════════════════════════════════════
; WinAPI 보조 함수
; ══════════════════════════════════════════════════════
Func _WinAPI_CreateSolidBrush($iColor)
Local $aRet = DllCall("gdi32.dll", "handle", "CreateSolidBrush", "int", $iColor)
Return $aRet[0]
EndFunc
Func _WinAPI_FillRect($hDC, $tRect, $hBrush)
DllCall("user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush)
EndFunc