Qt5 QWidget :: create()与Win32 HWNDembedded不再工作在Qt4之后的端口

下面的代码尝试使用create方法将自定义创build的OpenGL窗口的本机Win32 HWNDembedded到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); } 

查看器创build一个原生的Win32(或X11)窗口,将QWidget的父窗口作为父窗口。 它还创build并初始化一个OpenGL上下文。 这是为了更好地控制上下文创build和现场时间(我知道Qt5在这方面有很大改进)。 QWidget :: create()方法现在获取本地窗口的HWND并将其embedded到当前的QWidget中,以便事件处理完全通过Qt完成。

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

现在,当移植到Qt5时,相同的代码仍应该按照Qt5文档工作。 它需要微小的改变来说明WIdtypes的变化。 QWidget :: winId()方法仍然返回小部件的本地HWND句柄,我使用spyxx.exe(Visual Studio Tools)进行了validation。

但是,代码不再工作(在Visual Studio 2013的Windows 7 / 8.1 x64上使用Qt 5.4.0 x64)。 本机窗口只是没有embedded。 在Qt4中,在创build调用之后,检查创build的QWidget时,其本地句柄(winId)与本机HWND相同,这意味着embedded工作。 现在使用Qt5 QWidget包含自己的HWND,我可以再次使用spyxx.exe来确认。 现在有父窗口小部件/窗口和两个子窗口小部件/窗口,应该只有一个孩子(本地的)。 我查看了两个Qt版本的create()方法的源代码,我不明白为什么它不工作了。

好吧,在第一天晚上试图找出这个问题后,我尝试了几个其他的方法,我可以find论坛或文档:

  • 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); 

至less这种行为几乎和我所期望的一样。 我看到了我的窗口,并在新创build的窗口小部件中embedded了本机窗口。 但是:我发现没有办法从新创build的小部件获取任何鼠标事件/input。 我没有运气添加一个eventFilter。 我尝试了一个带透明顶级小部件的QStackedLayout来捕获input,但是这不起作用,因为通过createWindowContainer()创build的小部件始终位于Windows堆栈之上。 我尝试创build一个QWindow派生类来拦截nativeEvent()调用,没有运气…

我在我的想法的结尾与Qt4一样得到这个工作。 有什么我可以以不同的方式得到旧的行为? 我可以通过使用Qt :: StrongFocus策略的父窗口部件来跟踪键盘input,但鼠标input完全被本地窗口吞下。 我无法移动Qt5 OpenGL窗口代码,并需要使用我们自定义的OpenGL上下文工具,因为我们正在处理Qt5尚未完全支持的上下文。

我还不能在Linux上试用Qt5,但是上面看到的Qt4代码在那里工作。

Solutions Collecting From Web of "Qt5 QWidget :: create()与Win32 HWNDembedded不再工作在Qt4之后的端口"

我已经很大程度上解决了从Qt到窗口的通信,通过QWidget ,使用create()和重新实现QWidget事件函数来直接更改本地窗口。 到目前为止我发现的(大的)是焦点事件, resizeEventmoveEvent和内容rect并启用changeEvent 。 字体,调色板,工具提示等changeEvents可能是一个较低的优先级。

以上不会解决相反的问题,来自本地窗口的消息永远不会到达Qt的事件分派器。 你将需要从WndProc发送消息到Widget的 HWND(即从调用winId()返回)。 这也几乎绕过尝试将虚拟键码转换为Qt::Key并返回。

关于为什么这不起作用的一些说明,正如它在Qt4中所做的那样:

  • QWindow现在只适用于带有本地子部件的X11 。 正如你所提到的,尝试在Linux上测试。
  • QWidget::create()QWindow自从5.1以来一直是个问题。 你在这两个实现中遇到的问题似乎是合适的。
  • 以下是关于QWindow预期用法和问题的综合性错误报告

其他说明:

  • QWidget::effectiveWinId()是首选,即使您正在创建一个直接的子窗口。 这不幸的是,在5.4.1中断了。
  • 更新到5.4.1。 5.4.0和所有其他版本的Qt5存在二进制兼容性问题。