Reputation: 630
I'd like to embed a Qt Application inside Windows (not the other way around, as many other questions have already been answered). To clarify I have a win32 application which I launch a qt python process; this qt python process must be embedded within the win32 application. How can this be done? In the API for QWindow::fromWinId
, it clearly states:
"Creates a local representation of a window created by another process or by using native libraries below Qt...."
"...This can be used, on platforms which support it, to embed a QWindow inside a native window, or to embed a native window inside a QWindow."
And secondly QWidget::createWindowContainer
appears to only work for embedding native windows inside Qt (not the way I want it).
I am not sure how I would approach creating a QWidget
inside QWindow
. From this question, it seems the way would be to create a QQuickView
with a QWindow::fromWinId
; however, I can't seem to find how to bind a QWidget into a QQuickView.
Currently I am actually setting the parent with ::SetParent
but there are weird messaging protocols to deal with there so I'd like to try to refactor this with Qt's approach.
Some basic code written so far (PySide2, but C++ or any other language with Qt bindings is fine):
app = QApplication(sys.argv)
hwnd = int(sys.argv[1], 16)
nativeParentWindow = QWindow.fromWinId(hwnd)
quickview = QQuickView(nativeParentWindow)
# this part is incorrect (tries to embed native window into qt)
# I want this application to run embedded inside hwnd
wrongWidget = QWidget.createWindowContainer(quickview)
wrongWidget.show()
sys.exit(app.exec_())
Upvotes: 5
Views: 3371
Reputation: 8311
First, you need to create a QWindow from HWND so that Qt can handle it:
// C++
QWindow *nativeWindow = QWindow::fromWinId(hwnd);
// Python
nativeWindow = QWindow.fromWinId(hwnd);
Then you create your Qt Widget interface:
// C++
QLabel *label = new QLabel("Hello from Qt");
label->show();
// Python
label = QLabel("Hello from Qt");
label.show();
Then you parent the top window of you Qt Widget interface to the native window:
// C++
label->windowHandle()->setParent(nativeWindow);
// Python
label.windowHandle().setParent(nativeWindow);
However, you cannot use Qt to listen to changes in the HWND window. Quoting Qt documentation:
Note: The resulting QWindow should not be used to manipulate the underlying native window (besides re-parenting), or to observe state changes of the native window. Any support for these kind of operations is incidental, highly platform dependent and untested.
In practice, the signals QWindow::widthChanged()
and QWindow::heightChanged()
are not emitted.
If you want to listen to events from HWND you have to do it the native Win32 way by using SetWindowsHookEx()
or SetWinEventHook()
.
If you are interested in the resize event you can do in C or C++:
targetHwnd = hwnd; // defined on global scope
DWORD processId;
DWORD threadId= GetWindowThreadProcessId(hwnd, &processId);
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, 0, &Wineventproc, processId, threadId, WINEVENT_OUTOFCONTEXT);
with the following Wineventproc
:
void WINAPI Wineventproc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime
)
{
if(targetHwnd == hwnd) { // Filter events that are not for our window
qDebug() << "event" << event;
RECT rect;
GetWindowRect(hwnd, &rect);
qDebug() << "Height:" << rect.bottom - rect.top;
qDebug() << "Width:" << rect.right - rect.left;
}
}
Upvotes: 4