Qt - 如何在 Qt3DWindow 上获取鼠标事件

Qt - How to get mouse events on Qt3DWindow

我想在 Qt3D Window 上获取鼠标事件(如鼠标位置),每次我在 window.

中单击时

我看过 (also the same question on this forum) 但我的 Qt3DWindow 不在任何小部件中,所以我认为我不需要 EventFilter。

我刚刚开始学习 C++ 和 Qt,所以我正在努力使最简单的程序成为可能。在下面的代码中(我所有的程序都在这段代码中),我想在Qt3DWindow中每次点击时都得到鼠标位置,但我什至无法在每次点击时得到调试消息。

据我了解,mouseMoveEvent 函数仅在程序执行时调用一次。如果 Qt 中有这样的东西,我将如何在主循环中调用这个函数?

我需要做这样的事情吗?

Qt3DInput::QMouseDevice *mouse = new Qt3DInput::QMouseDevice(scene);

但是我该如何使用它呢?

#include <QGuiApplication>

#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QCameraLens>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>

#include <Qt3DInput/QInputAspect>

#include <Qt3DRender/QRenderAspect>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/QGoochMaterial>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QCuboidMesh>

#include <QMouseEvent>
#include <Qt3DInput/QMouseDevice>
#include <Qt3DInput/QMouseHandler>
#include <Qt3DInput/QMouseEvent>

#include <QDebug>

#include "qt3dwindow.h"

void mouseMoveEvent(Qt3DInput::QMouseEvent *event);

Qt3DCore::QEntity *createScene()
{
    // Root entity
    Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity;

    // Material
    //Qt3DRender::QMaterial *material = new Qt3DExtras::QPhongMaterial(rootEntity);
    Qt3DRender::QMaterial *material = new Qt3DExtras::QGoochMaterial(rootEntity);

    //Cube
    Qt3DCore::QEntity *cubeEntity = new Qt3DCore::QEntity(rootEntity);
    Qt3DExtras::QCuboidMesh *cubeMesh = new Qt3DExtras::QCuboidMesh;

    cubeEntity->addComponent(cubeMesh);
    cubeEntity->addComponent(material);

    return rootEntity;
}

int main(int argc, char* argv[])
{
    QGuiApplication app(argc, argv);
    Qt3DExtras::Qt3DWindow view;

    Qt3DCore::QEntity *scene = createScene();

    // Camera
    Qt3DRender::QCamera *camera = view.camera();
    camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
    camera->setPosition(QVector3D(5.0, 5.0, 5.0f));
    camera->setViewCenter(QVector3D(0, 0, 0));

    Qt3DInput::QMouseEvent *e;

    mouseMoveEvent(e);

    view.setRootEntity(scene);
    view.show();

    return app.exec();
}

void mouseMoveEvent(Qt3DInput::QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        qDebug() << "ok";
    }
}

通常 "mouseMoveEvent" 与 Qwidget 绑定。​​

这是Qt3DInput::QmouseEvent的源代码:

class QT3DINPUTSHARED_EXPORT QMouseEvent : public QObject {
    Q_OBJECT 
private:
    QT_PREPEND_NAMESPACE(QMouseEvent) m_event;  
};

m_event已经包含了您鼠标的信息,应该会自动处理。

Mouse events occur when a mouse button is pressed or released inside a widget, or when the mouse cursor is moved.

所以,我认为您不需要创建新的 Qt3DInput::QMouseDevice。你不应该这样做 Qt3DInput::QMouseEvent *e;因为小部件会自动获取它。

我不知道如何在不在 Qwidget 中覆盖它的情况下使用 mouseEvent,Qt3DExtras::Qt3DWindow 视图应该包含默认值 mouseMoveEvent()。 如果你只想打印一个"ok",我建议你不要写任何关于mouseMoveEvent()的东西。如果您希望鼠标移动时发生某些事情,您应该覆盖视图的 mouseMoveEvent().

你在这里做错了几件事。

首先,我建议你subclass Qt3DWindow 并将场景的设置代码放在那里。这毕竟是意见责任。主体应该保持简单和干净。当然不要在视图中放置任何重要的逻辑,但设置代码应该在那里(坚持模型-视图-控制器)。

接下来,您当然不会收到任何调试消息,因为您在那里进行了检查

if (event->button() == Qt::LeftButton)

但是您创建事件时从未设置过按钮,因此 event->button() 永远不会等于 Qt::LeftButton

我写了一些示例代码来帮助您开始使用这些事件:

main.cpp:

#include <QApplication>
#include "clickwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ClickWindow clickWindow;
    clickWindow.show();
    return a.exec();
}

clickwindow.h(我省略了头球后卫以节省一些 space):

#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DCore/QEntity>

class ClickWindow : public Qt3DExtras::Qt3DWindow {
public:
    ClickWindow();
    // Here we say we want to have a custom handling of click events
    void mousePressEvent(QMouseEvent *eventPress) override;

private:
    Qt3DCore::QEntity *createScene();
};

clickwindow.cpp:

#include "clickwindow.h"
#include <QDebug>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QMaterial>
#include <Qt3DExtras/QGoochMaterial>
#include <Qt3DExtras/QCuboidMesh>

ClickWindow::ClickWindow() : Qt3DExtras::Qt3DWindow() {
    // You could also create a dedicated setup method
    setRootEntity(createScene());
    Qt3DRender::QCamera *camera = this->camera();
    camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
    camera->setPosition(QVector3D(5.0, 5.0, 5.0f));
    camera->setViewCenter(QVector3D(0, 0, 0));
}

void ClickWindow::mousePressEvent(QMouseEvent *eventPress) {
    // No need to pass it on to the parent! It will receive it
    // anyway. You can stop event propagation by calling
    // eventPress->accept();
    // This is where the click is received
    qDebug() << "Click!";
}


Qt3DCore::QEntity* ClickWindow::createScene() {
    // Root entity
    Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity;

    // Material
    //Qt3DRender::QMaterial *material = new Qt3DExtras::QPhongMaterial(rootEntity);
    Qt3DRender::QMaterial *material = new Qt3DExtras::QGoochMaterial(rootEntity);

    //Cube
    Qt3DCore::QEntity *cubeEntity = new Qt3DCore::QEntity(rootEntity);
    Qt3DExtras::QCuboidMesh *cubeMesh = new Qt3DExtras::QCuboidMesh;

    cubeEntity->addComponent(cubeMesh);
    cubeEntity->addComponent(material);

    return rootEntity;
}

您还可以使用 Qt3D classes 处理点击,并遵循此示例 here, but to me, depending on your application, this seems a bit over the top. If you simply want to receive the 2D screen coordinates I'd prefer the solution above. If you need custom inputs for e.g. clicking on an object I answered a question regarding this here or if you simply need the 3D coordinates clicked on an object you can use the QObjectPicker class。

如果您遇到任何 QML 代码,请记住 QML 代码只是实例化 C++ classes,也就是说,您可以转移示例,有时会在命名等方面做一些细微的改动。