Sign in to follow this  
Death100

WM_LBUTTONDOWN

Recommended Posts

Death100    122
I know this isn't exactly a game, but I don't know any win32 specific forums, so here goes: I'm trying to make a music/movie player. I need to have some sort of slider to display where you are in the movie or music, so i'm making one, only i'm have a problem with WM_LBUTTONDOWN. My control doesn't detect it. But it does detect WM_NCLBUTTONDOWN (this is supposed to be sent when you aren't clicking on the client area of the control, right?), but only when you click on the control not in the window area. I don't know how to fix it... heres my control code:
class SLIDER {
      public:
      //functions to initialize slider
      SLIDER(bool i);
      
      //functions for callback func
      static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
      
      LRESULT paint(WPARAM wParam, LPARAM lParam);
      
      private:
      //variables to control control
      HWND hwnd; //you never know when you might need it
      COLORREF bg; //the background
      COLORREF Scol; //color of the slider
      float pos; //position (percentage) of the slider
      RECT rect;
}; //classes need semi colons at the end =)

SLIDER::SLIDER(bool i) {
               if (i != false) {
                   WNDCLASSEX wc;
                     
                   //fill it in
                   wc.cbSize = sizeof(wc);
                   wc.lpszClassName = "slider";
                   wc.hInstance = GetModuleHandle(0);
                   wc.lpfnWndProc = WndProc;
                   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
                   wc.hIcon = 0;
                   wc.lpszMenuName = 0;
                   wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
                   wc.style = 0;
                   wc.cbClsExtra = 0;
                   wc.cbWndExtra = sizeof(SLIDER);
                   wc.hIconSm = 0;
                   
                   //now register
                   RegisterClassEx(&wc);
               }
}

LRESULT SLIDER::paint(WPARAM wParam, LPARAM lParam) {
        HDC dc;
        PAINTSTRUCT ps;
        int x;
        
        dc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        
        //drawing here
        x = rect.left + ((rect.right - rect.left) * (pos / 100));
        
        Rectangle(dc, x - 10, rect.top, x + 10, rect.bottom);
        
        EndPaint(hwnd, &ps);
        
        return 0;
}

/*-----------------------------Window Procedure------------------------------------*/
LRESULT CALLBACK SLIDER::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
                     //memory variable
                     SLIDER* memory = (SLIDER *)GetWindowLong(hwnd, 0);
                     
                     switch (message) {
                            case WM_NCCREATE:
                                 memory = new SLIDER(false);
                                 SetWindowLong(hwnd, 0, (LONG)memory);
                                 
                                 //fill in default vars
                                 memory->hwnd = hwnd;
                                 memory->bg = RGB(10, 20, 30);
                                 memory->Scol = (COLORREF)20;
                                 memory->pos = 50;
                                 
                                 return (memory != NULL);
                                 
                            case WM_PAINT:
                                 return memory->paint(wParam, lParam);
                            
                            case WM_LBUTTONUP:
                                 memory->pos += 1;
                                 InvalidateRect(hwnd, &memory->rect, false);
                                 UpdateWindow(hwnd);
                                 
                                 return 0;
                            
                            case WM_ERASEBKGND:
                                 //prevent flicker
                                 return 1;
                            
                            default:
                                    DefWindowProc(hwnd, message, wParam, lParam);
                     }
}
/*---------------------------------End----------------------------------------------*/

SLIDER slide(true);
[/code]

heres the bit where i use it:
[code]
/*----------------------------------
  This is PlayM Movie player source
  Version:      0.1
*/

//definitions
#include "resource.h"

//include standard library stuff
#include <windows.h> //guess?

#include <stdio.h> //file input/output

//controls
#include "controls.h"

//include wrapper for creation of the window
#include "wrapper.h"

//callback func
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
        static HWND slider;
        
        switch(message) {
                        //menu
                        case WM_COMMAND:
                             switch (LOWORD(wParam)) {
                                  //exit from menu
                                  case menu_exit:
                                       exit(0);
                                       
                        }
                        
                        //on create
                        case WM_CREATE:
                             //make controls
                             slider = CreateWindowEx(
                                      WS_EX_CLIENTEDGE,
                                      "slider",
                                      "slider",
                                      WS_VISIBLE | WS_CHILD,
                                      0, 0,
                                      100, 100,
                                      hwnd, NULL, GetModuleHandle(0), NULL);
                                      
                             if (slider == NULL) {
                                        MessageBox(NULL, "hello", "bs", MB_OK);
                             }
                             
                             break;
                        
                        //resize slider
                        case WM_SIZE:
                             SetWindowPos(slider, NULL, 0, HIWORD(lParam) - 20, LOWORD(lParam), 20, NULL);
                             break;
                             
                        //exit
                        case WM_CLOSE:
                             //bye
                             exit(0);
                             
                        //default
                        default:
                                DefWindowProc(hwnd, message, wParam, lParam);
        }
}

//main func
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmd, int show) {
    //make window
    if (!win.MakeWindow("MPLAY", hInstance, 200, 200)) {
                                 return 0;
    }
    
    //show it
    win.ShowWin(show);
    
    //handle messages
    while(GetMessage(&win.message, NULL, 0, 0) > 0) {
                                    TranslateMessage(&win.message);
                                    DispatchMessage(&win.message);
    }
}

any help would be much appreciated. Edit: please use source tags for large portions of code - .ED [Edited by - Emmanuel Deloget on March 2, 2007 4:01:57 AM]

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
Before I attempt to answer your question, the Win32 API provides a slider control: the Trackbar control

Anyway, you control isnt handling WM_LBUTTONDOWN because you dont have a WM_LBUTTONDOWN handler in your window procedure. Instead, you have a WM_LBUTTONUP handler.

Share this post


Link to post
Share on other sites
Death100    122
I know there is a standard control, i just wanted to learn how to make my own. it's not just WM_MOUSEBUTTONDOWN, any WM_LMOUSEBUTTONS don't work.

Share this post


Link to post
Share on other sites
neob    100
In the forums you can paste code by writing

source lang="cpp"]
// code here
/source]

Both source lang & /source need begging and ending braces [ ] so they work. Please don’t get offended for me telling you this. I find it easier for others to read the code when it’s like that.

Share this post


Link to post
Share on other sites
Death100    122
k, I didn't know that.

Has no-one encountered this problem before? Is it something to do with the RECT? I really want this to work...

Share this post


Link to post
Share on other sites
Fahrenheit451    498
I would agree with Colin Jeanne that you don't appear to have all the right button handlers in there. Typically you would do something like this for a button click and release:

case WM_LBUTTONDOWN: // Left button down
{
SetCapture(hWnd);
.... do whatever you must here ....
return 0;
}

case WM_LBUTTONUP: // Left button released
{
.... do whatever you must here ....
ReleaseCapture();
return 0;
}

Read up on Windows mouse input on MSDN

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput.asp

hth
F451

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
I also note that in your current posted code you change the pos member of the SLIDER class but in paint() you never do anything with that member. When you paint you are painting the exact same thing always.

Also, the call to UpdateWindow() is not necessary after InvalidateRect() as invalidating part of the window will automatically send a WM_PAINT message to the message queue.

Share this post


Link to post
Share on other sites
Endurion    5411
If you build your own control and want it to receive all kind of input you need to answer the call to WM_GETDLGCODE. Simply return DLGC_WANTALLKEYS and do not pass the message on to DefWindowProc.

Share this post


Link to post
Share on other sites
Death100    122
The pos var is a percentage:

i convert it to coords here:


x = rect.left + ((rect.right - rect.left) * (pos / 100));




it's nothing to do with the WM_PAINT, because it does work when i use WM_NCLBUTTONDOWN to catch the mouseclicks. WM_LBUTTONDOWN doesn't even get sent (i put a MessageBox() in it and it didn't show)

I was using this tutorial: [url]http://www.catch22.net/tuts/custctrl.asp[/url]

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
I misread that line, sorry.

Have you tried setting a breakpoint on your WM_LBUTTONDOWN handler?

As a completely unrelated note, I did notice this bug as well: you're allocating sizeof(SLIDER) bytes of extra window data but you're only storing sizeof(pointer) bytes. You should change this line

wc.cbWndExtra = sizeof(SLIDER);

to

wc.cbWndExtra = sizeof(SLIDER *);

Share this post


Link to post
Share on other sites
Death100    122
if you meant:


case WM_LBUTTONDOWN:
memory->pos += 1;
InvalidateRect(hwnd, &memory->rect, false);

break;



didn't work...could it be something else in code i didn't show?

my windows wrapper class:

//function defs
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

class window
{
public:
//window class to fill
WNDCLASSEX wc;

//messages to handle
MSG message;

//handle for window
HWND hwnd;

//functions now
bool MakeWindow(char *title, HINSTANCE hInstance, int sizeX, int sizeY) {

//fill in WNDCLASSEX
//Empty first =)
ZeroMemory(&wc, sizeof(wc));

//gogogogo
wc.cbSize = sizeof(wc);
wc.style = 0; //just so you can change it easily
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground= (HBRUSH)30;
wc.lpszMenuName = MAKEINTRESOURCE(menu);
wc.lpszClassName= "cool";

//register class
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, "Couldn't Register WNDCLASSEX", "ERROR - This is a Windows app after all", MB_OK);
return FALSE;
}

//phew...now we can make the window
hwnd = CreateWindowEx( //this is one long function!
0, //window style
"cool", //class name we used earlier
title, //caption at the top of the window
WS_OVERLAPPEDWINDOW, //type of window
CW_USEDEFAULT, CW_USEDEFAULT, //use default x and y positions
sizeX, sizeY, //size of window
NULL, NULL, hInstance, NULL); //Not sure Really..

//check wether we made a window or not
if (hwnd == NULL) {
MessageBox(NULL, "Couldn't make window", "ERROR", MB_OK);
return FALSE;
}
}

//show window
bool ShowWin(int show) {
//show and update the window
ShowWindow(hwnd, show);
UpdateWindow(hwnd);
}

private:

};

window win;



my whole main.cpp

/*----------------------------------
This is PlayM Movie player source
Version: 0.1
*/


//definitions
#include "resource.h"

//include standard library stuff
#include <windows.h> //guess?

#include <stdio.h> //file input/output

//controls
#include "controls.h"

//include wrapper for creation of the window
#include "wrapper.h"

//callback func
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static HWND slider;

switch(message) {
//menu
case WM_COMMAND:
switch (LOWORD(wParam)) {
//exit from menu
case menu_exit:
exit(0);

}

//on create
case WM_CREATE:
//make controls
slider = CreateWindowEx(
WS_EX_CLIENTEDGE,
"slider",
"slider",
WS_VISIBLE | WS_CHILD,
0, 0,
100, 100,
hwnd, NULL, GetModuleHandle(0), NULL);

if (slider == NULL) {
MessageBox(NULL, "hello", "bs", MB_OK);
}

break;

//resize slider
case WM_SIZE:
SetWindowPos(slider, NULL, 0, HIWORD(lParam) - 20, LOWORD(lParam), 20, NULL);
break;

//exit
case WM_CLOSE:
//bye
exit(0);

//default
default:
DefWindowProc(hwnd, message, wParam, lParam);
}
}

//main func
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmd, int show) {
//make window
if (!win.MakeWindow("MPLAY", hInstance, 200, 200)) {
return 0;
}

//show it
win.ShowWin(show);

//handle messages
while(GetMessage(&win.message, NULL, 0, 0) > 0) {
TranslateMessage(&win.message);
DispatchMessage(&win.message);
}
}



maybe it's something to do with my wrapper class, that doesn't let controls work properly?

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
What I meant was, did you put a breakpoint in your WM_LBUTTONDOWN handler and did you hit it with your debugger?

With the exception of this line

wc.hbrBackground= (HBRUSH)30;

you window wrapper looks fine. Please use one of the defined constants rather than a magic number. Nobody knows what brush 30 is or even if it is a brush at all. However, I dont think the above is the cause of the problem.

Share this post


Link to post
Share on other sites
Endurion    5411
Erm, did you try to handle WM_GETDLGCODE as i mentioned above? I'm 99% sure that this is the problem. Normal user controls do simply not receive all the input/mouse messages without telling windows that you want them.

Share this post


Link to post
Share on other sites
Death100    122
To Endurion:
yep, no change unfortunatley...

To Collin:
Oh, sorry i didn't know what you meant. Dev C++'s debugger doesn't say anything...

by the way (HBRUSH)30 is a cool blue =)

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
I'm stumped right now. If you post a link to the full source of your project (or better, a small example which demonstrates the problem) I can try looking at it later this week.

As for the brush thing, (HBRUSH)30 is cool blue on your computer at this time. It will not be that color on many other computers or even on your computer in the future. 30 is the number representing the brush COLOR_MENUHILIGHT. If you want a blue brush I suggest creating one using CreateSolidBrush().

Share this post


Link to post
Share on other sites
Endurion    5411
The project you uploaded there receives WM_LBUTTONDOWN fine. One major problem though is the placing of DefWindowProc. The guy who put it this way in his tutorial needs to be shot.
Any message you handle will not be passed on to DefWindowProc. And you also don't return any value if you do. But you have to.

When you break out of WM_LBUTTONDOWN (or any other handled function) the message doesn't get passed on to DefWindowProc. Remove the default case and put return DefWindowProc at the end of the function.

The same goes for your main windows WndProc.

I compiled your project with Visual Studio. I did have a double resource entry though, as i included both .rc files first.

Also, your ShowWin function doesn't return anything. Your compiler should be spitting out warnings about this!

Share this post


Link to post
Share on other sites
Death100    122
YAY YAY YAY YAY YAY YAY YAY THANKYOU!! It works when I replaced defWindowProc, like you showed. I'll need to keep that in mind for all my window projects.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this