在本机中嵌入 Qt window (Windows)

Embed Qt inside native window (Windows)

我想在 Windows 中嵌入一个 Qt 应用程序(不是相反,因为已经回答了许多其他问题)。澄清一下,我有一个 win32 应用程序,我启动了一个 qt python 进程;此 qt python 进程必须嵌入到 win32 应用程序中。如何才能做到这一点?在 API for QWindow::fromWinId 中,它明确指出:

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

其次,QWidget::createWindowContainer 似乎只适用于在 Qt 中嵌入本机 windows(不是我想要的方式)。

我不确定如何在 QWindow 中创建 QWidget。从这个 question 看来,方法是用 QWindow::fromWinId 创建一个 QQuickView;但是,我似乎找不到如何将 QWidget 绑定到 QQuickView 中。

目前我实际上是用 ::SetParent 设置父级,但是有一些奇怪的消息协议需要处理,所以我想尝试用 Qt 的方法重构它。

到目前为止编写的一些基本代码(PySide2,但 C++ 或任何其他具有 Qt 绑定的语言都可以):

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_())

首先,您需要从 HWND 创建一个 QWindow,以便 Qt 可以处理它:

// C++
QWindow *nativeWindow = QWindow::fromWinId(hwnd);
// Python
nativeWindow = QWindow.fromWinId(hwnd);

然后创建 Qt Widget 界面:

// C++
QLabel *label = new QLabel("Hello from Qt");
label->show();
// Python
label = QLabel("Hello from Qt");
label.show();

然后您将 Qt Widget 界面的顶部 window 设置为原生 window:

// C++
label->windowHandle()->setParent(nativeWindow);
// Python
label.windowHandle().setParent(nativeWindow);

但是,您不能使用 Qt 来监听 HWND window 中的变化。引用 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.

实际上,信号 QWindow::widthChanged()QWindow::heightChanged() 不会发出。

如果你想监听来自 HWND 的事件,你必须使用 SetWindowsHookEx()SetWinEventHook().

如果您对可以用 C 或 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);

与以下 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;
    }
}