Я работаю над проектом C ++, который использует OpenVR для связи с HTC Vive Kit. Идея состоит в том, чтобы разработать библиотеку с меню, которое будет отображаться в среде виртуальной реальности, из которого пользователь может изменять некоторые параметры программы.
Я пытаюсь реализовать такое меню, как 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);
Заранее спасибо,
Lorenzo
РЕДАКТИРОВАТЬ: Добавлен соответствующий код.
РЕДАКТИРОВАТЬ: Переключен на стиль Qt5 для подключений. Он все еще компилируется и запускается, но события никогда не вызываются.
Задача ещё не решена.
Других решений пока нет …