Search code examples
c++qtqt3d

Qt3D input handling system works differently depending on the place it was created


I was implementing a custom camera controller for Qt3DRender::QCamera and I faced a rather strange behavior of the Qt3DInput::QMouseHandler. Depending on the environment it was created it either responds to mouse events or not. There are two cases: create both the device and the handler in the MainWindow object or create them inside my camera controller class (it only works in the first case).

First case:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    auto* window = new Qt3DExtras::Qt3DWindow();

    auto* window_container = QWidget::createWindowContainer(window, this, Qt::Widget);
    setCentralWidget(window_container);

    auto* scene = new Qt3DCore::QEntity();
    window->setRootEntity(scene);

    auto* mouse_device = new Qt3DInput::QMouseDevice(scene);
    auto* mouse_handler = new Qt3DInput::QMouseHandler(scene);
    mouse_handler->setSourceDevice(mouse_device);

    connect(mouse_handler, &Qt3DInput::QMouseHandler::positionChanged,
        [](Qt3DInput::QMouseEvent* event)
        {
            qDebug() << "I am actually printing to console!!!";
        });
}

Second case:

class CustomCameraController final : public Qt3DCore::QNode
{
Q_OBJECT

public:
    explicit CustomCameraController(Qt3DCore::QNode* parent = nullptr)
      : Qt3DCore::QNode(parent),
        mouse_device(new Qt3DInput::QMouseDevice(this)),
        mouse_handler(new Qt3DInput::QMouseHandler(this))
    {
        mouse_handler->setSourceDevice(mouse_device);

        connect(mouse_handler, &Qt3DInput::QMouseHandler::pressAndHold, this,
          &CustomCameraController::MousePositionChanged);
    }

public slots:
    void MousePositionChanged(Qt3DInput::QMouseEvent* event)
    {
        qDebug() << "I am not printing anything...";
    }

protected:
    Qt3DInput::QMouseDevice* mouse_device;
    Qt3DInput::QMouseHandler* mouse_handler;
};


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    auto* window = new Qt3DExtras::Qt3DWindow();

    auto* window_container = QWidget::createWindowContainer(window, this, Qt::Widget);
    setCentralWidget(window_container);

    auto* scene = new Qt3DCore::QEntity();
    window->setRootEntity(scene);

    auto* controller = new CustomCameraController(scene);
}

All the unnecessary code was removed. The main.cpp file was automatically generated by Qt Framework

I searched all through the Qt documentation and found nothing that would help me in this scenario. I also noticed that if the device and the handler are initialized in the constructor with parent as the parameter it does not help. Furthermore, I tried to create the device and the handler in the MainWindow scope and pass them to the controller via some setter function but it does not help neither.

So the questions I want to ask: what is the proper way of using Qt3DInput::QMouseDevice and Qt3DInput::QMouseHandler? Is there a better workaround for implementing input handling for my custom camera controller?

Update 1:

You should add the controller class declaration to the header instead of main window source file. Here are all the includes and the qmake options you are going to need:

#include <Qt3DCore/QNode>
#include <Qt3DInput/QMouseDevice>
#include <Qt3DInput/QMouseHandler>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DCore/QEntity>

3dinput 3dcore 3dextras


Solution

  • Looks like you just connected to different signals.
    In first case you are using &Qt3DInput::QMouseHandler::positionChanged which will be sended quite often. In second one - &Qt3DInput::QMouseHandler::pressAndHold which will be sended when a mouse button is pressed and held down.
    After fix both logging functions are called.