How do I implement dragging a window using its client area? - c++

I have a Win32 HWND and I'd like to allow the user to hold control and the left mouse button to drag the window around the screen. Given (1) that I can detect when the user holds control, the left mouse button, and moves the mouse, and (2) I have the new and the old mouse position, how do I use the Win32 API and my HWND to change the position of the window?

Implement a message handler for WM_NCHITTEST. Call DefWindowProc() and check if the return value is HTCLIENT. Return HTCAPTION if it is, otherwise return the DefWindowProc return value. You can now click the client area and drag the window, just like you'd drag a window by clicking on the caption.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if (hit == HTCLIENT) hit = HTCAPTION;
return hit;
}
// etc..
}

Sorry for being a little late to answer but here is the code you desire
First you declare these global variables:
bool mousedown = false;
POINT lastLocation;
bool mousedown tells us if user is holding left button on their mouse or not
Then in callback funtion you write these lines of code
case WM_LBUTTONDOWN: {
mousedown = true;
GetCursorPos(&lastLocation);
RECT rect;
GetWindowRect(hwnd, &rect);
lastLocation.x = lastLocation.x - rect.left;
lastLocation.y = lastLocation.y - rect.top;
break;
}
case WM_LBUTTONUP: {
mousedown = false;
break;
}
case WM_MOUSEMOVE: {
if (mousedown) {
POINT currentpos;
GetCursorPos(&currentpos);
int x = currentpos.x - lastLocation.x;
int y = currentpos.y - lastLocation.y;
MoveWindow(hwnd, x, y, window_lenght, window_height, false);
}
break;
}

Related

How to detect mouse cursor is outside a windows?

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.

WM_PAINT based on button click

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.

Visual Studio 2008 MFC drag dialog without title and detect all mouse events

I'm asked to add new feature to an existing program. The program consists of a dialog without title/border. I need couple of things:
When the user simply clicks inside the dialog area, just close it;
Move the dialog when the user mouse-down inside its area and drag
Here's what I found so far:
void MyDialog::onMessageReceived(UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_LBUTTONDOWN:
lastX=LOWORD(lParam);
lastY=HIWORD(lParam);
SendMessage(DlgHandle, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
break;
case WM_LBUTTONUP:
if (LOWORD(lParam)==lastX && HIWORD(lParam)==lastY)
onKillButtonClick();
break;
}}
EDIT:
This function is called in this way:
INT_PTR CALLBACK MyDialog::dialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_this->onMessageReceived(uMsg, wParam, lParam);
}
Moving the window works very well, but looks like the WM_LBUTTONUP event is lost. I had to click twice to get it fired.
Hope someone can help me...
EDIT:
Using Spy++ I saw that WM_LBTTONUP is fired, but immediately after a new WM_NCLBUTTONDOWN is emitted.
First, I agree with Michael Walz - this is a very confusing behavior: the processing of the mouse up event depends on whether or not it has moved... What if it moved just a little bit? I would much rather dismiss this dialog with a different action - click on the icon, right-click, etc.
However, the correct way to let the user move your captionless window is to process WM_NCHITTEST message and return HTCAPTION:
case WM_NCHITTEST:
SetWindowLong(hDlg, DWL_MSGRESULT, HTCAPTION);
return HTCAPTION;
Unfortunately, Windows then will take over all mouse events, so, as you observed, you would never get WM_LBUTTONUP. You have an option to set a short timer and see if the user started to move your window; cancel it when you get WM_ENTERSIZEMOVE message. If that timer fires - close your window. Yes, it's also awkward, but no more thatn your proposal.
Another way is to handle the move yourself:
static bool bDragging(false), bMoved(false);
static POINT pt1 = {}, pt2 = {};
static RECT r;
switch (message)
{
case WM_LBUTTONDOWN:
GetWindowRect(hDlg, &r);
pt1 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ClientToScreen(hDlg, &pt1);
bDragging = true;
bMoved = false;
break;
case WM_MOUSEMOVE:
if (bDragging)
{
pt2 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ClientToScreen(hDlg, &pt2);
if (pt2.x != pt1.x || pt2.y != pt1.y)
{
OffsetRect(&r, pt2.x - pt1.x, pt2.y - pt1.y);
SetWindowPos(hDlg, 0, r.left, r.top, 0, 0, SWP_NOSIZE);
pt1 = pt2;
bMoved = true;
}
}
break;
case WM_LBUTTONUP:
bDragging = false;
if (!bMoved)
PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
bMoved = false;
break;
}
return (INT_PTR)FALSE;

Creating child editable textbox window on firebreath plugin

Newbie to Winapi.Learnt the basics of winapi and tips of creating child window in firebreath plugin.
Searched tutorials,got answers.But don't know What Am i Doing wrong here? Following is my code>>My main objective is to create a textbox functioning like that in MSWord on aparent plugin(windowed firebreath plugin) window handle whereby I can edit,modify the text as well as move and resize the textbox.Also, I am not able to fire many events like WM_LBUTTONDOWN and more on the child window.
int WINAPI childwindow::LoadForm()
{
HWND pluginWnd=win->getHWND();
HINSTANCE pluginInstance = (HINSTANCE)GetWindowLong(pluginWnd, GWL_HINSTANCE);
HWND demoWnd = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"),TEXT("text to be written"),WS_CHILD|WS_VISIBLE|
ES_MULTILINE|ES_AUTOVSCROLL|ES_AUTOHSCROLL|WS_BORDER|WS_VSCROLL|WS_HSCROLL, 10, 10, 300, 100, pluginWnd, (HMENU)IDC_MAIN_EDIT, pluginInstance , NULL);
//SUBCLASSING=============REFERENCE>>(http://cboard.cprogramming.com/windows-programming/148771-subclassing-edit-box.html)
PreviousSubclassedEditProc=(WNDPROC)GetWindowLong(demoWnd, GWL_WNDPROC);//WNDPROC PreviousSubclassedEditProc;
SetWindowLong(demoWnd, GWL_WNDPROC,(LONG_PTR)&childwindow::CustomWinProc);
SetWindowText(demoWnd,_T("LALALA"));
//======================
ShowWindow(demoWnd, SW_SHOWNORMAL);
UpdateWindow(demoWnd);
return EXIT_SUCCESS;
}
LRESULT CALLBACK childwindow::CustomWinProc( HWND chWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
HWND textBoxInput,button,tempHandle=0;
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(chWnd, GWL_HINSTANCE);
switch(uMsg)
{
case WM_CREATE:
{
return 0;
break;
}
case WM_MOUSEACTIVATE:
{
SetFocus(chWnd);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_LBUTTONDOWN:
{
dragWindow = true;
tempHandle=SetCapture(chWnd);
break;
}
case WM_LBUTTONUP:
{
ReleaseCapture();
tempHandle=NULL;
dragWindow = false;
break;
}
case WM_MOUSEMOVE:
{
if(dragWindow==true)
{
RECT mainWindowRect;
POINT pos;
int windowWidth, windowHeight;
pos.x = (int)(short) LOWORD(lParam);
pos.y = (int)(short) HIWORD(lParam);
GetWindowRect(chWnd,&mainWindowRect);
windowHeight = mainWindowRect.bottom - mainWindowRect.top;
windowWidth = mainWindowRect.right - mainWindowRect.left;
ClientToScreen(chWnd, &pos);
SetWindowPos(chWnd, NULL, pos.x, pos.y, windowWidth,windowHeight, SWP_NOZORDER);
ShowWindow(chWnd,SW_SHOWNORMAL);
}
break;
}
case WM_KILLFOCUS:
{
LPCWSTR buffer[1024];
SendMessage(chWnd,
WM_GETTEXT,
sizeof(buffer)/sizeof(buffer[0]),
reinterpret_cast<LPARAM>(buffer));
break;
}
default:
{
return DefWindowProc(chWnd,uMsg,wParam,lParam);
}
}
return TRUE;
}
The above child window is being made on a parent windowed firebreath plugin handle.
I also want to get the text from the child textbox window.but that's not possible till I get this right.I saw one google grouptutorials and this which has helped me a lot to get the basics.But the above problem is bugging me from last day.
Any takers for this question?
You can't RegisterClass for "EDIT" and hope that your class will magically behave like an "Edit". You have two solutions:
First one: drop your Class Registration Code and use "Edit" (or WC_EDIT) as Class Name in CreateWindowEx.
Second One: use GetClassInfo to query the Windows "Edit" class informations, and use the Window Procedure from the class (lpfnWndProc) in place of DefWindowProc.
If you choose the fisrt solution, you can provide your own Window Procedure with subclassing:
As for moving/resizing a Child Window, provided that you have the hWnd, use either SetWindowPos or MoveWindow.

How do I properly move a window with a region?

I've just started looking into window regions, and I'm trying to create an elliptical window that I can move by dragging the client area. Unfortunately, when I drag the window, the window flashes back and forth from the ellipse to the normal window (as if I never called SetWindowRgn), and back, repeatedly and rapidly.
I read on MSDN that I have to call SetWindowRgn(nullptr);, then move the window, then reset the region, which I have already done in my code. I move the window by calling SetWindowPos with SWP_NOZORDER, SWP_NOSIZE, and SWP_NOREDRAW, and I've tried adding on all of SWP_NOSENDCHANGING, SWP_DEFERERASE, and SWP_NOCOPYBITS as well, to no avail.
Here's my window procedure, with emphasis on WM_MOUSEMOVE. I know it won't work if I release the button outside of the window; I was planning to deal with that after this worked. I also left out error checking. It's pretty obvious that the calls do work, though, because the window does move as I drag it.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static bool moving{};
switch (msg) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_LBUTTONDOWN: {
moving = true;
return 0;
}
case WM_LBUTTONUP: {
moving = false;
return 0;
}
case WM_MOUSEMOVE: {
static POINT old{0, 0};
if (moving) {
RECT r;
GetWindowRect(hwnd, &r);
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
RECT newPos;
newPos.left = r.left + x - old.x;
newPos.top = r.top + y - old.y;
SetWindowRgn(hwnd, nullptr, FALSE);
SetWindowPos(hwnd, nullptr, newPos.left, newPos.top, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW
);
SetWindowRgn(hwnd, CreateEllipticRgn(200, 200, 600, 400), FALSE);
}
old.x = GET_X_LPARAM(lParam);
old.y = GET_Y_LPARAM(lParam);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I've also tried calling ValidateRgn(hwnd, nullptr); at the end of WM_MOUSEMOVE, which doesn't change anything. As well, I've tried wrapping the DefWindowProc call in a condition that just returns 0 if moving is set in order to see whether it was just some other message being sent that was messing with it, but that resulted in the window doing nothing when dragged. I then applied that condition to WM_PAINT and WM_ERASEBKGND handlers, but that resulted in the same flickering problem when dragged.
In order to test it more easily, here's full code (just rudimentary window creation etc). Am I going about moving the window the right way? Is there some message or something that I should handle, but don't? This is happening on Window 7 Ultimate N.
A much easier way to handle the move logic is to handle the WM_NCHITTEST message, returning HTCAPTION. This makes Windows handle all the move logic for you.