I am trying to write a windowprocedure that would call the animation of a rectangle in the window only when the start button is clicked and stop when the stop button is clicked.
I tried doing this like this:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (wParam)
{
case BUTTON_START:
stopClicked = false;
DestroyWindow(hStartButton);
CreateStopButton(hWnd);
Animate(hWnd);
return 0;
case BUTTON_STOP:
stopClicked = true;
DestroyWindow(hStopButton);
CreateStartButton(hWnd);
return 0;
}
case WM_CREATE:
AddMenus(hWnd);
CreateStartButton(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
the Animate function:
void Animate(HWND hWnd)
{
HDC hdcWnd = GetDC(hWnd);
while(!stopClicked)
{
//drawing code
}
ReleaseDC(hWnd, hdcWnd);
DeleteDC(hdcWnd);
}
The program crashes as it never exist the while(!stopClicked) loop.
My question is how to make that possible that the animation would stop on a button click?
Your application hanged, bucause you are waiting for a flag to change and there is no way it will change.
WindowProcedure is called on an event, and until you leave it, any other event won't be processed.
What you need to do is to perform steps of animation on timer.
You need to setup a timer which will send you an event which you have to handle and there you can draw next frame of your animation.
Related
I've written a code that dynamically creates a POPUP style window when the user clicks inside my main app window. Now I'd like the POPUP window to be automatically destroyed when the mouse cursor goes out of the POPUP wnd region. I know that i have probably handle the WM_MOUSEMOVE message but how to do that? Please provide a simple code for that if You can...
Use the WM_MOUSELEAVE message instead. However, note that this message has to be explicitly requested via TrackMouseEvent(), which your window can call when it receives its first WM_MOUSEMOVE message.
As #Remy Lebeau said, the following is the code implementation.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL Tracing = FALSE;
switch (message)
{
case WM_MOUSELEAVE:
{
DestroyWindow(hWnd);
break;
}
case WM_MOUSEMOVE:
{
if (!Tracing)
{
Tracing = TRUE;
TRACKMOUSEEVENT tme{};
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
}
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
you can compare the event.target and event.currentTarget, if both are same then you are out side of popup window else in side the popup window.
I've got a C++ project in which I'm using the Winapi to develop a window with a button and I want to change the text of the button when it's being hovered. For example, changing "Click me" to "Click me NOW!", when hovered. I've tried searching but I've not found any good ways to do this.
I noticed that when user hovers, the WM_NOTIFY message is received, but I don't know how to ensure that it has been called by the mouse hover. I've found that I can use TrackMouseEvent to detect hovering, but it's limited to a period of time and I want to execute an action every time the user hovers the button.
Here is how I create a button:
HWND Button = CreateWindow("BUTTON", "Click me",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_NOTIFY,
20, 240, 120, 20,
hwnd, (HMENU)101, NULL, NULL);
And this my window procedure:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NOTIFY:
{
//??? Here is where I get a message everytime I hover the button, But I don't know any proper way to see if it has been executed by the button.
}
case WM_CREATE: //On Window Create
{
//...
}
case WM_COMMAND: //Command execution
{
//...
break;
}
case WM_DESTROY: //Form Destroyed
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Assuming you're using the common controls there is the BCN_HOTITEMCHANGE notification code for the WM_NOTIFY message. The message includes the NMBCHOTITEM structure, which includes information for whether the mouse is entering or leaving the hover area.
Here's an example:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NOTIFY:
{
LPNMHDR header = *reinterpret_cast<LPNMHDR>(lParam);
switch (header->code)
{
case BCN_HOTITEMCHANGE:
{
NMBCHOTITEM* hot_item = reinterpret_cast<NMBCHOTITEM*>(lParam);
// Handle to the button
HWND button_handle = header->hwndFrom;
// ID of the button, if you're using resources
UINT_PTR button_id = header->idFrom;
// You can check if the mouse is entering or leaving the hover area
bool entering = hot_item->dwFlags & HICF_ENTERING;
return 0;
}
}
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You can check the code of the WM_NOTIFY message to see if it is a NM_HOVER message.
switch(msg)
{
case WM_NOTIFY:
if(((LPNMHDR)lParam)->code == NM_HOVER)
{
// Process the hover message
}
else if (...) // any other WM_NOTIFY messages you care about
{}
}
You can use simply SFML to do this.
Code:
RectangleShape button;
button.setPosition(Vector2f(50, 50));
button.setSize(Vector2f(100, 40));
button.setFillColor(Color::Green);
if(button.getGlobalBounds().contains(static_cast<Vector2f>(Mouse::getPosition(/*your
window name*/window)
{
button.setFillColor(Color::Red);
}
I've a Button made using Win32Api that I want to be able to notify whenever the user put the mouse inside the button rectangle.
I noticed that when user does that the WM_NOTIFY is called but I don't know which flag to use for ensure that the user has the mouse inside it's area.
Here is my button:
HWND Button = CreateWindow("BUTTON", "Test",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_NOTIFY,
20, 240, 120, 20,
hwnd, (HMENU)101, NULL, NULL);
And my WndProc:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NOTIFY:
{
//??? Here is where I want to do it
}
case WM_CREATE: //On Window Create
{
wHWND = hwnd;
if (onCreate != NULL)
onCreate(hwnd);
break;
}
case WM_COMMAND: //Command execution
{
//...
break;
}
case WM_DESTROY: //Form Destroyed
{
if (onDestroy != NULL)
onDestroy(hwnd);
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I don't know if I'm in the right path using WM_NOTIFY or not, maybe there is an easier way to do that. Thank you!
Try catching the WM_SETFOCUS message instead if you want a generic way of tracking focus.
BN_SETFOCUS is sent as WM_COMMAND in the upper 16 bits of WPARAM (HIWORD):
The parent window of the button receives this notification code through the WM_COMMAND message
If you are not talking about focus but just the mouse position then you can use ChildWindowFromPointEx or RealChildWindowFromPoint and a timer.
Currently, I am creating my own function onPress and onRelease. However, I am having problem with my onRelease function. Apparently, my onRelease kept on triggering even if I have not release my keyboard.
I suspected it has to do with the number of cycle inside the CPU but I wasn't sure of this theory. Somehow, maybe the cycle is slower than my frame, that why the PeerMessage return false? As no event was triggered.
Solution to it:
**Under the WinProc function create a new case called WM_KEYUP. This event will trigger once the user leave the button. It help to solve the number of cycle inside the CPU issued.
**
*Note:
I have update my detail of my code.
Description. Window Programming
I have two std::array that store my keyboard data
1) InputCurr
2) InputPrev
std::array<char, 256> inputPrev;
std::array<char, 256> inputCurr;
While(TRUE) {
std::copy(InputCurr.begin(), InputCurr.end(), InputPrev.begin());
inputCurr.fill(0);
while(PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&uMsg);
DispatchMessage (&uMsg);
}
if(onReleased(x030)) //Button 0
//do something
}
char onReleased(char key)
{
return (inputCurr[key] && !inputPrev[key])? 1 : 0;
}
void VEInputMessage(WPARAM key)
{
inputCurr[key]= 1; //Set to true of the keyboard key
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC dc; /* device context */
PAINTSTRUCT ps; /* the paint struct */
RECT rect;
UNREFERENCED_PARAMETER(rect);
switch (msg)
{
/* when the window is created */
case WM_CREATE:
break;
/* when the rectangle is drawn */
case WM_LBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
case WM_PAINT:
dc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
/* When it's time for the window to be closed and removed */
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
VEINPUT::VEInputMessage(wParam); //Updated the input key
if(wParam == AEVK_ESCAPE)
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
I've created a formview using the Visual Studio resource editor but I can't get it to show.
The procedure to handle it's messages is this:
BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDC_BUTTONCancel:
EndDialog(hDlg,0);
return TRUE;
}
break;
}
return FALSE;
}
When a button is pressed in the main window I call:
DialogBox(hInst, MAKEINTRESOURCE(IDD_FORMVIEW), hwnd, (DLGPROC)DlgProc);
The main window freezes, but there is no dialog shown.
I'd appreciate some help. Thanks in advance.