Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Very strange behavior of button w/image list

Started by NoCforMe, August 06, 2022, 06:08:02 AM

Previous topic - Next topic


Here's a weird one for you:

I thought it would be nice to add a button to a program with a "hamburger" icon. You know, the 3 horizontal lines everyone's using these days to indicate "menu" or "options". So I created a small square button (32x32). Created an image list for the button (smaller, 24x24 so it'll fit inside and still show the button border). Loaded some bitmaps into the image list. Assigned the image list to the button.

It works, but it works weird. Check out the attached program. The button ... pulsates in its unclicked (and un-hovered over) state, at a rate of about 0.5 Hz. The image is steady when you mouse over or click on it (and hold the mouse button down). It actually looks kind of kewl, like someone animated it on purpose, but it's not what I want. And I'd like to know why it does that.

A word about image lists for those who don't know (I didn't myself until a few days ago): You can either assign a single image to a button (using the BM_SETIMAGE message), or you can assign an image list using BCM_SETIMAGELIST. If you do the latter and create an image list with different bitmaps you can have separate images for when the user hovers over the button with the mouse and when it's clicked. This works pretty well, although for some reason the mouse-over image (index=PBS_HOT) doesn't show the right colors. But that pulsation; just weird.

I tried a few things; called InitCommonControlsEx(). Tried using BCM_GETIDEALSIZE and resizing the control. Didn't make any difference. The button is being created as part of a dialog (one of the files is my dialog template file). Doesn't matter whether the BS_BITMAP style is included or not. You can try changing it in that include file (

Anyone have any idea what's going on here? I wouldn't spend too much time on this. This falls into the category of what I call "chrome", which includes all the whiz-bang visual effects that software developers spend so much time on. Animated stuff; kewl-looking controls with rounded edges; window opening and closing effects; transparency, etc. Doesn't affect how my code actually works.
Assembly language programming should be fun. That's why I do it.



Quote from: jj2007 on August 06, 2022, 07:57:59 AM
No such behaviour here on Win7-64 :cool:
Wow, really? I was afraid of that ...

Same OS here. So the image doesn't fade in and out? Did you try clicking on it?

That means there's something wrong with my system. I'm not surprised: so many things seem broken. I really should probably break down and buy a new copy of Windows, but I really don't want to do that ...
Assembly language programming should be fun. That's why I do it.


Could be some Windows settings, too. Themes?


Hi David,

There is nothing wrong with it here on an up to date Win10 64. Hover the mouse over it and it hilights the button, and if you click the button, it changes but remains hilighted while clicked on.


Oh gawd, what a bottomless pit that is! I actually was looking around at theme stuff yesterday. There is so much of that in Windows; the problem, of course, is that the documentation on it is piss-poor. I did discover several "theme explorers" you can download for free out there. Interesting poking around to see what's what.

As I said, it's all chrome. Like fins on cars in the 1950s.
Assembly language programming should be fun. That's why I do it.


Thanks, Hutch. That pretty much confirms that the problem lies within my system and not with that code, apparently.

BTW, if you look at the mouseover image and compare it to its bitmap (the 2nd one, Hamburger2.bmp), you'll see the background isn't the same color.

So are there any Windows theme experts here? I've found some stuff at other places, CodeGuru, Sourceforge, Stack Overflow, etc.
Assembly language programming should be fun. That's why I do it.


It looks like the background colour when clicked is a system default which you may be stuck with. Its probably better if you use the BM_SETIMAGE message and do a 3 stage image change, one as the default, the second as the hover image and the third as the clicked image. I am lazy, I only use 2 images, up and down.


So you're saying to change the images on the fly, in response to the state of the button? I could do that, I guess. What message(s) do I intercept to get the state of the button? I don't need to do owner draw, do I? I'm lazy too!

Hmm (answering own question): Looks like BCN_HOTITEMCHANGE will tell me when someone mouses over it. BN_PUSHED will tell me when it's pushed and BN_UNPUSHED when it goes back to normal. BUT there's a problem with those last two. MSDN says:

QuoteThis notification code is provided only for compatibility with 16-bit versions of Windows earlier than version 3.0. Applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

Aaaargh! I hate it. I really don't want to go the owner-draw route (what a nightmare, trying to draw something in the current theme!). On the other hand, who knows if those notifications are still supported? I'm going to guess they are and try them ...
Assembly language programming should be fun. That's why I do it.


For a 2 image solution, you subclass the button and respond in the subclass to the WM_LBUTTONUP and WM_LBUTTONDOWN messages.

You write a separate subclass for each button and have the bmp handles for each set with the two messages. The following example is 64 bit but the 32 bit versions work the same way.

Butn1Proc proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD

    .switch uMsg
      .case WM_LBUTTONUP
        rcall SendMessage,hButn1,BM_SETIMAGE,IMAGE_BITMAP,bImg1

      .case WM_LBUTTONDOWN
        rcall SendMessage,hButn1,BM_SETIMAGE,IMAGE_BITMAP,bImg2


    invoke CallWindowProc,lpButn1Proc,hWin,uMsg,wParam,lParam


Butn1Proc endp

There is a 32 bit subclassing tool in the MASM32 SDK that makes doing subclasses a lot easier and saves time.


Well, I got it to work without subclassing:

  • BCN_HOTITEMCHANGE tells me when the mouse enters or leaves the button's client area;
  • BN_CLICKED tells me when the user pushes the button *
  • BN_UNPUSHED tells me when the user stops pushing the button
BTW, BN_PUSHED doesn't work at all.

* One annoyance is that the "pushed" state doesn't show until the user clicks and then lets go of the mouse button. I'm guessing that your method works better. However, this isn't too bad. If you were a customer of mine, would you accept this behavior in your product?
Assembly language programming should be fun. That's why I do it.


Quote from: NoCforMe on August 06, 2022, 09:58:53 AMIf you were a customer of mine, would you accept this behavior in your product?

Looks perfect :thumbsup:

For inspiration I enclose some old tests.


Hutch: You were right. Your method works much better. I went ahead and subclassed the button. Now the subclass proc takes care of the button-down and button-up states, while the parent (dialog proc) handles the mouse-over state. Works well.

I don't understand why folks have so much trouble with subclassing. Once you understand it it's easy! No need for any package to do it for you, just

  • Define a proc to handle the subclassed window
  • Use SetWindowLong(GWL_WNDPROC) to do the magic

Easy peasy.
Assembly language programming should be fun. That's why I do it.