create QWidget width HWND parent - c++

OS Windows. Qt 5.5.1
I made library (dll) with GUI on Qt.
I connected it to new project. I have parent's hwnd. How to set parent for library-window (Qwidget)?
If use winapi SetParent(), then child window does not leave bounds the parent window.
I tried QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow), but it is not working, because according to documentation the parameter window is ignored in Qt 5.

I found a way that works, but there are unknown messages on the screen
windowsProc: No Qt Window found for event 0x24 (WM_GETMINMAXINFO), hwnd=0x0x110956.
windowsProc: No Qt Window found for event 0x83 (WM_NCCALCSIZE), hwnd=0x0x110956.
windowsProc: No Qt Window found for event 0x5 (WM_SIZE), hwnd=0x0x110956.
windowsProc: No Qt Window found for event 0x3 (WM_MOVE), hwnd=0x0x110956.
setGeometryDp: Unable to set geometry 640x480+0+0 on QWindow/''. Resulting geometry: 640x480+-760+-370 (frame: 8, 30, 8, 8, custom margin: 0, 0, 0, 0, minimum size: 0x0, maximum size: 16777215x16777215).
setGeometryDp: Unable to set geometry 640x480+0+0 on QWindow/''. Resulting geometry: 640x480+-760+-370 (frame: 8, 30, 8, 8, custom margin: 0, 0, 0, 0, minimum size: 0x0, maximum size: 16777215x16777215).
listLabels.size() 4
Let a parent window be an ownerWin, and a child one QWidget-window named childWin;
If to use SetWindowLongPtr, the desirable result is achieved (the child window overlaps the parent one), but the child window still is in the memory when the parent window closes.
To fix a problem I create one more child window (middleWin with a parent ownerWin.) using WinApi. After wrapping this window with QWidget using createWindowContainer() it stops working normally. Then using standard Qt methods we can link our QWidget window. So we have three windows: parent, intermediate and mine. Then I close middleWin using close().All that manipulations needs to insure that when ownerWin closes, also childWin closes as well. If SetWindowLongPtr is used, then childWin will always be above the parent window, but it works only if called after function show() in child window.
Below are the functions I use. First call setWinParent(), then showWindow().
In setWinParent() lines 1 through 5 is "black box" for me. I don't know why window is created that way.
void setWinParent(HWND ownerWin)
{
HWND hwnd = (HWND)this->winId();
DWORD exStyle = GetWindowLong(hwnd, GWL_EXSTYLE) ;//1
DWORD style = GetWindowLong(hwnd, GWL_STYLE);//2
WCHAR className[256];//3
GetClassName(hwnd, className,256);//4
HWND newHwnd = CreateWindowEx(exStyle, className, NULL, style,//5
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
ownerWin, NULL, qWinAppInst(), NULL);
QWindow *qw=QWindow::fromWinId((WId)newHwnd);
QWidget* qWidget = createWindowContainer(qw);
qWidget->show();
this->setParent(qWidget);
this->setWindowFlags(Qt::Window);
qWidget->close();
}
void showWindow(HWND ownerHwnd)
{
show();
SetWindowLongPtr((HWND)this->winId(), GWLP_HWNDPARENT, (LONG)ownerHwnd);
}

Unfortunately, this is a long-running issue with Qt on Windows (and other platforms). You'll have to find a way to hook into the parent window to catch mouse and keyboard events, etc. to propagate to your Qt child window. The internal Qt code for this is perpetually a work in progress.
There's a good page about these issues and the subject in general here. Here's the bug report discussing the issue, as well.
Note: QAxWidget isn't exactly helpful, either. It looks promising, but suffers the same issues with event propagation.

The parameter window is ignored in Qt 5. Please use
QWindow::fromWinId() to create a QWindow wrapping a foreign window and
pass it to QWidget::createWindowContainer() instead.
What's unclear about the Qt documentation?
QWindow *wndParent = QWindow::fromWinId(hwnd); // hwnd - your WId
if(wndParent)
{
QWidget *parent = QWidget::createWindowContainer(wndParent);
if(parent)
// ...
}
else
{
// unsupported window...
}

Related

Changing opacity of child window without using WS_EX_LAYERED

I have a window and then I create a child window using the following code:
HWND childHwnd = CreateWindowExA(WS_EX_LAYERED, "Test", "Test", WS_CHILD, 0, 0, 500, 500, mainHwnd, NULL, instance, NULL);
After it has been created I can control the opacity using:
static COLORREF color = RGB(255, 0, 0);
SetLayeredWindowAttributes(childHwnd, color, 127, LWA_ALPHA);
It works fine but I also have to support Windows 7 and MSDN says the following:
Windows 8: The WS_EX_LAYERED style is supported for top-level windows and child windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.
I have installed Windows 7 in a VM and sadly it doesn't works. What could be the workaround to achieve the same opacity control over a child window in Windows 7?
I also tried to make it a standalone window and just follow the position of the parent window but the user experience is not that good when the window gets moved fast.
According to the documentation:
Using Layered Windows
In order to use layered child windows, the application has to declare itself Windows 8-aware in the manifest.
I suggest you refer to this answer:
https://stackoverflow.com/a/42570249/11872808
In Windows 7, you could try to use the SetWindowRgn() function.
I suggest you refer to this question:
Creating a Transparent Child window on top of non-transparent Parent Window (win32)

MFC - Minimize main MDI window only

I have main MDI window and have custom CWnd derived window which I create dynamically run-time. I want to keep that window on the screen even when main MDI window is minimized but I dont want to have top-most window. I have tried use WS_EX_CONTROLPARENT | WS_EX_APPWINDOW styles, set parent to NULL and set owner to GetDesktopWindow() but nothing works.
Any ideas how I should do that?
When window is minimized, it takes down with it all of its child and owned windows.
This code creates a regular (not topmost) window which is not hidden when the main frame is minimized:
HWND hWnd = ::CreateWindow(L"button", L"test", WS_CAPTION|WS_VISIBLE,
100, 100, 200, 200, GetDesktopWindow(), 0, 0, 0);

Qt widget on top of other non qt window

I'm developing a plugin for a commercial program (I can't change it) that I use in Windows operating system. In this plugin I create a Qt Widget and when in the main program a button is clicked, the qt widget appears.
My problem is that the widget appears under the main program window, while I want it on top of it. It can be stay Always on top, if necessary.
Qt::WindowStaysOnTopHint does not seems to work here because I have no Qt parents.
I've found a way to put it on top, following the Qt wiki, and I've created a method that I call after widget constructor:
void RadiationPatternWidget::setWindowTopMost()
{
#ifdef Q_WS_WIN32
HWND hwnd = winId();
DWORD exStyle = ::GetWindowLong(hwnd, GWL_EXSTYLE);
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
HWND parent = NULL;
if (parentWidget()) {
parent = parentWidget()->winId();
}
exStyle |= WS_EX_TOPMOST;
HWND newHwnd = ::CreateWindowEx(exStyle, L"#32770", NULL, style,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent, NULL, qWinAppInst(), NULL);
create(newHwnd, true, true);
#endif // Q_WS_WIN32
}
Then I call it after constructor:
m_pxRadiationPatternWidget = new RadiationPatternWidget();
m_pxRadiationPatternWidget->setWindowTopMost();
Now it stays on top, but I've some problem:
Inside the widget I use some QPushButton cannot and if window is raised they are not clickable. clicked() signals are not captured and button image does not change when I click on it with mouse.
Inside the widget I use a derived QGLWidget derived class. When I put it on top this widget is black, while if I don't call the method it works well.
How can I raise on top che QWidget correctly?
Before using your hack, check if widget->window()->raise() wouldn't work.
Using the window class "#32770" is an error. You need to use the same window class that Qt is already using for your window.
You need to retrieve the class used by Qt for the existing window, and only then create a new window with the same class.

Application in C++ with two windows. One window shown in taskbar. The other not shown

I am doing some analysis before coding and I was having some trouble finding information or implementations where there is an application where there are these characteristics:
Window #1 (shown on taskbar)
Window #2 (doesn't show on taskbar and you can put this one behind Window #1, so we are not talking about popups/dialogs rooted from Window #1)
Both Window #1 and Window #2 are in the same Project (or application, so to speak)
Again, this is just speaking conceptually, so if you can point me to some information proving that this is possible, it would be great. Note, this is in C++ not C#.
The closest I came up with is this:
Added a class derived from CWnd
Added the following function to the class
void Create2ndWindow(CWnd* pParent){
LPCTSTR pszClassName = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, ::LoadCursor(NULL, IDC_ARROW), (HBRUSH) ::GetStockObject(WHITE_BRUSH), ::LoadIcon(NULL, IDI_APPLICATION));
BOOL bCreated = CreateEx(WS_EX_CLIENTEDGE,
pszClassName,
_T("My Second Window"),
WS_BORDER|WS_CAPTION|WS_ACTIVECAPTION|WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_POPUPWINDOW|WS_SIZEBOX,
CRect(20, 20, 100, 100),
pParent,
NULL);
if(bCreated)
ShowWindow(SW_SHOW);
}
In the InitInstance i added the following lines:
CSecondWindow* pWnd = new CSecondWindow();
pWnd->Create2ndWindow(pFrame);
Execute the application, 2 Windows appear on your desktop but you should see only one taskbar button for the pFrame window and no button for the CSecondWindow
if the pParent is NULL then you would see the taskbar button. There is another style you can add WS_EX_TOOLWINDOW but that reduces the height of caption bar.

Child window created by CreateEx() overlapped by sibling windows

I tried to create a child window using:
CreateWindowEx( NULL, NULL, "MyChild", WS_CHILD | WS_VISIBLE | WS_BORDER, 300, 300, 400, 200, hParentWnd, NULL, NULL );
where the parent HWND hParentWnd has many other child windows already. However, this created a child window hiding behind all the siblings. Windows Spy++ shows that it is on top (first) of the z-order among the child windows of hParentWnd. I have tried all different win32 commands including SetWindowPos(), BringWindowToTop(), SetForegroundWindow(), SetFocus(), SetActiveWindow(), SendMessage(WM_ACTIVATE, 0, 0), etc., but none brings it from behind the siblings. When I replaced WS_CHILD by WS_OVERLAPPEDWINDOW in the CreateWindowEx() command, the created non-child window has no problem showing as the topmost foreground active window. So what must I do to get the child window to the top from behind the siblings?
Thanks a million.
z/0
It is quite explicit in the MSDN article for CreateWindowEx():
If the created window is a child window, its default position is at the bottom of the Z-order. If the created window is a top-level window, its default position is at the top of the Z-order.
You'll need to move it to the top of the Z-order with SetWindowPos().