I want to prevent a window from being moved between monitors by checking for the message WM_MOVE and using the SetWindowPos function to keep the window within the bounds of the display. When I try to do this, the window briefly flashes where the mouse is and snaps to a small area on the bottom of the screen. I'm not sure why this is happening, since the code is just like any other collision detection:
case WM_MOVE:
{
int nX = (int)(short)LOWORD(lParam);
int nY = (int)(short)HIWORD(lParam);
if (nX < pDisplayDevice->getLeft()) {
nX = pDisplayDevice->getLeft();
} else if (nX + int(uNormalWidth) > pDisplayDevice->getRight()) {
nX = pDisplayDevice->getRight() - int(uNormalWidth);
}
if (nY < pDisplayDevice->getTop()) {
nY = pDisplayDevice->getTop();
} else if (nY + int(uNormalHeight) > pDisplayDevice->getBottom()) {
nY = pDisplayDevice->getBottom() - int(uNormalHeight);
}
SetWindowPos(hWnd, 0, nX, nY, uNormalWidth, uNormalHeight, 0);
}
break;
pDisplayDevice is basically a pointer to a Rect that contains the coordinates of the display, and uNormalWidth/uNormalHeight are the width and height of the window in windowed mode.
WM_MOVE
lParam The x and y coordinates of the upper-left corner of the client
area of the window. The low-order word contains the x-coordinate while
the high-order word contains the y coordinate.
Each time you enter WM_MOUSE, you Move your windows +8 pixels to the right and +30 pixels to the bottom (no menu in my code). That's the Width of the left sizing border and the height of the top sizing border + Title bar.
That move triggers a recursive chain of WM_MOVE processing, eventually ending up with some coords.
What you could do:
1. Follow Jonathan' advice. WM_MOVE is not the message you are looking for, it's WM_WINDOWPOSCHANGING.
2. Use the NON-client coordinates:
int nX = (int)(short)LOWORD(lParam);
int nY = (int)(short)HIWORD(lParam);
RECT rect;
GetWindowRect( hWnd, &rect );
nX = rect.left;
nY = rect.top;
if (nX < pDisplayDevice->getLeft()) {
[...]
Related
I have refereed below article to draw a custom frame area with DWM.
Custom Window Frame Using DWM
After removing the standard frame, non client area is not exist in the frame.
void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
int nTHight = 30; /*The title bar height*/
RECT * rc;
RECT aRect;
RECT bRect;
RECT bcRect;
if(bCalcValidRects == TRUE)
{
CopyRect(&aRect,&lpncsp->rgrc[1]);
CopyRect(&bRect,&lpncsp->rgrc[0]);
bcRect.left = bRect.left;
bcRect.top = bRect.top - nTHight;
bcRect.right = bRect.right;
bcRect.bottom = bRect.bottom;
CopyRect(&lpncsp->rgrc[0],&bcRect);
CopyRect(&lpncsp->rgrc[1],&bRect);
CopyRect(&lpncsp->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lpncsp;
rc->left = rc->left;
rc->top = rc->top - nTHight;
rc->right = rc->right;
rc->bottom = rc->bottom;
}
CFrameWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
Because the entire window is client region, I have to adjust the UI control placement for the frame, but I don't know how to handle this problem.
For example, below red rectangle (all UI component) should be shifted into the original coordinate of the client area before removing the non client part.
CWnd::GetWindowRect gives you the rectangle of the window on screen. The dimensions of the caption, border, and scroll bars, if present, are included.
CWnd::GetClientRect gives you the client rectangel of the window. The left and top members will be 0. The right and bottom members will contain the width and height of the window.
CWnd::ScreenToClientand CWnd::ClientToScreen calculate a point or rectangle from the client area to screen coordinates and back to screen.
AdjustWindowRect calculates the required window rectangle, based on the client rectangle of the window.
Here is afunction which calcualtes the margins of a window:
void CalculateWndMargin( const CWnd &wnd, int &leftM, int &rightM , int &topM, int &bottomM )
{
CRect wndRect;
wnd.GetWindowRect( wndRect );
CRect screenRect;
wnd.GetClientRect( screenRect );
wnd.ClientToScreen( screenRect );
leftM = screenRect.left - wndRect.left;
rightM = wndRect.right - screenRect.right;
topM = screenRect.top - wndRect.top;
bottomM = wndRect.bottom - screenRect.bottom;
}
I'm currently working on project which will have two RichEdit controls one close to the other: let's say RichEdit1 is on left and RichEdit2 is on the right.
The user scenario I want to enable in the project is:
User mouse LButton down at somewhere in RichEdit1, e.g. before the 3rd char, in total 7 chars.
User drag the mouse to RichEdit2, e.g. after the 6th char, in total 11 chars.
User mouse LButton up.
I want to see both RichEdit1 3rd char to end and RichEdit2 begin to 6th char are selected.
Currently I notice that once mouse LButton down on RichEdit1, after I move the mouse to RichEdit2, the RichEdit2 could not receive mouse event before I release mouse.
Any suggestion will be appreciated. Thank you!
When the mouse button is pressed down on RichEdit1, it captures the mouse, thus subsequent mouse messages are sent to RichEdit1 until the mouse button is released. That is why RichEdit2 does not receive any mouse events while dragging over RichEdit2.
You will have to process the mouse move messages in RichEdit1 and check if their coordinates are outside of RichEdit1's client area. If so, convert them into coordinates relative to RichEdit2's client's area and then send EM_SETSEL/EM_EXSETSEL messages to RichEdit2 as needed. For example:
int RichEdit2StartIndex = -1;
...
// in RichEdit1's message handler...
case WM_MOUSEMOVE:
{
if ((wParam & MK_LBUTTON) == 0)
break;
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
RECT r;
GetClientRect(hwndRichEdit1, &r);
if (xPos < (r.right - r.left))
{
if (RichEdit2StartIndex != -1)
{
SendMessage(hwndRichEdit2, EM_SETSEL, -1, 0);
RichEdit2StartIndex = -1;
}
}
else
{
POINT pt;
pt.x = xPos;
pt.y = yPos;
MapWindowPoints(hwndRichEdit1, hwndRichEdit2, &pt, 1);
POINTL pl;
Pl.x := pt.x;
Pl.y := pt.y;
int idx = SendMessage(hwndRichEdit2, EM_CHARFROMPOS, 0, (LPARAM)&Pl);
if (idx != -1)
{
if (RichEdit2StartIndex == -1)
RichEdit2StartIndex = idx;
SendMessage(hwndRichEdit2, EM_SETSEL, RichEdit2StartIndex, idx);
}
}
break;
}
Vice versa when dragging a selection from RichEdit2 to RichEdit1.
And make sure that both RichEdit controls have the ES_NOHIDESEL style applied so you can see the selection in both controls at the same time.
I am trying to make a 3 x 3 grid with a black pen on a window. however I want it to be centered, for example that my grid is inside a white space,
10% of top, right, left and bottom. and my grid will fit in the remaining 80% even when we resize the window.
Now I could make the grid but after several attempts to create the 10% area, got frustrated.
case WM_SIZE:
//get the 10% range.
cxInvalid = LOWORD(lParam) * 0.1;
cyInvalid = HIWORD(lParam) * 0.1;
//get the grid, DIVISIONS = 3
cxBlock = LOWORD(lParam) / DIVISIONS;
cyBlock = HIWORD(lParam) / DIVISIONS;
return 0;
Thanks in advaced :)
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (x = 0; x < DIVISIONS; x++)
for (y = 0; y < DIVISIONS; y++)
{
Rectangle(hdc, x * cxBlock, y * cyBlock,
(x + 1) * cxBlock, (y + 1) * cyBlock);
}
EndPaint(hwnd, &ps);
return 0;
This is exactly the sort of problem for which Windows mapping modes are intended to be used. For the moment I'm going to assume that you want your grid to remain square, regardless of the shape of the window it's in.
One way to do that is to switch from the default MM_TEXT mapping mode to the MM_ISOTROPIC mapping mode (but if we want the grid to change shape with the surrounding window, we'd use MM_ANISOTRCOPIC instead).
Using that, we can set our window as a virtual grid of, say, 1200 x 1200 cells, and then draw our 3x3 grid on that. I've chosen 1200 x 1200 so the part we care about will be a nice, convenient 1000 x 1000 grid.
// set up the mapping mode:
RECT rect;
GetClientRect(hWnd, &rect);
SetMapMode(hDC, MM_ISOTROPIC);
SetViewportExt(rect.x, rect.y);
// The virtual width/height for our window:
static const int width = 1200;
static const int height = 1200;
SetWindowExt(width, height);
SetWindowOrg(-100, -100); // Set the virtual 0 point ~10% of the way into the window.
// And then draw the grid. We always draw in a 1000 x 1000 grid, and Windows
// scales that to the actual window size for us.
//
static const int grid_size = 1000;
static const int step = grid_size / 3;
for (int i = step; i < grid_size-1; i += step) {
MoveTo(hDC, i, 0);
LineTo(hDC, i, grid_size);
MoveTo(hDC, 0, i);
LineTo(hDC, grid_size, i);
}
To reiterate the difference between MM_ISOTROPIC and MM_ANISOTROPIC, here are screen shots of the grid. First as it's drawn with MM_ISOTROPIC:
...and then as it's drawn with MM_ANISOTROPIC:
I'm trying to get the x and y coordinates of a specific window relative to the screen (e.g. If the window's position on the screen is (100, 300) then I should retrieve an x-coordinate of 100 and a y-coordinate of 300). How can I achieve this so that I can assign the coordinates to some variables?
int x = /*Get x-coordinate*/;
int y = /*Get y-coordinate*/;
On Vista and later with Aero glass enabled, you have to use DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) to account for glass padding.
Otherwise, you can use GetWindowRect() instead, which does not account for glass padding.
RECT rect;
GetWindowRect(window, &rect);
int x = rect.left;
int y = rect.top;
If console aplication starts and system creates console window for it, but sometimes this window is created in such coordinates that some of it's contents slide out of right screen edge. Then the user must use mouse to show everything.
How to cope with that ?
What functions use to detect upper right corner coordinates of console window ?
Then I will be able to check if it is outside the screen and move the window just the distance that is needed.
What function use to move window ?
Or maybe there is all in one solution to prevent window from moving outside the screen ?
Here's a fully multi-monitor aware and taskbar aware implementation that does what you describe.
#include <Windows.h>
int main()
{
ClampConsoleToScreen();
return 0;
}
void ClampConsoleToScreen()
{
HWND window = GetConsoleWindow();
RECT windowRect;
GetWindowRect(window, &windowRect);
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO mi;
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
GetMonitorInfo(monitor, &mi);
int adj, any;
adj = 0;
any = 0;
if (windowRect.right > mi.rcWork.right)
{
// Get negative adjustment value to move it left onto screen
adj = mi.rcWork.right - windowRect.right;
}
if (windowRect.left < mi.rcWork.left)
{
// Get positive adjustment value to move it right onto screen
adj = mi.rcWork.left - windowRect.left;
}
windowRect.left += adj;
windowRect.right += adj;
any |= adj;
adj = 0;
if (windowRect.bottom > mi.rcWork.bottom)
{
// Get negative adjustment value to move it up onto screen
adj = mi.rcWork.bottom - windowRect.bottom;
}
if (windowRect.top < mi.rcWork.top)
{
// Get positive adjustment value to move it down onto screen
adj = mi.rcWork.top - windowRect.top;
}
windowRect.top += adj;
windowRect.bottom += adj;
any |= adj;
if (any)
{
MoveWindow(window,
windowRect.left,
windowRect.top,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top, TRUE);
}
}