Focused Control Colored Border Animation
GDI/Gdip, DllCall, And Onmessage
This example script draws a colored border around the currently focused control in an AHK GUI using onmessage, tics gdip library found
here, and Lexiko's WinToClient function found
here. I know that some controls have a border property that can be turned on and off. The example below can be used to specify any color border and any location for the border. You could also use this to draw a colored groupbox, to draw other shapes, and to draw text. There's many more examples that can be adopted from
tics topic. I'm sure it's also possible to turn off the standard control outlines and borders and draw your own.
This example is using onmessage to draw a border around the focused control when the script receives the
WM_COMMAND 0x111 message. The other onmessage,
WM_SYSCOMMAND 0x112, is used to reset the border drawing when the GUI is restored from being minimized. The biggest lingering problem I'm having, is GUI flickering when the focus is switched quickly and repeatedly. I'm trying to find the best way to do this, I know it can be optimized further. I'm also open to and welcome suggestions for additional things to add to this.
The client area offset may be different for your system, it is going to be different for XP, Vista, and 7 and it may be different for different themes. You can fix it for now by changing the CX -= 1 an CY -= 1 offset as needed. I have tried to compensate for the difference in the client area position using Lexikos WinToClient function found
here in the new version of this script. This should fix all of the border location issues from the first version. Please post a response if you have any issues with the location of the border drawing using the newest version.
Changes/Additions:- (2/15/11) Added Lexikos's WinToClient function to get the correct client area offset for different versions of Windows.
Requires Gdip.ahk to be in your library, or in the same directory as this script.
You can download it here from this topic.
Code:
#NoEnv
#Include Gdip.ahk
SetWorkingDir %A_ScriptDir%
SetBatchLines, -1
OnExit, ExitProcess
If !pToken := Gdip_Startup()
{
Msgbox, 64, Focused Control Border, Could not load gdipluss.dll. Make sure you have gdiplus.dll support on your system.
ExitApp
}
Gui, +LastFound
WinId := WinExist()
OnMessage(0x112, "WindowState")
OnMessage(0x111, "DrawBorder")
Gui, Font, s9 cBlack, Trebuchet MS
Gui, Add, GroupBox, x7 y5 w312 h114 Section, Account Data
Gui, Font, s8 cBlack, Trebuchet MS
Gui, Add, Edit, xs+12 ys+21 w237 r1 vEmail Section
Gui, Add, Text, x+3 ys+4 w30, Email
Gui, Add, Edit, x18 y+9 w100 r1 vFirst Section
Gui, Add, Text, x+3 ys+4 w20, First
Gui, Add, Edit, x+11 ys w100 r1 vLast Section
Gui, Add, Text, x+3 ys+4 w30, Last
Gui, Add, Radio, x18 y+14 w15 h15 vMale Section Checked1
Gui, Add, Text, x+3 ys-2 w25, Male
Gui, Add, Radio, x+2 ys w15 h15 vFemale Section
Gui, Add, Text, x+2 ys-2 w30, Female
Gui, Add, DropDownList, x+16 ys-5 w126 r6 vQuestion Section, Option A||Option B|Option C|Option D
Gui, Add, Text, x+3 ys+4 w30, Option
Gui, Show,, Focused Control Border
Return
GuiClose:
;==============
ExitApp
ExitProcess:
;==============
If pToken !=
Gdip_Shutdown(pToken)
ExitApp
DrawBorder(wParam, lParam, msg, hwnd)
{
Global WinId
Global Last
If lParam = %Last%
Return
WinSet, Redraw,, ahk_id %WinId%
Sleep, 20
Last := lParam
ControlGetPos, CX, CY, CW, CH,, ahk_id %lParam%
WinToClient(WinId, CX, CY)
CX -= 1
CY -= 1
CW += 1
CH += 1
Width = 1024
Height = 768
hbm := CreateDIBSection(Width, Height)
hdc := getDC(WinId)
obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_SetSmoothingMode(G, 4)
pPen := Gdip_CreatePen(0xff87ceff, 1)
Gdip_DrawRectangle(G, pPen, CX, CY, CW, CH)
Gdip_DeletePen(pPen)
DllCall("UpdateWindow", UInt, WinId)
SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(G)
Return
}
WindowState(wParam, lParam, msg, hwnd)
{
Global Last
If lparam = 0
Last =
}
WinToClient(hwnd, ByRef CX, ByRef CY)
{
WinGetPos, wx, wy,,, ahk_id %hwnd%
VarSetCapacity(pt, 8)
NumPut(CX + wx, pt, 0)
NumPut(CY + wy, pt, 4)
DllCall("ScreenToClient", "uint", hwnd, "uint", &pt)
CX := NumGet(pt, 0, "int")
CY := NumGet(pt, 4, "int")
}