The most glaring problem is the limitations on Windows XP. On XP, buttons with the BM_SETIMAGE message do not assume the OS's visual style, which can end up looking downright ugly if you have both text buttons and image buttons in your app. These buttons also are incapable of displaying an image+text.
BM_SETIMAGE buttons do not have native support for button states (hover, disabled, etc) or image alignment.
So with these flaws in mind, I went searching for a better way to create an image button. What I found was the BCM_SETIMAGELIST message. This attaches an imagelist to a button, and, combined with a few dllcall functions, allows for more flexible and customizable image buttons. I've written a single small function wrapping most of the options that are available.
Features[*:346l8jia] Supports exe, dll, ico, cur, ani, and bmp files
[*:346l8jia] Button states: normal, hover, pressed, disabled, focused, and stylushot
[*:346l8jia] Supports image+text
[*:346l8jia] Supports visual styles on Windows XP
[*:346l8jia] Alignment options: left, right, top, bottom, or center - very useful for image+text buttons
[*:346l8jia] Image margin options
[*:346l8jia] Creates no global variables
_
Download: ILButton11.ahk
/*
Title: ILButton
Version: 1.1
Author: tkoi <http://www.autohotkey.net/~tkoi>
License: GNU GPLv3 <http://www.opensource.org/licenses/gpl-3.0.html>
Function: ILButton()
Creates an imagelist and associates it with a button.
Parameters:
hBtn - handle to a buttton
images - a pipe delimited list of images in form "file:zeroBasedIndex"
- file must be of type exe, dll, ico, cur, ani, or bmp
- there are six states: normal, hot (hover), pressed, disabled, defaulted (focused), and stylushot
- ex. "normal.ico:0|hot.ico:0|pressed.ico:0|disabled.ico:0|defaulted.ico:0|stylushot.ico:0"
- if only one image is specified, it will be used for all the button's states
- if fewer than six images are specified, nothing is drawn for the states without images
- omit "file" to use the last file specified
- ex. "states.dll:0|:1|:2|:3|:4|:5"
- omitting an index is the same as specifying 0
- note: within vista's aero theme, a defaulted (focused) button fades between images 5 and 6
cx - width of the image in pixels
cy - height of the image in pixels
align - an integer between 0 and 4, inclusive. 0: left, 1: right, 2: top, 3: bottom, 4: center
margin - a comma-delimited list of four integers in form "left,top,right,bottom"
Notes:
A 24-byte static variable is created for each IL button
Tested on Vista Ultimate 32-bit SP1 and XP Pro 32-bit SP2.
Changes:
v1.1
Updated the function to use the assume-static feature introduced in AHK version 1.0.48
*/
ILButton(hBtn, images, cx=16, cy=16, align=4, margin="1,1,1,1") {
static
static i = 0
local himl, v0, v1, v2, v3, ext, hbmp, hicon
i ++
himl := DllCall("ImageList_Create", "UInt",cx, "UInt",cy, "UInt",0x20, "UInt",1, "UInt",5)
Loop, Parse, images, |
{
StringSplit, v, A_LoopField, :
if not v1
v1 := v3
v3 := v1
SplitPath, v1, , , ext
if (ext = "bmp") {
hbmp := DllCall("LoadImage", "UInt",0, "Str",v1, "UInt",0, "UInt",cx, "UInt",cy, "UInt",0x10)
DllCall("ImageList_Add", "UInt",himl, "UInt",hbmp, "UInt",0)
DllCall("DeleteObject", "UInt", hbmp)
}
else {
DllCall("PrivateExtractIcons", "Str",v1, "UInt",v2, "UInt",cx, "UInt",cy, "UIntP",hicon, "UInt",0, "UInt",1, "UInt",0)
DllCall("ImageList_AddIcon", "UInt",himl, "UInt",hicon)
DllCall("DestroyIcon", "UInt", hicon)
}
}
; Create a BUTTON_IMAGELIST structure
VarSetCapacity(struct%i%, 24)
NumPut(himl, struct%i%, 0, "UInt")
Loop, Parse, margin, `,
NumPut(A_LoopField, struct%i%, A_Index * 4, "UInt")
NumPut(align, struct%i%, 20, "UInt")
; BCM_FIRST := 0x1600, BCM_SETIMAGELIST := BCM_FIRST + 0x2
PostMessage, 0x1602, 0, &struct%i%, , ahk_id %hBtn%
Sleep 1 ; workaround for a redrawing problem on WinXP
}
Download: ilbuttondemo.ahk#SingleInstance force
#NoEnv
#Include %A_ScriptDir%\ILButton.ahk
Gui, +ToolWindow +AlwaysOnTop
Loop 5 {
Gui, Add, Button, w64 h32 xm hwndhBtn
ILButton(hBtn, "user32.dll:" A_Index-1, 16, 16, A_Index-1)
Gui, Add, Button, w100 h32 x+10 hwndhBtn, text
ILButton(hBtn, "user32.dll:" A_Index-1, 16, 16, A_Index-1)
}
Gui, Add, Button, xm w174 h48 vStates hwndhBtn, pushbuttonstates
ILButton(hBtn, "user32.dll:0|:1|:2|:3|:4|:5", 32, 32, 0, "16,1,-16,1")
Gui, Add, Button, w100 h26 xm+74 gToggle, Enable/disable
Gui, Show, , ILButton demo
return
Toggle:
GuiControlGet, s, Enabled, States
GuiControl, Disable%s%, States
return
GuiClose:
GuiEscape:
ExitApp
return
Please post any bugs you find!Regards,
tkoi




