如果 Qt3DWindow 嵌入在 QWidget 中,为什么 Qt3D QObjectPicker 不能在 Android 上工作?

Why does the Qt3D QObjectPicker not work on Android if the Qt3DWindow is embedded inside a QWidget?

我有一个包含 Qt3DWindow 和多个 QWidget 的 Qt 应用程序。要同时使用两者,Qt3DWindow 是通过 QMainWindow::createWindowContainer() 嵌入的,它在 Windows 和 Android 上都可以正常工作。对于附加到 QEntity 的 QObjectPicker,情况并非如此,QObjectPicker::clicked 事件仅在 Windows 上发生,而不是在 Android 上发生。但是,如果我从 QMainWindow 中删除 Qt3DWindow 并再次使用它 'standalone',QObjectPicker 在两个平台上都按预期工作。

我已经使用不同的 Qt 版本(5.10、5.12、5.13 beta)和不同的工具链(NDK R14 with GCC、NDK R19 with Clang)测试了这个用例,但没有成功。在极少数情况下,我收到一个 QObjectPicker::clicked() 事件,但触摸事件远离对象的屏幕位置。

要重现问题,最好扩展到 "Qt 3D: Simple C++ Example"。 将以下内容添加到 main.cpp:

#include <Qt3DRender/QObjectPicker>
#include <Qt3DRender/QPickEvent>
#include <QObject>
#include <QtWidgets/QApplication>
#include <QGuiApplication>
#include <QtWidgets/QMainWindow>

在 main.cpp/createScene() 的末尾添加以下代码,就在 return 语句之前:

    Qt3DRender::QObjectPicker* picker = new Qt3DRender::QObjectPicker();
    QObject::connect(picker, &Qt3DRender::QObjectPicker::clicked, material, [material](Qt3DRender::QPickEvent *pickEvent){
                qDebug() << "Sphere  clicked";
                static_cast<Qt3DExtras::QPhongMaterial*>(material)->setAmbient(QColor(rand()%255,rand()%255,rand()%255));
            });
    sphereEntity->addComponent(picker);

要为 Android 编译和部署,请创建一个 AndroidManifest.xml 并从 "android:configChanges" 中删除 "density" 标志。 运行 应用程序应显示环面和移动的球体,当触摸球体时,两者的颜色会随机变化。

接下来将 main.cpp/main() 中的 QGuiApplication app(argc, argv); 替换为 QApplication app(argc, argv); 并在 return 语句之前附加以下代码:

    QMainWindow* mainWindow = new QMainWindow();
    mainWindow->resize(800, 600);
    auto centralwidget = new QWidget(mainWindow);
    mainWindow->setCentralWidget(centralwidget);
    auto container = QMainWindow::createWindowContainer(&view,mainWindow->centralWidget());
    mainWindow->show();
    container->resize(mainWindow->centralWidget()->size());

现在 Android 应用程序在小部件内显示相同的场景,但触摸球体不会改变颜色。 (在 Windows 上相反)

注释掉最后三行使示例再次运行:

    //auto container = QMainWindow::createWindowContainer(&view,mainWindow->centralWidget());
    //mainWindow->show();
    //container->resize(mainWindow->centralWidget()->size());

知道这是配置错误还是错误吗?

对象选择器只能通过鼠标点击来工作。如果你需要触摸手势,你需要使用 QScreenRayCaster 说明

感谢 user3405291 的提示,我终于在 Android 上工作了,方法是将事件过滤器附加到 QMainWindow::createWindowContainer 返回的容器小部件,过滤掉 QEvent::MouseButtonRelease,调用 QScreenRayCaster::trigger 以事件位置作为参数并通过 QScreenRayCaster::hitsChanged 接收拾取的对象。 在 Windows 上,此过程也有效,但前提是事件过滤器附加到 Qt3DWindow 本身,而不是容器小部件。 我的假设是,在 Windows 上,鼠标事件从容器小部件转发到 Qt3DWindow,而在 Android 上,它们由容器小部件使用。由于 QObjectPicker 似乎(仅)监听 Qt3DWindow 上的事件,因此它在 Android 上无法正常工作,并且没有手动将事件转发给它的选项。 但这只是一个肤浅的印象,如果有任何进一步的说明,我会很高兴。