Button in windows programming

Pages: 12
I'm writing a Windows program which contains some buttons (using C++ language) . The purpose of this program is that when I press a button, a sound will be on. But when I release that button, the sound will be off. I tried the WM_COMMAND but it doesn't work.The problem is although I released the button, the sound was still on forever . I also tried WM_LBUTTONDOWN and WM_LBUTTONUP but I don't know how to use them for my purpose. Can anyone help me to solve this problem?Thanks in advance
you need to catch wm_command for the button. it will not be a good idea to do mouse messages.
if you are not able to catch wm_command for button here is a small code.

lets say you button id is: BTN_LEFT.

1
2
3
4
5
6
case WM_COMMAND:
	switch(wParam)
	{
	case BTN_LEFT:
//		handle your button click here
	}
return true;

you may set a text like start/stop. on button click if the text is start then start the sound and make the text as stop. now on the second click the text will be stop, make the text start again and stop the sound.
Thanks for your response. However, you misunderstood my idea. I mean that if I keep the button pressed, there will be a sound.But if I release that button, the sound will immediately be off .One left mouse click includes 2 actions: press and release.
You want to hook into the buttons window procedure and handle the WM_LBUTTONDOWN/UP events.
Can you explain more how to hook into the buttons window procedure and handle those events?I don't know how to do that. Thanks
Depends on exactly what you want to do, but you could probably just do this. You have to save the button hwnd in a global variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    while (GetMessage (&msg, NULL, 0, 0))
    {
        if (msg.hwnd == hwndButton) {
            switch (msg.message) {
            case WM_LBUTTONDOWN:
                // start sound
                continue;
            case WM_LBUTTONUP:
                // stop sound
                continue;
            }
            // Allow other messages to fall through
        }
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

Thank you. I'm just a beginner of windows programming. I get some basic understanding about how to write a simple window and button. In your code, there are two variables which i don't understand.First, what is hwndButton and how to define it when I create a button. Second, what msg.message mean?and again how to define it in my code.Here is my code.



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

#include <windows.h>
 
HWND hwnd, simple_button, icon_button;
HINSTANCE hInstance;
HICON hIcon1; 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			LPSTR lpCmdLine, int nCmdShow )
{

  MSG  msg ;    
  WNDCLASS wc = {0};
  wc.lpszClassName = TEXT( "Static Control" );
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc ;
  wc.hCursor       = LoadCursor(0,IDC_ARROW);
  wc.hIcon          = LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);
 

 hwnd = CreateWindow( wc.lpszClassName, TEXT("Win32 Basic Window "),
                WS_OVERLAPPEDWINDOW,
                100, 100, 330, 270, 0, 0, hInstance, 0);  
 
 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);
 
 
  while( GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}
 

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
 
  switch(msg)
   {
   case WM_CREATE:
	    {
        button1 =   CreateWindow(TEXT("button"), TEXT("Button"),    
		             WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
		             80, 10, 100, 50,        
		             hwnd, (HMENU) buttonID, NULL, NULL);
       
        hIcon1 = LoadIcon (NULL, IDI_WARNING);
        SendMessage(icon_button,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon1);
 
	    break;
	}
 
    case WM_DESTROY:
       {
        PostQuitMessage(0);
        return 0;
       }
 
   }
 
 return DefWindowProc(hwnd, msg, wParam, lParam);
}





oh.. ok.. i though you are trying to get the button press...

what Hammurabi said may be called windows subclassing.. the idea is correct but there is a better way..
here hwndButton is the handle of button which will be created in windowproc, now to access it in winmain, one needs to make it global.. as the controls keeps on increasing globals also increase.. if the button is subclassed then there will be a separate function for each control which will be neat and clear.

read about SetWindowLong() and GWL_WNDPROC. you will get your answer.
Last edited on
This person is clearly not at the level where reading about SetWindowLong() will get them the answer. However, it is done like so:

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
WNDPROC  OldButtonProc;

LRESULT CALLBACK ButtonProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_LBUTTONDOWN:
        // start sound
        return 0;
    case WM_LBUTTONUP:
        // stop sound
        return 0;
    }
    return CallWindowProc (OldButtonProc, hwnd, msg, wp, lp);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_CREATE:
      HWND hwndButton = MAKE YOUR BUTTON HERE;

      OldButtonProc = (WNDPROC)
        SetWindowLong (hwndButton, GWL_WNDPROC, (LONG) ButtonProc);

      // ... 


Thanks for your help. I nearly got your code. However, when I compiled my code (after modifying), I got an error

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
#include <windows.h>

#include <soundfile.h>

HWND hwnd, hwndButton, icon_button;
HINSTANCE hInstance;
HICON hIcon1;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			LPSTR lpCmdLine, int nCmdShow )
{

  MSG  msg ;
  WNDCLASS wc = {0};
  wc.lpszClassName = TEXT( "Static Control" );
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc ; // error: undefined reference to `WndProc(HWND__*, unsigned int, unsigned int, long)@16'

  wc.hCursor       = LoadCursor(0,IDC_ARROW);
  wc.hIcon          = LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);


 hwnd = CreateWindow( wc.lpszClassName, TEXT("Win32 Basic Window "),
                WS_OVERLAPPEDWINDOW,
                100, 100, 330, 270, 0, 0, hInstance, 0);

 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);


  while( GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}

WNDPROC OldButtonProc;

LRESULT CALLBACK ButtonProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_LBUTTONDOWN:
        playsoundfile();
        return 0;
    case WM_LBUTTONUP:
        stopsoundfile();
        return 0;
    }
    return CallWindowProc (OldButtonProc, hwnd, msg, wp, lp);
}


LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{

  switch(msg)
   {
   case WM_CREATE:
	    {
        HWND hwndButton =   CreateWindow(TEXT("button"), TEXT("Button"),
		             WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
		             80, 10, 100, 50,
		             hwnd, (HMENU) buttonID, NULL, NULL);
        OldButtonProc = (WNDPROC) SetWindowLong (hwndButton, GWL_WNDPROC, (LONG) ButtonProc);


        hIcon1 = LoadIcon (NULL, IDI_WARNING);
        SendMessage(icon_button,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon1);

	    break;
	}

    case WM_DESTROY:
       {
        PostQuitMessage(0);
        return 0;
       }

   }

 return DefWindowProc(hwnd, msg, wParam, lParam);
}
I don't know what's wrong with WndProc.

You should replace this WNDCLASS wc = {0}; with this WNDCLASS wc = {sizeof(wc)};

And you should return 0 after handling WM_CREATE (don't break and pass control to the default window procedure).

And you have two of these lines wc.hCursor = LoadCursor (NULL, IDC_ARROW);
Last edited on
I changed my code as your suggestion.Then it's compiled successfully. But when I run this program, nothing happens except MS DOS windows. No window and button is created. The GUI seems to be fail. Can you check that code?
Read the Petzold and MSDN, as what you do is really basic (and it's not the right method to subclass..)
To george135: you said that what I've done is really basic, So can you help me to solve my problems?
Your problem sounds like you don't have the right project settings. Start a new project and make sure you choose a Windows Application.
I use Codeblock to write this program, and choose WIN32 GUI project for my project. I tried to create a new project but it can not solve the problem.
You haven't registered the class. Just before CreateWindow() put RegisterClass(&wc);
Hammurabi:


yeah.. thats what i was trying to say.. looks neat.. :)
due to lack of time these days.. i avoided writing the code.. :(
to Hammurabi: thanks a lot.You helped me to figure out my problems and solved it.

I have one more question: With this code, when I pressed the button, that button doesn't seem to be pressed, I meant the visual effect. That button should be down when you press the left mouse and then be up when you release the left mouse. It looks like the windows just recognize that you pressed the left mouse button into the region of that button instead of pressing the button in the GUI.
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
#include <windows.h>

#include <soundfile.h>

HWND hwnd, hwndButton, icon_button;
HINSTANCE hInstance;
HICON hIcon1;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			LPSTR lpCmdLine, int nCmdShow )
{

  MSG  msg ;
  WNDCLASS wc = {sizeof(wc)};
  wc.lpszClassName = TEXT( "Static Control" );
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc ; // error: undefined reference to `WndProc(HWND__*, unsigned int, unsigned int, long)@16'
  wc.hIcon          = LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);

 RegisterClass(&wc);
 hwnd = CreateWindow( wc.lpszClassName, TEXT("Win32 Basic Window "),
                WS_OVERLAPPEDWINDOW,
                100, 100, 330, 270, 0, 0, hInstance, 0);

 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);


  while( GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}

WNDPROC OldButtonProc;

LRESULT CALLBACK ButtonProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_LBUTTONDOWN:
        playsoundfile();
        return 0;
    case WM_LBUTTONUP:
        stopsoundfile();
        return 0;
    }
    return CallWindowProc (OldButtonProc, hwnd, msg, wp, lp);
}


LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{

  switch(msg)
   {
   case WM_CREATE:
	    {
        HWND hwndButton =   CreateWindow(TEXT("button"), TEXT("Button"),
		             WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
		             80, 10, 100, 50,
		             hwnd, (HMENU) buttonID, NULL, NULL);
        OldButtonProc = (WNDPROC) SetWindowLong (hwndButton, GWL_WNDPROC, (LONG) ButtonProc);


        hIcon1 = LoadIcon (NULL, IDI_WARNING);
        SendMessage(icon_button,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon1);

	    break;
	}

    case WM_DESTROY:
       {
        PostQuitMessage(0);
        return 0;
       }

   }

 return DefWindowProc(hwnd, msg, wParam, lParam);
}

In ButtonProc, change both instances of return 0; to break;. That way the original button proc will be able to respond to the messages as well.
Pages: 12