繁体   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