OSG在事件处理中由于模态对话框导致后续事件出错的问题

问题描述:

在OSG的事件处理GUIEventHandler中,当我们需要操作打开一个模态对话框(非模态的对话框并没有问题)的时候,在关闭模态对话框之后导致后续的事件处理异常。


本文以osgQt为例,描述这一问题的出现以及解决方式。程序很简单,在窗口中点击右键弹出对话框,加载选择的模型。代码如下:

class ViewerWidget : public QWidget, public osgViewer::Viewer
{
	Q_OBJECT
public:
	ViewerWidget(QWidget* parent = 0, Qt::WindowFlags f = 0): QWidget(parent, f)
	{
		setThreadingModel(ViewerBase::SingleThreaded);
		QWidget* renderWidget = createViewWidget(createGraphicsWindow(0, 0, 100, 100), nullptr);

		QGridLayout* grid = new QGridLayout;
		grid->addWidget(renderWidget, 0, 0);
		grid->setMargin(1);
		setLayout(grid);

		_testHandler = new TestHandler();
		this->addEventHandler(_testHandler);


		connect(_testHandler, SIGNAL(rightButtonClickedSignal()), this, SLOT(rightButtonClickedSlot()));
		connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
		_timer.start(10);
	}

	QWidget* createViewWidget(osgQt::GraphicsWindowQt* gw, osg::Node* scene)
	{
		osg::Camera* camera = this->getCamera();
		camera->setGraphicsContext(gw);

		const osg::GraphicsContext::Traits* traits = gw->getTraits();

		camera->setClearColor(osg::Vec4(0.2, 0.2, 0.4, 1.0));
		camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
		camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0f, 10000.0f);

		this->setSceneData(scene);
		this->setCameraManipulator(new osgGA::TrackballManipulator());

		return gw->getGLWidget();
	}

	osgQt::GraphicsWindowQt* createGraphicsWindow(int x, int y, int w, int h, const std::string& name = "", bool windowDecoration = false)
	{
		osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
		osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
		traits->windowName = name;
		traits->windowDecoration = windowDecoration;
		traits->x = x;
		traits->y = y;
		traits->width = w;
		traits->height = h;
		traits->doubleBuffer = true;
		traits->alpha = ds->getMinimumNumAlphaBits();
		traits->stencil = ds->getMinimumNumStencilBits();
		traits->sampleBuffers = ds->getMultiSamples();
		traits->samples = ds->getNumMultiSamples();

		return new osgQt::GraphicsWindowQt(traits.get());
	}

	virtual void paintEvent(QPaintEvent* event)
	{
		frame();
	}

public slots:
	bool rightButtonClickedSlot();

protected:

	QTimer _timer;
	TestHandler* _testHandler;
};

该类中添加的TestHandler的代码如下:

	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		switch (ea.getEventType())
		{
		case osgGA::GUIEventAdapter::PUSH:
		{
			if (ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
			{
				 QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"),
					"/home",
					tr("Models (*.osg *.osgb *.osgt)"));

				 if (!fileName.isEmpty())
				 {
					 QByteArray fileByteArray = fileName.toLocal8Bit();
					 std::string fileNameStdString = fileByteArray.constData();

					 osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
					 if (viewer)
					 {
						 viewer->setSceneData(osgDB::readNodeFile(fileNameStdString));
					 }
				 }

			}

			return false;
		}
		break;


		case osgGA::GUIEventAdapter::DRAG:
		{
			if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
			{
				return false;
			}
			else if (ea.getButtonMask() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
			{
				return false;
			}

			return false;
		}

		case osgGA::GUIEventAdapter::MOVE:
		{
			return false;
		}

		default:
			break;
		}
		return false;
	}

运行程序,在点击右键之后弹出打开文件的对话框,选择osg的文件之后,发现场景加载进来之后鼠标在移动的时候触发了右键的Drag事件,导致模型一直在缩放中。


鼠标的Move事件被解析为了右键的Drag事件(感觉上是右键一直在被按下的效果)。

解决方式:

出现的原因暂时未知,但是感觉上是OSG的事件封装和Qt的事件出现了冲突,于是将弹窗放到Qt的事件中处理:

让TestEventHandler继承自QObject,并将窗体的事件处理器安装在EventTest上,在事件处理器中处理右键点击打开文件:

class TestHandler : public QObject, public osgGA::GUIEventHandler
{
	Q_OBJECT

public:
	TestHandler(QWidget *w)
	{ 
		_widget = w;
	}

	~TestHandler(){ }


	bool eventFilter(QObject *obj, QEvent *event)
	{
		if (event->type() == QEvent::MouseButtonPress)
		{
			QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
			if (mouseEvent->button() == Qt::RightButton)
			{
				QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"),
					"/home",
					tr("Models (*.osg *.osgb *.osgt)"));

				if (!fileName.isEmpty())
				{
					QByteArray fileByteArray = fileName.toLocal8Bit();
					std::string fileNameStdString = fileByteArray.constData();

					osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(_widget);
					if (viewer)
					{
						viewer->setSceneData(osgDB::readNodeFile(fileNameStdString));
					}
				}

				return true;
			}
			else
			{
				return QObject::eventFilter(obj, event);
			}
			
		}
		else {
			return QObject::eventFilter(obj, event);
		}
	}



	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		switch (ea.getEventType())
		{
		case osgGA::GUIEventAdapter::PUSH:
		{
			//if (ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
			//{

			//}

			return false;
		}
		break;


		case osgGA::GUIEventAdapter::DRAG:
		{
			if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
			{
				return false;
			}
			else if (ea.getButtonMask() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
			{
				return false;
			}

			return false;
		}

		case osgGA::GUIEventAdapter::MOVE:
		{
			return false;
		}

		default:
			break;
		}
		return false;
	}


signals:
	bool rightButtonClickedSignal();


protected:
	QWidget* _widget;
};

同时在主窗口的构造函数中安装这个事件处理器

		_testHandler = new TestHandler(this);
		this->addEventHandler(_testHandler);
		renderWidget->installEventFilter(_testHandler);

修改代码之后再次运行程序,右键调出对话框选择文件加载之后,一切正常了。


本文提供了一种处理的思路,其实也可以不用事件过滤这种方式来做,直接在主窗体的事件中处理即可。只是想说明这个问题的处理方式是让弹窗的处理在Qt中进行。这可能是OSG的一个事件封装的Bug。





  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值