簡體   English   中英

Qt5 QWidget :: create(),Win32 HWND嵌入在Qt4端口后不再工作

[英]Qt5 QWidget::create() with Win32 HWND embedding not longer working after port from Qt4

以下代碼嘗試使用create方法將自定義創建的OpenGL窗口的本機Win32 HWND嵌入到QWidget中:

viewer_widget::viewer_widget(
    QWidget* parent,
    const viewer::viewer_attributes&     view_attrib,
    const wm::context::attribute_desc&   ctx_attrib,
    const wm::surface::format_desc&      win_fmt)
  : QWidget(parent)
{
    setMouseTracking(true);
    setFocusPolicy(Qt::StrongFocus);

    setAttribute(Qt::WA_NativeWindow, true);
    setAttribute(Qt::WA_PaintOnScreen, true); // disables qt double buffering (seems X11 only since qt4.5, ...)
    setAttribute(Qt::WA_NoSystemBackground, true);
    setAutoFillBackground(false);

    _viewer = make_shared<viewer>(math::vec2ui(100, 100), parent->winId(), view_attrib, ctx_attrib, win_fmt);

    // ok set the native window as this widgets window...and hold thumbs
    QWidget::create(_viewer->window()->window_handle(), true, true);
}

查看器創建一個本機Win32(或X11)窗口,其中QWidget的父級作為父級。 它還創建並初始化OpenGL上下文。 這樣做是為了更好地控制上下文創建和實時時間(我知道Qt5在這方面有很大改進)。 QWidget :: create()方法現在獲取本機窗口的HWND並將其嵌入到當前的QWidget中,因此事件處理完全通過Qt完成。

這在Qt4上完美運行(在Visual Studio 2013上最新使用的是Windows 7 / 8.1 x64上的Qt 4.8.6 x64)。

現在當移植到Qt5時,相同的代碼應該仍然可以根據Qt5文檔工作。 它需要進行微小的更改以考慮WId類型的變化。 QWidget :: winId()方法仍然返回小部件的本機HWND句柄,我使用spyxx.exe(Visual Studio Tools)驗證了這些句柄。

但是,代碼不再起作用(在Visual Studio 2013上使用Windows 7 / 8.1 x64上的Qt 5.4.0 x64)。 本機窗口沒有嵌入。 在Qt4中,當檢查創建的QWidget時,在創建調用之后它的本機句柄(winId)與本機HWND相同,這意味着嵌入工作。 現在使用Qt5,QWidget包含自己的HWND,我可以再次使用spyxx.exe進行確認。 現在有父窗口小部件/窗口和兩個子窗口小部件/窗口,其中應該只有一個子節點(本機節點)。 我查看了兩個Qt版本的create()方法的源代碼,我不明白為什么它不再起作用了。

好的,在第一個晚上試圖解決這個問題后,我嘗試了幾種其他方法,我可以在論壇或文檔中找到:

  • QWindow :: fromWinId(HWND)和QWidget :: createWindowContainer(QWindow):這個似乎是Qt-Devs希望我這樣做的方式:
_viewer = make_shared<viewer>(math::vec2ui(100, 100), par_hndl, view_attrib, ctx_attrib, win_fmt);
QWindow* native_wnd  = QWindow::fromWinId((WId)_viewer->window()->window_handle());
QWidget* native_wdgt = QWidget::createWindowContainer(native_wnd);

QHBoxLayout* lo        = new QHBoxLayout(this);
lo->setContentsMargins(0, 0, 0, 0);
lo->addWidget(native_wdgt);

這至少至少表現得像我期望的那樣。 我看到了我的窗口,在新創建的小部件中嵌入了本機窗口。 但是:我發現無法從新創建的小部件中獲取任何鼠標事件/輸入。 我添加了一個沒有運氣的eventFilter。 我嘗試了一個帶有透明頂級窗口小部件的QStackedLayout來捕獲輸入,但是這不起作用,因為通過createWindowContainer()創建的窗口小部件始終位於窗口堆棧的頂部。 我嘗試創建一個QWindow派生類來攔截nativeEvent()調用,沒有運氣......

我的想法結束了我的工作與Qt4一樣。 有什么我能以不同的方式來恢復舊的行為嗎? 鍵盤輸入我可以使用Qt :: StrongFocus策略通過父窗口小部件進行跟蹤,但鼠標輸入完全被本機窗口吞下。 我無法移動Qt5 OpenGL窗口代碼,需要使用我們的自定義OpenGL上下文工具,因為我們正在使用Qt5仍然不完全支持的上下文。

我還不能在Linux上嘗試Qt5,但上面看到的Qt4代碼在那里工作。

我已經基本上通過QWidget來解決從Qt到窗口的通信,使用最初的create() ,並重新實現QWidget事件函數以直接更改本機窗口。 到目前為止我發現的那些(大的)是焦點事件, resizeEventmoveEvent和內容rect並啟用changeEvent 字體,調色板,工具提示等changeEvents可能是較低的優先級。

以上內容不能解決相反的問題,來自本機窗口的消息永遠不會到達Qt的事件調度程序。 您需要將WndProc中的消息發布到小部件的 HWND(即,從調用winId()返回)。 這也幾乎試圖將虛擬鍵碼轉換為Qt::Key並返回。

關於為什么這不能正常工作的一些注釋,就像在Qt4中那樣:

其他說明:

  • 即使您正在創建直接子窗口,也首選QWidget::effectiveWinId() 不幸的是,這打破了5.4.1。
  • 更新至5.4.1。 5.4.0和Qt5的所有其他版本存在二進制兼容性問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM