how to use ScreenToClient in win32, not MFC? - winapi

As MSDN said
BOOL ScreenToClient(
_In_ HWND hWnd,
LPPOINT lpPoint
);
the ScreenToClient's second para is a pointer to POINT,
and PINT said by MSDN is
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT, *PPOINT;
it has only x and y. It's NOT like MFC ScreenToClient function, the para is a rect, and rect has width and height.
I am confused how to use win32 ScreenToClient function.

You can use MapWindowPoints() to convert a RECT in a single operation:
RECT r = ...;
MapWindowPoints(NULL, hWnd, (LPPOINT)&r, 2);

MFC actually has two methods, they're overloaded. One accepts a POINT structure, just like the Win32 function, the other accepts a RECT structure, both work the same way: it maps each point from screen-to-client.
If you have a RECT that you want to get client coordinates of without using MFC then just do it manually, like so:
RECT rect = GetMyRect();
POINT rectTL;
rectTL.x = rect.left;
rectTL.y = rect.top;
ScreenToClient( hWnd, &rectTL );
POINT rectBR;
rectBR.x = rect.right
rectBR.y = rect.bottom;
ScreenToClient( hWnd, &rectBR );
rect.left = rectTL.x;
rect.top = rectTL.y;
rect.right = rectBR.x;
rect.bottom = rectBR.y;

Note that RECT is
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
and looks like two consecutive POINTs in memory. Therefore you can do what the MFC source code does, which is approx. the following (don't have the MFC source in front of me right now):
::ScreenToClient(hWnd, (POINT*)&rect->left);
::ScreenToClient(hWnd, (POINT*)&rect->right);
which is not the cleanest thing from a C point of view, but those structures are bound to remain binary compatible.

Related

WinApi, disabling all controls in a rect area

Is there an api to disable all controls in a rect area?
I am trying to write something like that:
GetClientRect(hWnd, rect);
DisableControls(rect);
GetClientRect gets the client area (left and top are always 0), you need to use GetWindowRect to figure out where a child window is.
All child controls are in the client area and you can just disable the parent window and all children will also stop accepting input.
It does seem a little contrived to disable based on a rectangle instead of a list of known controls but I suppose it might be useful in some cases.
static BOOL CALLBACK DisableChildrenInRectProc(HWND hWnd, LPARAM Param)
{
RECT *pParentRect = (RECT*) Param, r, ir;
if (GetWindowRect(hWnd, &r) && IntersectRect(&ir, &r, pParentRect))
{
EnableWindow(hWnd, FALSE);
}
return TRUE;
}
HWND hWnd = ...
RECT r;
GetWindowRect(hWnd, &r);
r.bottom = r.top + (r.bottom - r.top) / 2; // In this example, only disable controls in the top half.
EnumChildWindows(hWnd, DisableChildrenInRectProc, (LPARAM) &r);
I don't believe there is one. Use EnumChildWindows, GetWindowRect and some coordinate mapping via ScreenToClient. For overlap testing you could use IntersectRect.

Rectangle manipulation is missing in Direct2D

Direct2D has D2D1_RECT_F
{
FLOAT left;
FLOAT top;
FLOAT right;
FLOAT bottom;
}
It's similar to GDI RECT structure except it uses float values.
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
GDI provides all those RECT manipulation functions like
BOOL IntersectRect(
_Out_ LPRECT lprcDst,
_In_ const RECT *lprcSrc1,
_In_ const RECT *lprcSrc2
);
BOOL SubtractRect(
_Out_ LPRECT lprcDst,
_In_ const RECT *lprcSrc1,
_In_ const RECT *lprcSrc2
);
I can't believe Direct2D doesn't provide similar functions for D2D1_RECT_F.
I guess I can create rectangular geometries and combine them any way I want but that's creating and allocating objects instead of doing simple math.
Or I guess I may just create my own versions of them.
Am I missing something? Thanks.
For IntersectRect, Direct2D has ID2D1Geometry::CompareWithGeometry which will determine the relationship between two geometries, that's will work for you. note, this function only return the relationship of the two geometries, such as overlap, contains, it will not return the intersection rectangle as what IntersectRect did.
For SubtractRect, Direct2D has no such function, you need to write it yourself.

Drawing (too slow) in WM_PAINT causes flicker?

I want to draw a lot of lines in the WM_PAINT message handler with the following code.
//DrawLine with double buffering
LRESULT CALLBACK CMyDoc::OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
std::vector<Gdiplus::Point> points;
std::vector<Gdiplus::Point>::iterator iter1, iter2;
HDC hdc, hdcMem;
HBITMAP hbmScreen, hbmOldBitmap;
PAINTSTRUCT ps;
RECT rect;
hdc = BeginPaint(hWnd, &ps);
//Create memory dc
hdcMem = CreateCompatibleDC(hdc);
GetClientRect(hWnd, &rect);
hbmScreen = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
hbmOldBitmap = (HBITMAP)SelectObject(hdcMem, hbmScreen);
//Fill the rect with white
FillRect(hdcMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
//Draw the lines
Gdiplus::Graphics graphics(hdcMem);
Gdiplus::Pen blackPen(Gdiplus::Color(255, 0, 0));
points = m_pPolyLine->GetPoints();
for (iter1 = points.begin(); iter1 != points.end(); iter1++) {
for (iter2 = iter1 + 1; iter2 != points.end(); iter2++)
graphics.DrawLine(&blackPen, *iter1, *iter2);
}
//Copy the bitmap from memory dc to the real dc
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
//Clean up
SelectObject(hdcMem, hbmOldBitmap);
DeleteObject(hbmScreen);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
return 0;
}
However, if the size of points exceed 20, the client rect just flicker. I think the reason is that Gdiplus::DrawLines is too slow.
Is there any method to solve the flicker problem?
Thanks.
The flickering may be caused by slow painting as well as by other things. In general, try/ensure the following:
Try to not rely on WM_ERASEBKGND message, i.e. return non-zero, or specify NULL in WNDCLASS::hbrBackground if possible. Often the paint method paints all the background of the dirty region, then there is no need to do the erasing.
If you need the erasing, it can often be optimized so that WM_ERASEBKGND returns non-zero, and the paint method then ensures the "erasing" by also painting areas not covered by the regular painted contents, if PAINTSTRUCT::fErase is set.
If reasonably possible, write the paint method so that it does not repaint the same pixels in one call. E.g. to make blue rect with red border, do not FillRect(red), then repainting inner part of it with FillRect(blue). Try to paint each pixel once as much as reasonably possible.
For complex controls/windows, the paint method may often be optimized to easily skip a lot of painting outside the dirty rect (PAINTSTRUCT::rcPaint) by proper organizing the control data.
When changing the control state, invalidate only the minimal required region of the control.
If it is not top-level window, consider using CS_PARENTDC. If your paint method does not rely on system setting clipping rectangle to the client rect of the control, this class style will lead to a somewhat better performance.
If you see the flickering on control/window resizing, consider to not using CS_HREDRAW and CS_VREDRAW. Instead invalidate the relevant parts of the control in WM_SIZE manually. This often allows to invalidate only smaller parts of the control.
If you see the flickering on control scrolling, do not invalidate whole client, but use ScrollWindow() and invalidate only small area which exposes the new (scrolled-in) content.
If everything above fails, then use double buffering.
Use double buffer. It is an offen problem with Win32 C++ application and specifically with OnPaint function and DC facilities.
Here is a few links to help you check if everything is fine with YOUR implementation of double buffer: Flicker Free Drawing In MFC and SO question "Reduce flicker with GDI+ and C++"
If your lines happen to extend outside the bounds of the DC (Graphics), Win32/GDI+ is painfully slow at clipping. Like, up to two orders of magnitude slower than rolling your own clipping function. Here is some C# code that implements Liang/Barsky - I scrounged this up from an old library that was originally in C++ 20 years ago. Should be easy enough to port back.
If your lines can extend beyond the client rectangle, call ClipLine(rect, ...) on your points before handing them off to Graphics::DrawLine.
private static bool clipTest(double dp, double dq, ref double du1, ref double du2)
{
double dr;
if (dp < 0.0)
{
dr = dq / dp;
if (dr > du2)
{
return false;
}
else if (dr > du1)
{
du1 = dr;
}
}
else
{
if (dp > 0.0)
{
dr = dq / dp;
if (dr < du1)
{
return false;
}
else if (dr < du2)
{
du2 = dr;
}
}
else
{
if (dq < 0.0)
{
return false;
}
}
}
return true;
}
public static bool ClipLine(Rectangle clipRect, ref int x1, ref int y1, ref int x2, ref int y2)
{
double dx1 = (double)x1;
double dx2 = (double)x2;
double dy1 = (double)y1;
double dy2 = (double)y2;
double du1 = 0;
double du2 = 1;
double deltaX = dx2 - dx1;
double deltaY;
if (clipTest(-deltaX, dx1 - clipRect.Left, ref du1, ref du2))
{
if (clipTest(deltaX, clipRect.Right - dx1, ref du1, ref du2))
{
deltaY = dy2 - dy1;
if (clipTest(-deltaY, dy1 - clipRect.Top, ref du1, ref du2))
{
if (clipTest(deltaY, clipRect.Bottom - dy1, ref du1, ref du2))
{
if (du2 < 1.0)
{
x2 = DoubleRoundToInt(dx1 + du2 * deltaX);
y2 = DoubleRoundToInt(dy1 + du2 * deltaY);
}
if (du1 > 0.0)
{
x1 = DoubleRoundToInt(dx1 + du1 * deltaX);
y1 = DoubleRoundToInt(dy1 + du1 * deltaY);
}
return x1 != x2 || y1 != y2;
}
}
}
}
return false;
}
The problem is I have not handle WM_ERASEBKGND message by myself.

how to clear dialog picture control type=frame

I have a dialog picture control of type = frame that I've used as a parent for something else.
When the child window is destroyed, the remnants are left in the control. What can I do to either clear the control or cause the demise of the child window to clear the control?
winapi c++
I thought there might be a simpler method but the following does the trick and allows you to color it however you like.
int s;
HDC dc;
RECT R;
z = GetDlgItem (hDlg, IDC_PS_AREA); // clear the containing control
dc = GetWindowDC (z);
s = GetClientRect (z,&R);
FillRect (dc, &R, (HBRUSH) GetStockObject (LTGRAY_BRUSH));
ReleaseDC (z, dc);
And even better
int s;
HDC dc;
RECT R;
HBRUSH hB;
z = GetDlgItem (hDlg, IDC_PS_AREA); // clear the parent containing control
dc = GetWindowDC (z);
s = GetClientRect (z,&R);
hB = GetSysColorBrush (COLOR_3DFACE);
FillRect (dc, &R, hB);
ReleaseDC (z, dc);

How to create window using structure concept so as to reduce code segment?

Suppose i have 5 window to be created in which one is parent and the four window are child window. So on the parent window if i have to create four window then how should i implement the structure concept so as to reduce the code segment.?
Is this a good habit or not to use the structure concept?
Please reply thanks a lot.
Suppose u have a structure
struct HANDLES
{
HINSTANCE hInstance;
HWND parent;
HWND childwindow1;
HWND childwindow2;
HWND childwindow3;
HWND childwindow4;
};
Now declare object for this handle
HANDLES handles;
Now create parent window like this at bool WINAPI InitInstance(HINSTANCE hInstance, int nCmdShow)
handles.parent = CreateWindowEx(0,
className,
windowName,
WS_VISIBLE | WS_POPUP,
0, 0,
coordinates.width, coordinates.height,
NULL,
NULL,
hInstance,
NULL);
where coordinates is an object and width & height are data member of COORDINATES.
Now create the child window under WM_CREATE.
HWND *buttons = &(handles.childwindow1);
for(int i = MIN_BUTTON; i <= MAX_BUTTON; i++) // MIN_BUTTON = 0 & MAX_BUTTON = 3
{
*buttons = CreateWindowEx(WS_EX_TOPMOST,
TEXT("button"),
L"",
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
btns[i].x, btns[i].y,
btns[i].width,btns[i].height,
handles.parent,
(HMENU) ((short)(INITIAL_BUTTON + i)), //(INITIAL_BUTTON + i) is id for your child window
handles.hInstance, NULL) ;
buttons++;
}
where "btns[4]" is an object of struct "AXIS"
AXIS btns[4];
struct AXIS
{
short int x;
short int y;
short int width;
short int height;
short int widthSrc;
short int heightSrc;
};
and for each child window there is a different value which is specified from btns[0] to btns[3].
So in this way u can create your window using structure.
Yes its a good habit to use structure which reduces code segment and easy to implement.

Resources