1

我正在开发一个使用 OpenVR 与 HTC Vive 套件通信的 C++ 项目。这个想法是开发一个带有菜单的库,在 VR 环境中显示,用户可以从中更改程序的一些参数。

我正在尝试将此类菜单实现为 ​​QWidget,如官方 OpenVR 示例中所示。我的问题是,在这个项目中已经有一个主(我可以访问但我不想干扰它)在我的代码执行之前创建和启动一个 QApplication 。

我设法创建了 QWidget,但由于某些原因,它的插槽根本没有被调用。我怀疑这与我没有以某种方式在事件循环中“注册”我的 QWidget 的事实有关,但问题可能出在其他地方。

简而言之,如果这甚至是问题,那么如果 QApplication 已经在运行,那么连接槽和信号如何工作?


这是我的测试 QWidget,非常基础。

#include "overlaywidget.h"
#include "ui_overlaywidget.h"

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

OverlayWidget::~OverlayWidget()
{
    delete ui;
}

void OverlayWidget::on_pushButton_clicked()
{
    QApplication::quit();
}

这是控制器,直接取自我上面链接的 OpenVR 示例。我剥离了所有不必要的东西

#include "openvroverlaycontroller.h"

#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLPaintDevice>
#include <QPainter>
#include <QtWidgets/QWidget>
#include <QMouseEvent>
#include <QtWidgets/QGraphicsSceneMouseEvent>
#include <QtWidgets/QApplication>
#include <QtWidgets/QGraphicsEllipseItem>
#include <QCursor>
#include <QObject>
#include <QMainWindow>

using namespace vr;

COpenVROverlayController *s_pSharedVRController = NULL; // I guess this makes it visibile in the global scope

COpenVROverlayController *COpenVROverlayController::SharedInstance()
{
    if ( !s_pSharedVRController )
    {
        s_pSharedVRController = new COpenVROverlayController(QApplication::instance());
    }
    return s_pSharedVRController;
}

COpenVROverlayController::COpenVROverlayController(QObject * parent)
    : BaseClass(parent)
    , m_eLastHmdError( vr::VRInitError_None )
    , m_eCompositorError( vr::VRInitError_None )
    , m_eOverlayError( vr::VRInitError_None )
    , m_strVRDriver( "No Driver" )
    , m_strVRDisplay( "No Display" )
    , m_pOpenGLContext( NULL )
    , m_pScene( NULL )
    , m_pOffscreenSurface ( NULL )
    , m_pFbo( NULL )
    , m_pWidget( NULL )
    , m_pPumpEventsTimer( NULL )
    , m_lastMouseButtons( 0 )
    , m_ulOverlayHandle( vr::k_ulOverlayHandleInvalid )
    , m_bManualMouseHandling( false )
{
}

bool COpenVROverlayController::Init()
{
    bool bSuccess = true;

    m_strName = "systemoverlay";

    QStringList arguments = qApp->arguments();

    int nNameArg = arguments.indexOf( "-name" );
    if( nNameArg != -1 && nNameArg + 2 <= arguments.size() )
    {
        m_strName = arguments.at( nNameArg + 1 );
    }

    QSurfaceFormat format;
    format.setMajorVersion( 4 );
    format.setMinorVersion( 1 );
    format.setProfile( QSurfaceFormat::CompatibilityProfile );

    m_pOpenGLContext = new QOpenGLContext();
    m_pOpenGLContext->setFormat( format );
    bSuccess = m_pOpenGLContext->create();
    if( !bSuccess )
        return false;

    // create an offscreen surface to attach the context and FBO to
    m_pOffscreenSurface = new QOffscreenSurface();
    m_pOffscreenSurface->create();
    m_pOpenGLContext->makeCurrent( m_pOffscreenSurface );

    m_pScene = new QGraphicsScene();

    // This is where I connect to the QGraphicsScene
    connect(m_pScene, &QGraphicsScene::changed, this, &COpenVROverlayController::OnSceneChanged);

    // Loading the OpenVR Runtime
    bSuccess = ConnectToVRRuntime();

    bSuccess = bSuccess && vr::VRCompositor() != NULL;

    if( vr::VROverlay() )
    {
        std::string sKey = std::string( "sample." ) + m_strName.toStdString();

        vr::VROverlayError overlayError = vr::VROverlay()->CreateDashboardOverlay( sKey.c_str(), m_strName.toStdString().c_str(), &m_ulOverlayHandle, &m_ulOverlayThumbnailHandle);

        bSuccess = bSuccess && overlayError == vr::VROverlayError_None;
    }

    if( bSuccess )
    {
        vr::VROverlay()->SetOverlayWidthInMeters( m_ulOverlayHandle,1.5f );
        vr::VROverlay()->SetOverlayInputMethod( m_ulOverlayHandle, vr::VROverlayInputMethod_Mouse );

        m_pPumpEventsTimer = new QTimer( this );

        // This is where I connect to the QTimer
        connect(m_pPumpEventsTimer, &QTimer::timeout, this, &COpenVROverlayController::OnTimeoutPumpEvents);
        m_pPumpEventsTimer->setInterval( 20 );
        m_pPumpEventsTimer->start();


    }
    return true;
}

// First slot, never being called
void COpenVROverlayController::OnSceneChanged( const QList<QRectF>& )
{
    /* ... code ... */
}


// Second slot, never being called
void COpenVROverlayController::OnTimeoutPumpEvents()
{
    /* ... */

}


void COpenVROverlayController::SetWidget( QWidget *pWidget )
{
    if( m_pScene )
    {
        // all of the mouse handling stuff requires that the widget be at 0,0
        // (else, the widget will still be there, but it will behave as if it's trasnlated)
        pWidget->move( 0, 0 );
        m_pScene->addWidget( pWidget );
    }
    m_pWidget = pWidget;

    m_pFbo = new QOpenGLFramebufferObject( pWidget->width(), pWidget->height(), GL_TEXTURE_2D );

    if( vr::VROverlay() )
    {
        vr::HmdVector2_t vecWindowSize =
        {
            (float)pWidget->width(),
            (float)pWidget->height()
        };
        vr::VROverlay()->SetOverlayMouseScale( m_ulOverlayHandle, &vecWindowSize );
    }

}

这是我在我的库的其他类之一的构造函数中设置这两者的方法(只要按下应用程序的“VR”按钮,在应用程序已经运行的任何时候都会调用它) .

  OverlayWidget *pOverlayWidget = new OverlayWidget(this->getMainWindow());

  // Basicallly creates a new OverlayController and calls Init
  this->controller = COpenVROverlayController::SharedInstance();
  this->controller->Init();

  // On that same controller, sets the OverlayWidget
  this->controller->SetWidget(pOverlayWidget);

提前谢谢你,洛伦佐

编辑:添加了相关代码。 编辑:切换到 Qt5 样式进行连接。它仍然可以编译和运行,但永远不会调用这些事件。

4

0 回答 0