Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

ILButton() - image buttons with text, states, alignment


  • Please log in to reply
52 replies to this topic
tkoi
  • Members
  • 56 posts
  • Last active: Feb 25 2011 02:32 AM
  • Joined: 26 Jun 2008
First of all, I want to say thanks a bunch to corrupt for his excellent graphic button functions. I've used them extensively. However, I found a few aspects lacking.

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 variablesPosted Image_Posted Image

Download: ILButton11.ahk
/*
Title: ILButton
Version: 1.1
Author: tkoi <https://ahknet.autohotkey.com/~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

BoBo³
  • Guests
  • Last active:
  • Joined: --
Thanks for sharing your script(s). Much appreciated :D

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Great! Thanks. :)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Very nice!
Could you extend it, such that the associated system icon of the file would be shown, e.g. when the icon number is -1?

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
The command VarSetCapacity(structs, c+24) looks suspicious:

It allocates larger and larger memory blocks, but each time the previous data can be lost. In this script the old data might be preserved, because struct is the last static variable, so its memory is just increased, but this behavior might change in a future AHK version or when the memory pool dries out. Since we have no static arrays, we probably have to use an array of global structs.

To demonstrate the problem, add VarSetCapacity(c, c+24) to the code. Now the struct variable cannot be just enlarged, and the script breaks.

majkinetor !
  • Guests
  • Last active:
  • Joined: --
Great discovery. I traversed all API places around for the solution regarding system bug with button images but I didn't see this one.

IT works in XP too, but here icons appear only when i mouse over them. Seems like an easy thing to solve anyway.

Thx.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

IT works in XP too, but here icons appear only when i mouse over them.

On my XP laptop changing Sleep -1 to Sleep 1 (last line) fixes the problem.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
:)

Thx
Posted Image

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005
Looks useful. Thanks for sharing. :)

webber
  • Members
  • 129 posts
  • Last active: Aug 13 2011 06:45 PM
  • Joined: 25 Aug 2005
testing this tool but I'm unable to use a specific icon. the icon image is in the same folder as script

can someone tell me why this line fails to return an image ?


Gui, 2:Add, Button, x16 y50  w100 h30 hwndhBtn gButtonTool_1, Tool_2
		ILButton(hBtn, "icon6-16x16C.ico:0" 1, 16, 16, 0)

________
DRUGTEST

tkoi
  • Members
  • 56 posts
  • Last active: Feb 25 2011 02:32 AM
  • Joined: 26 Jun 2008
What's that 1 doing there? :D
Gui, 2:Add, Button, x16 y50  w100 h30 hwndhBtn gButtonTool_1, Tool_2
      ILButton(hBtn, "icon6-16x16C.ico:0" [color=red]1[/color], 16, 16, 0)


webber
  • Members
  • 129 posts
  • Last active: Aug 13 2011 06:45 PM
  • Joined: 25 Aug 2005
image is not appearing on the button - that's what I doing there.

so the question is, why no image from the code ?

tkoi
  • Members
  • 56 posts
  • Last active: Feb 25 2011 02:32 AM
  • Joined: 26 Jun 2008
I tested it - it works if you remove the 1.

webber
  • Members
  • 129 posts
  • Last active: Aug 13 2011 06:45 PM
  • Joined: 25 Aug 2005
:oops:
________
Chevrolet colorado

tkoi
  • Members
  • 56 posts
  • Last active: Feb 25 2011 02:32 AM
  • Joined: 26 Jun 2008
Updated - the function now uses the assume-static mode introduced in 1.0.48