Correct Way to Handle Multiple windows?
Snow-Okami opened this issue · 2 comments
I have been trying to get multiple windows working without much luck. I don't know how to go about it at all. At first I tried pure inheritance but I couldn't get this to work without running into the diamond problem. I also don't know QT enough (specifically their QWidget class) to get this working. Then I tried a combination of inheritance and a hardcoded enum that is passed in to the constructor that tells the QWinWidget which type of class to create (widget.cpp).
When I do this however, having 2 windows open at once, causes a rendering error, as well as interaction within the windows to behave oddly. It seems as though parts of the 2 windows are controlling one another still leading the odd behavior.
I basically made copies of widget.cpp and widget.h for my different windows, and modified QWinWidget.cpp and QWinWidget.h to accept these copies and spawn different windows. These copies are derived from a basewidget.cpp (the original widget.cpp).
Is there any simple example or explanation you could provide that could aid me in this? Thanks so much.
After taking a break, and then coming back to this, I have figured out how to solve the issue. But the issue I had prior has re-emerged (the dragging windows). Here is how I solved it. Basically the static members of WinNativeWindow (childWindow and childWidget) need to become non static. By them being static it causes all windows spawn to share the same first-created window and widget. This is why the others were being controlled in strange manners as well as not occupying the full space. To do this however you must find a way to expose these to the static LRESULT CALLBACK WndProc. To do this, we transform them into pointers to save into the userdata of the window.
QWinWidget.cpp
Change:
p_ParentWinNativeWindow = new WinNativeWindow(1 * window()->devicePixelRatio()
, 1 * window()->devicePixelRatio()
, 1 * window()->devicePixelRatio()
, 1 * window()->devicePixelRatio()
, (HWND)winId()
, this);
Delete the following:
p_ParentWinNativeWindow->childWindow = (HWND)winId();
p_ParentWinNativeWindow->childWidget = this;
WinNativeWindow.h
Change:
WinNativeWindow(const int x, const int y, const int width, const int height, const HWND hwnd, QWidget* childwidget);
HWND childWindow;
QWidget* childWidget;
WinNativeWindow.cpp
Delete (at top, above constructor):
HWND WinNativeWindow::childWindow = nullptr;
QWidget* WinNativeWindow::childWidget = nullptr;
Change (Constructor at top):
WinNativeWindow::WinNativeWindow(const int x, const int y, const int width, const int height, const HWND hwnd, QWidget* childwidget)
: hWnd(hwnd),
childWidget(childwidget)
{
Add (under the other SetWindowLongPtr):
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(hWnd));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(childWidget));
Add (under LRESULT CALLBACK):
HWND* childWindow = reinterpret_cast<HWND*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
QWidget *childWidget = reinterpret_cast<QWidget*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
Change:
case WM_CLOSE:
{
if (*childWindow)
{
SendMessage(*childWindow, WM_CLOSE, 0, 0);
return 0;
}
break;
}
After doing that, multiple windows will work, just do the same in the main.cpp as the other window to spawn a second window independent of the first:
QWinWidget ww;
ww.setGeometry(windowXPos, windowYPos, windowWidth, windowHeight);
ww.show();
I'm going to continue working on this a bit and try to solve the dragging issue I am having again to get this all working.
Thank you for the solution, after some fixes, it works like a charm.
The problem is that the USERDATA can only hold one pointer.
so when you do
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(hWnd));
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(childWidget));
the USERDATA pointer is overriden by each call. a way to fix that is by grouping all the pointers we need to pass in a struct, and pass a pointer to this struct
struct userData_t
{
WinNativeWindow* nativeWindow;
HWND* childWindow;
QWidget* childWidget;
};
userData_t userdata;
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(&userData));