Is it possible to combine GLFW window with WINAPI controls? - winapi

I have such 3D scene in a window which was created using GLFW:
Now I'd like to have some buttons and lists and input fields in here too. WinAPI provides those. How do I achieve this and add controls to my window?
I checked the Internet, and I don't see much questions about using WinAPI controls with GLFW window. As far as I remember, GLFW does not appreciate when someone tries to snatch HWND of its window (I think, it's protected, since they strive for cross-platform implementation of their library). I have seen a question when someone tried to embed a GLFW window into another window, which does not fit my idea. I completely appreciate if GLFW handles an input on scene - mouse clicks on scene, drags, key presses and other events, but controls, of course, should be reachable as well. Alternatively I may go with Dear ImGui, and use those controls in my window, if adding WinAPI controls to GLFW window appears too complicated.

You have to do a better research. Instead of checking the Internet, why didn't you just visited the most relevant sites: WinAPI and GLFW
As far as I remember, GLFW provides a Native access.
For example, to create a button, you'll need the HWND of the parent window (see here):
HWND glfwGetWin32Window(GLFWwindow *window);
and then (see here)
HWND hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"OK", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
100, // Button width
100, // Button height
m_hwnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(m_hwnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
After you've created the button, listen to the incoming events and act properly.

Related

The correct method for drawing a bitmap image into a window

I have a function which takes a rectangular region of a bitmap image, rescales it to different dimensions, and draws it at some offset inside of a window within my dialog-box application:
void DrawImage(HANDLE hImageBitmap,
CDC* pDstDC,const CRect& dstRect,
CDC* pSrcDC,const CRect& srcRect)
{
pSrcDC->SelectObject(hImageBitmap);
pDstDC->SetStretchBltMode(HALFTONE);
pDstDC->StretchBlt
(
dstRect.left,dstRect.top,dstRect.Width(),dstRect.Height(),pSrcDC,
srcRect.left,srcRect.top,srcRect.Width(),srcRect.Height(),SRCCOPY
);
}
I create and maintain the window using a CWnd m_cImageWindow member variable.
I perform the drawing from the dialog-box's OnPaint handler as follows:
CDC* pDC = m_cImageWindow.GetDC();
CDC cDC;
cDC.CreateCompatibleDC(pDC);
CRect srcRect = ...;
CRect dstRect = ...;
DrawImage(m_hImageBitmap,pDC,dstRect,&cDC,srcRect);
cDC.DeleteDC();
m_cImageWindow.ReleaseDC(pDC);
I have two problems:
I see flickering whenever I change the drawing parameters. The standard way to solve this, from what I have read here and there, is by using a temporary DC for double-buffering. But as far as I understand, this is exactly what I am already doing.
If some of the destination region falls outside the window, it is painted over other controls within the dialog box. I am able to partially solve this by calling MoveWindow or SetWindowPos for each one of these controls. But I can still see the image flickering behind them. I have tried calling SetWindowPos in various different ways, hoping in vain that it would dictate a strict Z-order of the controls.
Thank you.
The painting of the image into the child window should be done in the WM_PAINT handler for that child window, not for the dialog. Your child window may need remember information provided by the parent dialog so that it can paint independently. By painting the window from the dialog's WM_PAINT handler, you're possibly painting more often than necessary (and possibly aren't causing a validation to occur in the image window).
The dialog should probably have the WS_CLIPCHILDREN window style and your image window should probably have WS_CLIPSIBLINGS. This will prevent the dialog controls from drawing over each other, and it can reduce flicker by allowing for more minimal updates.
If the image will always completely cover the entire image window, then you want to make sure there's no background erasing happening for the image window, as that can cause a flash of the background color which looks like painting. There are several ways to do this, but the easiest is probably to provide a WM_ERASEBKGND handler that just returns TRUE.
I found OnEraseBkgnd to be the right place to minimize flickering of drawn bitmaps.

Child window forwards messages to parent

I have a parent window (MFC dialog) with some controls on it (editbox, button, etc.), which looks like this:
At runtime (OnInitDialog), I create another child window which covers and hides all the other controls in the dialog, using this code:
RECT r;
GetClientRect(&r);
m_layer.Create(NULL, NULL, WS_CHILD | WS_VISIBLE, r, this, 0);
The m_layer object is an instance of a class CLaywerWnd inherited from CWnd. In this class I override the following method:
BOOL CLayerWnd::OnEraseBkgnd(CDC* pDC)
{
CBrush b(RGB(0, 100, 100));
RECT r;
GetClientRect(&r);
pDC->FillRect(&r, &b);
return TRUE;
}
Now my window looks like this:
The problem is that when I move the mouse cursor or click on this new child window the messages are forwarded to the parent window (I checked this using Spy++), and the other child controls are redrawn over the new child window, like bellow.
I don't understand why this happens and I want to know how to avoid this behavior.
I may well be wrong, but I wonder if you've mixed up in your code the handles to the two dialogs, such that you're posting messages to the wrong dialog?
One easy way to avoid it takes two steps:
Change the state of all the hidden controls to disabled, so they won't react to any messages.
Make sure the overlay window is at the top of the Z-order. You can do this when you create the window or later using SetWindowPos.

WIN32 change the text insideTextOut

This will diplay the text on the screen with a TRANSPARENT BG and A colored text, but what if i want to change the
text later, how do i do? should i use: SendMessage(); or: SetWindowText( ) If yes, how and if
no, then what then??? and how
case WM_PAINT:
dc = BeginPaint(hwnd, &Ps);
SetBkMode(dc, TRANSPARENT);
SetTextColor(dc, RGB(454,0,0));
TextOut(dc, 10, 200, L"SEE? ", 5);
EndPaint(hwnd, &Ps);
break;
If you want to draw the text associated with your window - this is what you should do:
Don't call TextOut with the hard-coded string. Instead obtain it via GetWindowText.
Add a hander to WM_SETTEXT message. Upon receiving it - invalidate your window (or at least the area where the text is assumed to be drawn).
Now some explanations about transparency and etc.
I assume your window has an associated background brush (i.e. its WNDCLASS had non-zero hbrBackground member upon class registration). If not - you're painting a transparent text above a non-painted area, which may contain any junk.
During the call to BeginPaint your window procedure receives WM_ERASEBACKGROUND. Assuming you pass it to the DefWindowProc - the client area of your window will be filled by the background brush. So that every time you begin painting - the client are of your window will be filled by some brush. Then you draw your text transparently on the newly-filled background. So that no smearing should occur.
Whenever you want to change something visual on your window - drawing extra things in-place is not enough. Because at any time your window may be requested by the OS to redraw itself. So that your window must be able to paint itself adequately upon receiving WM_PAINT.
A common practice is to invalidate your window (or a part of it, using InvalidateRect or similar function) upon some change. And then, when you receive WM_PAINT - repaint your window.

Win32 transparent controls on all versions ofWindows

I'm working on a Win32 GUI app using plain Win32 API (no MFC or .NET). The issue I'm having is making controls appear transparent. I've come up with a method which works for most things, in Windows Vista+ I do this in the WndProc:
case WM_CTLCOLORSTATIC:
{
SetBkMode((HDC)wParam, TRANSPARENT);
return (INT_PTR)::GetStockObject(NULL_PEN);
}
break;
In Windows XP, I do this in the WndProc:
case WM_CTLCOLORSTATIC:
{
HBRUSH hbr = (HBRUSH)DefWindowProc(hDlg, message, wParam, lParam);
::DeleteObject(hbr);
SetBkMode((HDC)wParam, TRANSPARENT);
return (LRESULT)(HBRUSH)(COLOR_WINDOW);
}
Now this works for most of the controls, however I get a transparent background on the label on the top of a group box control which draws the group box line through the text. I started working towards a case for just group boxes but I'm sure that this is a problem which must have been solved before and I don't want to go re-inventing the wheel.
Is there a tried and tested method for making controls appear transparent?
Thanks,
J
To achieve transparent controls you are going to have to be aware that:
You can't really. The standard windows controls just don't support "transparent" painting.
Even when you get it right, the dialog is going to flicker badly if you resize it.
The 'hacks' to get transparent painting of controls working tend to be different if theming is on or off, and change between windows versions.
Usually the goal of making controls "transparent" is so that a bitmap skin under the controls shows through. The way to achieve this kind of transparency is to create a bitmap for the background of the control. Then use CreatePatternBrush from the bitmap.
This chunk of DialogProc code implements the simplest skinning method possible and will then take care of painting both the background of the dialog, and most of the controls that support this form of painting:
// _hwnd is the dialogs handle
// _hbrSkin is a pattern brush handle
HWND hwndCtl;
POINT pt;
HDC hdc;
case WM_CTLCOLORDLG:
return (INT_PTR)_hbrSkin;
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORBTN:
hdc = (HDC)wParam;
SetBkMode(hdc,TRANSPARENT); // Ensure that "static" text doesn't use a solid fill
pt.x = 0; pt.y = 0;
MapWindowPoints(hwndCtl,_hwnd,&pt,1);
SetBrushOrgEx(hdc,-pt.x,-pt.y,NULL);
return (INT_PTR)_hbrSkin;
Controls that overlap will draw incorrectly as one will paint its "transparent" background over the other. You can reduce the flicker by:
Not allowing the dialog to be resized.
setting the WS_EX_COMPOSITED style on the dialog, but as the Windows NT 6 DWM doesn't support it, its essentially useless from Vista on.
Setting the WS_CLIPCHILDREN style on the dialog & or WS_CLIPSIBLINGS - these styles prevent the use of group boxes and tab controls as they rely on controls overlapping.
subclassing all the controls, using the WM_PRINTCLIENT message to paint them to a backbuffer, then blitting the prepared backbuffer in one pass. Hard work and not all controls support WM_PRINTCLIENT.

Making an owner-draw button transparent against its arbitrary background in WINCE

I am trying to place an owner-draw button transparently onto a background. I have no trouble doing this when the background is a solid colour but if the background is an image I cannot seem to get the correct HDC (handle to device context) to Bitblt() the area that button covers.
The HDC that is passed as part of the DRAWITEMSTRUCT gives me a button-default-grey area. If I attempt to get the parent of the HWND and then the device context of that i.e
pdc = GetDC(GetParent(hWnd));
then the background that gets BitBlt'd is the background of the last painted window.
I hope this question makes sense.
this is the code I have:
pdis = (LPDRAWITEMSTRUCT)(lParam);
hdc = pdis->hDC;
button = pdis->CtlID - IDC_BUTOFFSET;
//pdc = GetDC((hWnd));
pdc = GetDC(GetParent(hWnd));
hbm = CreateCompatibleBitmap(pdc, Buttons_[button]->bc.Size.cx, Buttons_[button]->bc.Size.cy);
SelectObject(hdc, hbm);
BitBlt(hdc, 0, 0, Buttons_[button]->bc.Size.cx, Buttons_[button]->bc.Size.cy,
pdc, Buttons_[button]->bc.Position.x, Buttons_[button]->bc.Position.y, SRCCOPY);
TIA
Best regards
Ends
It seems that what I have been doing is more or less correct. However Bitblt is copying the section of the window with the button already placed, so what I am in effect doing is copying the default button background and then overlaying that on top of the owner-draw button. A bit dumb but completely logical.
I hate it when computers do what you tell them to do and not what you want them to do. :P
Now I have to figure out how to copy the background as the ownerdraw function does not know what the window under the button is displaying at any given time...
Thanks to those who had a look at the question.
BTW:
pdc = GetDC(GetParent(hWnd)); // NOT CORRECT
pdc = GetDC(hWnd); // better

Resources