Adding an Icon to a Button

Pages: 12
Hi, I'm using Win32 C++ and want to add an Icon to the button, I have came up with this code which should but doesn't work:

//Creating the button:

HWND button = CreateWindowEx (
BS_ICON,
"BUTTON",
WS_CHILD | WS_VISIBLE,
0, 0,
100, 50,
hwnd,
(HMENU)buttonid,
NULL,
NULL,
);

SendMessage (button, BM_SETIMAGE, IMAGE_ICON, IDI_APPLICATION);

After I do this, the button disappears completely. I have also tried the LoadIcon function but that didn't do any help either. Any help would be appreciated.
Where is the button style ?
(BS_PUSHLIKE or other)
In this thread I have given explicit instructions on how to add an image to an icon --

http://cplusplus.com/forum/windows/50741/
Thanks for your help, Lamblion but it didn't work. I tried what you said but it didn't change anything. I don't know what my mistake is, so if you don't mind could you please post a code I could just copy so that it would work? I've done everything you said but it still disappears. This is the part of my code related to the button:

"main.c"

HWND button = CreateWindowEx (
BS_ICON,
"BUTTON",
"GO",
WS_CHILD | WS_VISIBLE,
10, 30,
100, 20,
hwnd,
(HMENU)IDB_BUTTON,
NULL,
NULL
);
SendDlgItemMessage(hwnd,IDB_BUTTON,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)LoadImage(NULL,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,25,25,NULL));

//note: the two lines above are connected but they wouldn't fit in one line here...

"resource.h"

#define IDI_ICON 100
PUSHBUTTON "", IDB_BUTTON, 10, 10, 25, 25, BS_ICON

"resource.rc"

IDI_ICON ICON DISCARDABLE "myicon.ico"

With all these codes it still doesn't work, and the button doesn't appear at all.

Could you please write a code which works in the way I wrote mine, please?

P.S. Sorry for being annoying but I've tried a lot to make it work
Have you declared a HANDLE to your icon? Doesn't look like it.

In your header file, i.e., your .h file ==
HANDLE hMyIcon;

In your functions --
1
2
3
4
5
6
7
const int icon_size=25;

hMyIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON,
	icon_size, icon_size, NULL);

SendlMessage(button,BM_SETIMAGE,
		(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);


If you still have problems, I would suggest scrapping the CreateWindow() for your button and just define it in your header file. As a matter of fact, you have already defined your button TWICE in your code above, once by CreateWindo() and the other in your resource file. I would delete the CreateWindow() and just leave it as is in the resource file. Of course, doing this means you will also in your header file above have to do this --

#define IDB_BUTTON 101

In that case you would do this:
SendDlgItemMessage(GetDlgItem(hwnd,IDB_BUTTON),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);
Last edited on
If I can get this work, here is an image of an app I created with icon buttons --

http://www.lamblion.net/image_dump/rme_screenshot.jpg
Here is your COMPLETE code. I KNOW this will work --

header.h
1
2
3
#define IDB_BUTTON 101
#define IDI_ICON 100
HANDLE hMyIcon;


resource.rc
1
2
3
IDI_ICON ICON "myicon.ico"

PUSHBUTTON "", IDB_BUTTON, 10, 10, 25, 25, BS_ICON


foo.cpp
1
2
3
4
5
const int icon_size=25;

hMyIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, icon_size, icon_size, NULL);

SendDlgItemMessage(GetDlgItem(hwnd,IDB_BUTTON),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);


This will work for sure.

Don't forget to do this in your cleanup before exiting --

DestroyIcon((HICON)hMyIcon);
Last edited on
I tried it and it STILL doesn't work. I'm really sorry that I have to ask so many questions but when I type in the code:
 
PUSHBUTTON "", IDB_BUTTON, 10, 10, 25, 25, BS_ICON


into the resource.rc file it says "Syntax Error" and nothing else.


You MUST REMOVE your CreateWindowEX() for your button. Do the code EXACTLY as I have displayed it above. Of course, you must make sure your HWND is the one in your function, and you must make sure you have done EXACTLY what I have showed you in the three files above, i.e., the .h, .rc., and .cpp file.

Is your PUSHUBTTON code in your RC file??? In your code above it is in your HEADER file. That is ENTIRELY wrong. It MUST be in your RESOURCE file.

Also, syntax errors don't alway point to where the error actually is. It could be in code before that. But if your PUSHBUTTON statement is in your header file instead of your resource file, then that's your problem.

As I said, get rid of your CreateWindow() button COMPLETELY and follow my code with the corresponding files EXACTLY.

EDIT: Also, you must use #include in your resource file to access the #defines in your header file.
Last edited on
@Lamblion, better use LR_SHARED flag as last argument to LoadImage() and let Windows automatically destroy the handle for you.
Do you read answers ?!

Where is the button style ? (2)
(BS_PUSHLIKE or other)
Thanks, modoran. I didn't know that. That will save me a lot of DestroyIcon() statements in my cleanup in several of my apps.
Yes, I did put the PUSHBUTTON in the resource (.rc) file and I did #include the header file but it still gives me an error. BTW, the PUSHBUTTON has nothing before it (except for the #includes). Also, when I use the code:
SendDlgItemMessage(GetDlgItem(hwnd,IDB_BUTTON),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyyIcon);
It says "too few arguments to SendDlgItemMessageA" which I don't know where the A came from.
I also did get rid of the CreateWindowEx() function but it didn't make any difference.

Anyway, just to finish this sooner could you please send me a project file (dev preferably) to this e-mail:

ali.d.hosseini@gmail.com

or if you have a website or something, you can put it there.

Thanks,


If you use the code EXACTLY as I have posted it above, then it will work. You need to just create a clean project with a simple window, and you need to put the EXACT CODE in the EXACT SAME FILES as I showed you above. You don't have to name the file header.h or resource.rc or foo.cpp, but YOU DO, YOU MUST put the statements EXACTLY as they are written EXACTLY in the appropriate file, in EXACTLY the order I showed you.

You have to put the appropriate statements I showed you above in the appropriate HEADER file; you have to put the appropriate statements in the appropriate RESOURCE file IN THE RIGHT ORDER as I showed you; you have to put the appropriate statements in the appropriate CPP file in the appropriate functions as I showed you.

As I said, I do this ALL THE TIME with the EXACT SAME CODE. Once again, here is an example of an app I've created with button icons --

http://www.lamblion.net/image_dump/rme_screenshot.jpg

You are clearlly not following the instructions. Create a clean project and follow the instructions EXACTLY.

The ONLY change you might make is the one modoran showed me. That is the ONLY change you should make, if you are going to make any changes at all. If you do make that change, then don't call DestroyIcon() in your cleanup.
Last edited on
Actually, it has occured to me that you may be having problems with your PUSHBUTTON code because you are trying to use it nakedly in a regular window.

In your WinMain() function, instead of using CreateWindow() use CreateDialog(), like this --

hwnd=CreateDialog(hInstance, szClassName, 0, NULL);

Of course, you must create the code for your dialog box in your resource file for this to work, and you may not know how to do all of this.

In that case, do NOT put the PUSHBUTTON code in your resource file and DO create the button with CreateWinowEx(), just as you did at first. Also, do NOT use CreateDialog() as noted above, but just do your regular window procedure.

This may very well be your problem. Just remember to use the proper ID for your button in the HMENU argument in CreateWindowEx()

The fact that you got the syntax error in the PUSHBUTTON statement makes me think this could be the culprit.
Last edited on
I tried your codes again in a new project and this time it did make a difference, but still it had a problem. It didn't give me an error (so far) about the PUSHBUTTON, but it still says "too few arguments to function 'LONG SendDlgItemMessage ... '

If you know a way that could fix that, there will (probably) be no more problems.

Thanks & sorry for taking your time,
You need to post the EXACT code with regard to that statment. Make sure your sytax is correct, that you have the parenthesis in the proper place, with the commas in their proper place, and also I need to know WHERE in your code you are placing this statement. Just paste the whole function code that contains that statement here, but use the code tags to the right of this box so that your code reads in blue like mine above. It's much easier for me to read that way.
Last edited on
Oh, OK, here's my foo.cpp code (new project):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <windows.h>
#include "header.h"

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );
           
           HWND button = CreateWindowEx (
                               BS_ICON,
                               "BUTTON",
                               "Go",
                               WS_CHILD | WS_VISIBLE,
                               0, 0,
                               100, 100,
                               hwnd,
                               (HMENU)IDB_BUTTON,
                               NULL,
                               NULL
                               );
    const int icon_size=25;

hMyIcon=LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, icon_size, icon_size, NULL);

SendDlgItemMessage(GetDlgItem(hwnd,IDB_BUTTON),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);


    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
             
break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}


I also tried the codes you gave me for this file in the WM_CREATE case of the windowProcedure function but it didn't make any difference. The header and resource files are all exactly like your ones (they have the includes).
First, I would put the LoadImage() statement and the SendDlgItemMessage() and the CreateWindow() "button" in the WM_CREATE case in your CALLBACK prodecure.

Also, I am assuming you have #defined your IDB_BUTTON, your icons, etc., as well as I am assuming you have declared your HANDLE hMyIcon in your header file as well.

Secondly, instead of SendDlgItemMessage(), since your are creating the button dynamically and calling its HWND button, I think you should probably use INSTEAD of SendDlgItemMessage(), you would do this --

SendMessage(button,BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);

Give that a try and see what happens.

Also, experiment with return TRUE; in your WM_CREATE statement and return FALSE;

I sometimes have problems with that depending on what else is going on in my code. Place the WM_CREATE case statement BEFORE your WM_DESTROY case statement.
Last edited on
SendDlgItemMessage() takes 5 arguments, not 4 as in your code.
This is wrong:
SendDlgItemMessage(GetDlgItem(hwnd,IDB_BUTTON),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);

This is right:
SendDlgItemMessage(hwnd,IDB_BUTTON, BM_SETIMAGE, (WPARAM)IMAGE_ICON,(LPARAM)hMyIcon);

Not need for GetDlgItem() also (it is internally called by SendDlgItemMessage).
Last edited on
Pages: 12