Qt widget on top of other non qt window - c++

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.

Related

create QWidget width HWND parent

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...
}

embed window(glfwCreateWindow) as child to C++ MFC parent form

Please refer this link
Embedding a GLFW window inside windows forms
How can the same achieved by using VC++ to embed glfw window to Parent form?
Try this:
Call glfwWindowHint() to set GLFW_DECORATED and GLFW_VISIBLE to false.
Call glfwCreateWindow().
Call glfwGetWin32Window() to get the native handle of the OpenGL window.
Call SetParent() to set your form as the new parent of the OpenGL window.
Call GetWindowLong() / SetWindowLong() to remove the WS_POPUP and add the WS_CHILDWINDOW style for the OpenGL window.
Call ShowWindow() to finally make the OpenGL window visible.
I got this from github.com/Chronial/foo_chronflow :: EngineWindow.cpp.
You might also call SetWindowPos() to adjust the position of the OpenGL window within your form.
The link in zett42's post is dead, so here's a more complete snippet
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWwindow* pWindow = glfwCreateWindow(width, height, "", NULL, NULL);
HWND hwNative = glfwGetWin32Window(m_pWindow);
SetParent(hwNative, hwParentWindow);
long style = GetWindowLong(hwNative, GWL_STYLE);
style &= ~WS_POPUP; // remove popup style
style |= WS_CHILDWINDOW; // add childwindow style
SetWindowLong(hwNative, GWL_STYLE, style);
... any other initialisation code (e.g enable/disable gl features) ...
ShowWindow(hwNative, SW_SHOW);

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);

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.

Hiding an MFC dialog box

Ok so I am using this code to hide the taskbar icon of a dialog based MFC application(VC++). The taskbar icon and the dialog box hide whenever I click on the cross or the close buttons. But I can’t get this one thing right. Whenever I hit the close or the cross button from title bar, the dialog box first flickers and shows a sort of intermediate dialog box and then hides. This is very annoying. I am posting my code here after two days of vain effort. So guys please help me. Thanks in advance.
void CMyAppDlg::OnBnClickedCancel()
{
// TODO: Add your control notification handler code here
CWnd* pWnd;
pWnd = AfxGetMainWnd();
RemoveTaskbarIcon(pWnd);
pWnd->ModifyStyle(WS_VISIBLE, 0);
mVisible = FALSE;
}
BOOL CMyAppDlg::RemoveTaskbarIcon(CWnd* pWnd)
{
LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
// Create static invisible window
if (!::IsWindow(mWndInvisible.m_hWnd))
{
if (!mWndInvisible.CreateEx(0, pstrOwnerClass, _T(""),
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, 0))
return FALSE;
}
pWnd->SetParent(&mWndInvisible);
return TRUE;
}
Here are the screen shots of dialog box. When I press the close or cross button, the dialog box which looks like this in the first place turns into this for like less than half a second and then disappears (hides).
If you show your dialog using CDialog::DoModal() the framework will make sure your dialog is shown. There is only one way to prevent a modal dialog from being shown:
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()
BOOL CHiddenDialog::OnInitDialog()
{
CDialog::OnInitDialog();
m_visible = FALSE;
return TRUE;
}
void CHiddenDialog::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
if (!m_visible)
lpwndpos->flags &= ~SWP_SHOWWINDOW;
CDialog::OnWindowPosChanging(lpwndpos);
}
I think Paul DiLascia recommended the following. This is for modal dialogs only.
The following code can be put in OnInitDialog to move the dialog off-screen. You will need to implement a method for moving it back on-screen when appropriate.
CRect DialogRect;
GetWindowRect(&DialogRect);
int DialogWidth = DialogRect.Width();
int DialogHeight = DialogRect.Height();
MoveWindow(0-DialogWidth, 0-DialogHeight, DialogWidth, DialogHeight);
The answer from l33t looks good and is probably better but this is an alternative.
Maybe an obvious thing, but what happens when you do the hide before you reparent the dialog? Also what if you don't directly modify the window style but use ShowWindow(SW_HIDE)?
Finally, have you tried switching the dialog's window style to WS_CHILD before calling SetParent() and/or maybe moving it out of the client area so that the window isn't shown any more (MoveWindow(-1000, -1000) or something like that).