首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Qt5 QWidget::create()与Win32 HWND嵌入不再在Qt4端口后工作

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

Stack Overflow用户
提问于 2015-02-28 19:55:31
回答 1查看 6K关注 0票数 5

以下代码尝试使用create方法将自定义OpenGL窗口的本机OpenGL HWND嵌入到QWidget中:

代码语言:javascript
运行
复制
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上非常有效(最新使用的是Windows7/8.1上的Qt 4.8.6 x64,在Visual 2013上的x64 )。

现在,当移植到Qt5时,根据Qt5文档,相同的代码仍然可以工作。它需要对WId类型的更改进行一些小的更改。QWidget::winId()方法仍然返回小部件的本机HWND句柄,我使用spyxx.exe ()对其进行了验证。

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

好吧,在第一天晚上尝试解决这个问题之后,我尝试了几种我可以在论坛或文档中找到的其他方法:

  • QWindow::fromWinId(HWND)和QWidget::createWindowContainer容器(QWindow):这似乎是Qt-Devs希望我这样做的方式:
代码语言:javascript
运行
复制
_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()创建的小部件总是在windows堆栈的顶部。我尝试创建一个QWindow派生的类来拦截nativeEvent()调用,但没有成功.

我的想法已经接近尾声了,我希望能像Qt4一样让它发挥作用。有什么可以让我改变过去的行为吗?我可以使用Qt::StrongFocus策略通过父小部件跟踪键盘输入,但是本机窗口在完全燕子中的鼠标输入。我不能移动Qt5 OpenGL窗口代码,需要使用自定义的OpenGL上下文工具,因为我们使用的是Qt5仍然不完全支持的上下文。

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

EN

回答 1

Stack Overflow用户

发布于 2015-03-28 16:54:41

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

上面的内容不会解决来自本机窗口的消息永远不会到达Qt的事件分配器的反向问题。您需要将消息从您的WndProc发送到小部件的HWND (即调用winId()的返回)。这也几乎是试图将虚拟密钥代码转换为Qt::Key和back的步骤。

关于这一点为什么不能正常工作的一些说明,正如在Qt4中所做的那样:

其他说明:

  • QWidget::effectiveWinId()是首选的,即使您正在创建一个直接子窗口。不幸的是,这打破了5.4.1。
  • 更新为5.4.1。5.4.0和所有其他版本的Qt5都存在二进制兼容性问题。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28786172

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档