유저폼(Userform)은 엑셀 솔루션을 만들 때 많이 사용되는 요소입니다.
- Userform 속성에서 [ShowModal] 프로퍼티를 False로 변경.
- 유저폼을 띄울 때 옵션값을 0으로 지정. Userform1.Show 0
모양 |
|
API 적용 | Dim hwnd As Long hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Caption) '***** 캡션창을 없앤다. SetWindowLong hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) And Not WS_CAPTION |
모서리가 둥근 유저폼 만들기(Round Rect Userform)
모양 |
|
API 적용 | Dim hwnd As Long hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Caption) '***** 설정된 값으로 모서리가 둥근 유저폼 생성한다. SetWindowRgn hwnd, CreateRoundRectRgn(0, 0, Me.Width + 100, Me.Height, 20, 20), True |
유저폼 반투명하게 만들기(Transparent Userform)
모양 |
|
API 적용 | Dim hwnd As Long hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Caption) '***** 반투명 레이어로 만들기 위해 유저폼 셋팅 SetWindowLong hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED '***** 반투명 폼으로 적용(0~255) SetLayeredWindowAttributes hwnd, 0, 195, LWA_ALPHA |
위의 방법을 다 적용하면 다음과 같이 타이틀바 없고, 모서리가 둥글고, 반투명한 유저폼도 생성할 수 있습니다. ^^
<타이틀바 없고, 모서리가 둥글고, 반투명한 유저폼>
하지만 너무 과도하게 효과를 넣으면 오히려 보기 싫어질 수가 있겠죠?
위에 간단하게 API 코드를 적었습니다만, 당연히 그냥은 실행이 안됩니다.
API 함수를 선언해 줘야 하고, 사용된 상수값들도 셋팅해 줘야겠죠.
그런데 위와 같은 유저폼을 옮기고 싶으면 어떻게 할까요?
MouseMove이벤트와 API를 이용해서 Userform 아무곳을 클릭하고 드래그 하면 이동되게 할 수 있습니다.
또, 예기치않게 사용자가 창을 닫아버리는 걸 방지하고 싶다면 어떻게 할까요?
캡션바가 없어졌으므로 우측상단의 X 버튼은 자연히 사용할 수 없게 되었습니다.
Alt+F4로 폼을 닫는 것도 막아버릴 수 있습니다.
사용자는 오직 내가 만들어놓은 Close버튼을 눌러야만 창을 닫을 수 있습니다.
이렇게 사용자의 행동을 내가 원하는 대로 제한시킬 수 있습니다. 종종 생기죠, 이런 경우. ㅎㅎ
위의 모든 내용을 아우르는 코드입니다..
1. Userform을 하나 생성하고, 버튼을 하나 만듭니다.(CommandButton1)
2. 아래 코드를 붙여넣습니다.
'//********** API용 상수값 설정 Private Const WS_CAPTION = &HC00000 Private Const LWA_COLORKEY = &H1 '## 색상지정값 확정 Private Const LWA_ALPHA = &H2 '## 투명도 확정 Private Const GWL_STYLE = (-16) '## 윈도우 스타일 Private Const GWL_EXSTYLE = (-20) '## 확장형윈도우 스타일 Private Const WS_EX_LAYERED = &H80000 '## 계층형 윈도우 생성 Private Const WM_NCMOUSEMOVE = &HA0 Private Const WM_NCLBUTTONDOWN = &HA1 Private Const WM_NCLBUTTONUP = &HA2 Private Const WM_NCLBUTTONDBLCLK = &HA3 Private Const WM_NCRBUTTONDOWN = &HA4 Private Const WM_NCRBUTTONUP = &HA5 Private Const WM_NCRBUTTONDBLCLK = &HA6 Private Const WM_NCMBUTTONDOWN = &HA7 Private Const WM_NCMBUTTONUP = &HA8 Private Const WM_NCMBUTTONDBLCLK = &HA9 Private Const HTCAPTION = 2 Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Private Declare Function CreateRoundRectRgn Lib "gdi32" (ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long, ByVal X3 As Long, ByVal Y3 As Long) As Long Private Declare Function SetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long Private Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Private Declare Sub ReleaseCapture Lib "user32" () Private Sub CommandButton1_Click() Unload Me End Sub Private Sub UserForm_Initialize() Dim hwnd As Long hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Me.Caption) '***** 캡션창을 없앤다. SetWindowLong hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) And Not WS_CAPTION '***** 설정된 값으로 모서리가 둥근 유저폼 생성한다. SetWindowRgn hwnd, CreateRoundRectRgn(0, 0, Me.Width + 100, Me.Height, 20, 20), True '***** 반투명 레이어로 만들기 위해 유저폼 셋팅 Call SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED) '***** 반투명 폼으로 적용(0~255) Call SetLayeredWindowAttributes(hwnd, 0, 195, LWA_ALPHA) Me.Height = Me.Height + 1 End Sub Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single) Dim hwnd As Long '***** 마우스 왼쪽 버튼을 누은 상태에서 Drag한다면 If Button = 1 And Shift = 0 Then '***** 유저폼의 핸들을 취득한다. hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Me.Caption) '***** 마우스 이벤트이외의 이벤트 발생을 허용 Call ReleaseCapture '***** 해당 지점을 Caption Bar로 인식시킨다. Call SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&) End If End Sub Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) '***** Alt+F4로도 종료하지 못하도록 조치함 Cancel = CloseMode = 0 End Sub
참고2
FindWindow 함수로는 현재 유저폼의 핸들을 취득합니다.
엑셀 자체 프로그램의 핸들은 Application.hwnd 메서드로 바로 구할 수가 있지만, 유저폼에서는 지원되지 않습니다.
유저폼의 핸들은 FindWindow API함수를 이용해 찾을 수 있습니다.
hwnd = FindWindow(IIf(Application.Version >= 11, "ThunderDFrame", "ThunderXFrame"), Me.Caption)
이 포스팅에 소개한 예제 파일입니다.
이외에도 유저폼에 애니메이션 효과를 줄 수 있는 AnimateWindow 함수,
포지션 및 크기를 Windows기준으로 설정할 수 있는 MoveWindow 함수,
각 유저폼(또는 특정 핸들)을 다른 폼에 종속시킬 수 있는 SetParent 함수 등
필요에 따라 많은 API함수를 적용해 볼 수 있습니다.
'Excel Develop > VBA' 카테고리의 다른 글
[ACCESS] 엑세스의 일련번호(Autonumber Counter) 를 초기화하는 쿼리 (0) | 2013.07.04 |
---|---|
[VB/VBA] 자동으로 닫히는 MsgBox (4) | 2012.11.27 |
[VBA] 크기조절이 가능한 유저폼 생성하기. (Resizable Userform) (3) | 2012.11.24 |
[vba] Twain드라이버와 Lead Tools를 이용해 스캐너 직접 제어 (5) | 2012.01.20 |