将OSG嵌入QT窗口系统中,实现拖拽界面
一、原理
OSG底层使用的是OpenGL图形系统,QT也增加了对OpenGL的支持,因此,可以通过QT的OpenGL模块,实现将OSG窗口嵌入到QT中,这样可以充分利用QT的UI界面设计,满足OSG的2D的界面系统的不足。当然除了使用OSG做2D渲染特效,可以尽情享受QT界面设计带来的方便。

二、准备
1. QT对OpenGL的支持:
QT中,场景视图模型模块,可以使用OpenGL绘制基本图元。视图,即:QGraphicsView ,场景,即:QGraphicsScene,当然还有基本图元项,QGraphicsItem,这里暂不介绍。
简单设计思路:我们新建一个QT MainWindow项目。首先,将场景,加入到视图中,接着,将视图加入MainWindow中,这样以后,我们就可以使用MainWindow在视图中浏览场景,场景包含OSG内容,这样,我们就达到了目的。
2. OSG窗口移植:
OSG的窗口API中,可以嵌入各种各样的窗口系统,这给我移植到QT带来的可能,在OSG参考文档中,我选择使用GraphicsWindowEmbedded 来创建可移植的窗口。
三、QT 模型视图框架
QT环境:
qt-opensource-windows-x86-msvc2010_opengl-5.4.1.exe
qt-vs-addin-1.2.4-opensource.exe
设计:
视图类QGraphicsView
GLView.h
GLView.cpp
文件:GLView.h#pragma once
#include <QtWidgets/QGraphicsView>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QResizeEvent>
#include "GLScene.h"
class GLView :
public QGraphicsView
{
public:
GLView(QWidget *parent = 0);
~GLView(void);
protected:
//更新视图的时候,更新场景
void resizeEvent(QResizeEvent *event);
public:
QGLWidget *m_widget;
GLScene *m_scene;
};
#pragma once
#include <QtWidgets/QGraphicsView>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QResizeEvent>
#include "GLScene.h"
class GLView :
public QGraphicsView
{
public:
GLView(QWidget *parent = 0);
~GLView(void);
protected:
//更新视图的时候,更新场景
void resizeEvent(QResizeEvent *event);
public:
QGLWidget *m_widget;
GLScene *m_scene;
};
文件:GLView.cpp
#include "GLView.h"
#include <QtWidgets/QMessageBox>
GLView::GLView(QWidget *parent):
QGraphicsView(parent)
,m_widget(new QGLWidget(QGLFormat(QGL::DoubleBuffer)))
,m_scene(new GLScene(this))
{
this->resize(800,600);//设置视口大小
this->setViewport(m_widget);//将m_widget设置为视口:为了使用OpenGL渲染,你要设置一个新的QGLWidget作为QGraphicsView的视口
m_widget->setMouseTracking(true);//鼠标追踪
this->viewport()->setMinimumSize(1,1);
this->setScene(m_scene);
this->setMinimumSize(1,1); //设置视图的最小尺寸
this->scene()->setSceneRect(0,0,this->width(),this->height());//设置场景大小
this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);//设置视图的更新方式:整个视图更新
}
GLView::~GLView(void)
{
}
//更新视图的时候,更新场景
void GLView::resizeEvent( QResizeEvent *event )
{
//更新场景大小
m_scene->setSceneRect(this->rect().left(),this->rect().right(),this->rect().width(),this->rect().height());
m_scene->resizeViewer();
}
场景类QGraphicsScene
文件:GLScene.h
#pragma once
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/qgraphicsscene.h>
#include <QtWidgets/QGraphicsSceneEvent>
#include <QTimerEvent>
#include <QtGui//QPainter>
#include "OsgLib.h"
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/ViewerEventHandlers>
#include "KeyBoardMap.h"
static KeyBoardMap s_QtKeyboardMap;//按键映射
class GLScene :
public QGraphicsScene
{
public:
GLScene(QObject *parent = 0);
~GLScene(void);
protected:
//绘制场景
void drawBackground(QPainter *painter, const QRectF &rect);
//窗口更新函数:使用定时器,定时更新
void timerEvent(QTimerEvent *);
protected:
//鼠标事件
void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent);
void wheelEvent(QGraphicsSceneWheelEvent * wheelEvent);
//键盘按键
void keyPressEvent(QKeyEvent * keyEvent);
void keyReleaseEvent(QKeyEvent * keyEvent);
int timer_id;
public:
//更新OSG窗口
void resizeViewer();
void setKeyboardModifiers( QInputEvent* event );//组合键
public:
osg::ref_ptr<osgViewer::Viewer> m_viewer;
};
文件:GLScene.cpp
#include "GLScene.h"
GLScene::GLScene(QObject *parent):
QGraphicsScene(parent)
,m_viewer(NULL)
,timer_id(0)
{
//OSG初始化
m_viewer = new osgViewer::Viewer;
m_viewer->setUpViewerAsEmbeddedInWindow(0,0,800,600);//设置窗口的嵌入大小
m_viewer->setSceneData(osgDB::readNodeFile("glider.osg"));
m_viewer->setCameraManipulator(new osgGA::TrackballManipulator);//添加操作器
m_viewer->addEventHandler(new osgViewer::StatsHandler);//状态信息
m_viewer->realize();//实例化GraphicsContext
timer_id = startTimer(0);//当定时器触发时,应用程序会发送一个QTimerEvent,如果参数为0,那么定时器事件每次发生时没有窗口系统事件处理。
}
GLScene::~GLScene(void)
{
}
//绘制场景
void GLScene::drawBackground( QPainter *painter, const QRectF &rect )
{
painter->beginNativePainting();
painter->setRenderHint(QPainter::Antialiasing);//抗锯齿
m_viewer->frame();
//m_viewer->getViewerBase()->frame();
painter->endNativePainting();
}
//窗口更新函数
void GLScene::timerEvent(QTimerEvent *)
{
this->update();
}
void GLScene::mousePressEvent( QGraphicsSceneMouseEvent * mouseEvent )
{
//std::cout<<"mousePressEvent"<<std::endl;
QGraphicsScene::mousePressEvent(mouseEvent);
int button = 0;
switch ( mouseEvent->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
//_gw->getEventQueue()->mouseButtonRelease( event->x(), event->y(), button );
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->mouseButtonPress( mouseEvent->scenePos().x(), mouseEvent->scenePos().y(), button );
}
void GLScene::mouseReleaseEvent( QGraphicsSceneMouseEvent * mouseEvent )
{
//std::cout<<"mouseReleaseEvent"<<std::endl;
QGraphicsScene::mouseReleaseEvent(mouseEvent);
int button = 0;
switch ( mouseEvent->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->mouseButtonRelease( mouseEvent->scenePos().x(), mouseEvent->scenePos().y(), button );
}
void GLScene::mouseMoveEvent( QGraphicsSceneMouseEvent * mouseEvent )
{
//std::cout<<"mouseMoveEvent"<<std::endl;
QGraphicsScene::mouseMoveEvent(mouseEvent);
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->mouseMotion( mouseEvent->scenePos().x(), mouseEvent->scenePos().y());
}
void GLScene::mouseDoubleClickEvent( QGraphicsSceneMouseEvent * mouseEvent )
{
//std::cout<<"mouseDoubleClickEvent"<<std::endl;
QGraphicsScene::mouseDoubleClickEvent(mouseEvent);
int button = 0;
switch ( mouseEvent->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->mouseDoubleButtonPress( mouseEvent->scenePos().x(), mouseEvent->scenePos().y(), button );
}
void GLScene::wheelEvent( QGraphicsSceneWheelEvent * wheelEvent )
{
//std::cout<<"wheelEvent"<<std::endl;
QGraphicsScene::wheelEvent(wheelEvent);
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->mouseScroll(
wheelEvent->orientation() == Qt::Vertical ?
(wheelEvent->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
(wheelEvent->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) );
}
void GLScene::keyPressEvent( QKeyEvent * keyEvent )
{
setKeyboardModifiers(keyEvent);
int value = s_QtKeyboardMap.remapKey( keyEvent );
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->keyPress( value );
QGraphicsScene::keyPressEvent(keyEvent);
}
void GLScene::keyReleaseEvent( QKeyEvent * keyEvent )
{
//std::cout<<"keyReleaseEvent"<<std::endl;
QGraphicsScene::keyReleaseEvent(keyEvent);
int value = s_QtKeyboardMap.remapKey( keyEvent );
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->keyRelease( value );
QGraphicsScene::keyPressEvent(keyEvent);
}
//OSG场景窗口更新
void GLScene::resizeViewer()
{
//更新OSG窗口大小
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->resized(this->sceneRect().x(),this->sceneRect().y(),this->sceneRect().width(),this->sceneRect().height());
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->windowResize(this->sceneRect().x(),this->sceneRect().y(),this->sceneRect().width(),this->sceneRect().height());//? 更新状态S按键
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->requestRedraw();//?
}
//组合键
void GLScene::setKeyboardModifiers( QInputEvent* event )
{
int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
unsigned int mask = 0;
if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
(dynamic_cast<osgViewer::GraphicsWindow*> (m_viewer->getCamera()->getGraphicsContext()))->getEventQueue()->getCurrentEventState()->setModKeyMask( mask );
}
QMainWindow类
文件:qtosgmainwindow.h
#ifndef QTOSGMAINWINDOW_H
#define QTOSGMAINWINDOW_H
#include <QtWidgets/QMainWindow>
#include "ui_qtosgmainwindow.h"
#include "GLView.h"
class QtOsgMainWindow : public QMainWindow
{
Q_OBJECT
public:
QtOsgMainWindow(QWidget *parent = 0);
~QtOsgMainWindow();
protected:
//更新视图
void resizeEvent(QResizeEvent *);
private:
Ui::QtOsgMainWindowClass ui;
GLView *m_glview;
};
#endif // QTOSGMAINWINDOW_H
文件:qtosgmainwindow.cpp
#include "qtosgmainwindow.h"
QtOsgMainWindow::QtOsgMainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->resize(800,600);//MainWindow设置窗口大小
this->setCorner(Qt::BottomLeftCorner,Qt::LeftDockWidgetArea);
this->setCorner(Qt::BottomRightCorner,Qt::RightDockWidgetArea);
this->setCorner(Qt::TopLeftCorner,Qt::LeftDockWidgetArea);
this->setCorner(Qt::TopRightCorner,Qt::RightDockWidgetArea);
ui.gridLayout->setMargin(-1);
m_glview = new GLView(this);
//隐藏滚动条
m_glview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_glview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->layout()->addWidget(m_glview);
}
QtOsgMainWindow::~QtOsgMainWindow()
{
}
void QtOsgMainWindow::resizeEvent( QResizeEvent * )
{
std::cout<<"MainWindow resizeEvent."<<std::endl;
m_glview->resize(this->rect().width(),this->rect().height());//更新视图
}
注:文件使用KeyBoardMap.h等文件,注释掉即可,该文件用于QT按键与OSG按键的映射.
五、Main函数
#include "qtosgmainwindow.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtOsgMainWindow w;
w.show();
return a.exec();
}