![](/img/trans.png)
[英](LINUX)Porting from Qt4 to QT5 undefined symbol : _Zn9Qwidget11stylechangeER6QStyle
[英]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()方法的源代碼,我不明白為什么它不再起作用了。
好的,在第一個晚上試圖解決這個問題后,我嘗試了幾種其他方法,我可以在論壇或文檔中找到:
_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
事件函數以直接更改本機窗口。 到目前為止我發現的那些(大的)是焦點事件, resizeEvent
, moveEvent
和內容rect並啟用changeEvent
。 字體,調色板,工具提示等changeEvents
可能是較低的優先級。
以上內容不能解決相反的問題,來自本機窗口的消息永遠不會到達Qt的事件調度程序。 您需要將WndProc
中的消息發布到小部件的 HWND(即,從調用winId()
返回)。 這也幾乎試圖將虛擬鍵碼轉換為Qt::Key
並返回。
關於為什么這不能正常工作的一些注釋,就像在Qt4中那樣:
QWidget::create()
和QWindow
至少是5.1以來的問題。 您在兩種實現中遇到的問題似乎都適合。 其他說明:
QWidget::effectiveWinId()
。 不幸的是,這打破了5.4.1。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.