【librviz源码解读】Tool类的添加和鼠标事件处理

编程入门 行业动态 更新时间:2024-10-10 15:23:44

【librviz源码解读】Tool类的添加和<a href=https://www.elefans.com/category/jswz/34/1769042.html style=鼠标事件处理"/>

【librviz源码解读】Tool类的添加和鼠标事件处理

文章目录

  • 前言
  • 1 Tool类的添加和鼠标事件处理
    • 1.1 已注册工具类的添加
    • 1.2 鼠标事件的传递和处理
    • 1.3 实现工具类的无注册调用
  • 总结


前言

在使用rviz库编写自己的工具的时候,需要使用这样的语句,将工具注册到pluginlib。

#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(robot_upper_plugins::RouteGoalTool, rviz::Tool )

需要启用工具时,需要用注册时的名称来添加到tool_manager,类似于:

addTool("robot_upper_plugins/RouteGoalTool");

让我们来看看librviz是怎么从插件库中加载和启用工具类的。


1 Tool类的添加和鼠标事件处理

1.1 已注册工具类的添加

工具类添加到插件库后,当我们在rviz中点击添加工具,对应到代码里,就是调用了ToolManager类的addTool方法,用插件库内的唯一命名来创建工具,像这样:

void ToolManager::initialize()
{// 这些都是rviz中的默认插件addTool( "rviz/MoveCamera" );addTool( "rviz/Interact" );addTool( "rviz/Select" );addTool( "rviz/SetInitialPose" );addTool( "rviz/SetGoal" );
}

在visualization_manager.cpp内:

当VisualizationManager实例化ToolManager后,成为其上下文;

tool_manager_ = new ToolManager( this );

在ToolManager.cpp内

addTool():根据插件class_id从工厂创建一个tool,将VisualizationManager作为context传入tool->initialize()。最后发出toolAdded(tool)信号;

ToolManager::ToolManager( DisplayContext* context ) : context_( context ) {}Tool* ToolManager::addTool( const QString& class_id )
{Tool* tool = factory_->make( class_id, &error );tools_.append( tool );tool->initialize( context_ );Q_EMIT toolAdded( tool );
}

在visualization_frame.cpp内

addTool( Tool* tool ):toolAdded()的槽,当接收到toolAdded()信号,创建一个qaction到toolbar_actions_组里;

当这个qaction被触发时,调用ToolManager()->setCurrentToo()

connect( tool_man, SIGNAL( toolAdded( Tool* )), this, SLOT( addTool( Tool* )));void VisualizationFrame::addTool( Tool* tool )
{QAction* action = new QAction( tool->getName(), toolbar_actions_ );toolbar_->insertAction( add_tool_action_, action );tool_to_action_map_[ tool ] = action;
}toolbar_actions_ = new QActionGroup( this );
connect( toolbar_actions_, SIGNAL( triggered( QAction* )), this, SLOT( onToolbarActionTriggered( QAction* )));void VisualizationFrame::onToolbarActionTriggered( QAction* action )
{Tool* tool = action_to_tool_map_[ action ];manager_->getToolManager()->setCurrentTool( tool );
}

在ToolManager.cpp内

setCurrentTool( Tool* tool ):设置当前工具后,发出toolChanged信号通知VisualizationManager;

void ToolManager::setCurrentTool( Tool* tool )
{ ...Q_EMIT toolChanged( current_tool_ );
}

在visualization_manager.cpp内:

connect( tool_manager_, SIGNAL( toolChanged( Tool* ) ), this, SLOT( onToolChanged( Tool* ) ));
void VisualizationManager::onToolChanged( Tool* tool ) {} /* 然鹅未启用 */

1.2 鼠标事件的传递和处理

我们知道,rviz::Tool类中有一个processMouseEvent( ViewportMouseEvent& event ),用于处理工具的鼠标事件,这是Tool类的核心功能,让我们来看一下它是怎么被调用的。

在render_panel.cpp中:

fake_mouse_move_event_timer_:定时器,定时触发sendMouseMoveEvent();

sendMouseMoveEvent():创建虚拟的鼠标事件fake_event并作为参数调用onRenderWindowMouseEvents( &fake_event ),这也就是按照一定周期(33ms)发送鼠标事件;

onRenderWindowMouseEvents( QMouseEvent* event ):获取鼠标的当前位置,创建ViewportMouseEvent,传递给上下文(就是VisualizationManager)的handleMouseEvent( QMouseEvent* event )进行处理;

connect( fake_mouse_move_event_timer_, SIGNAL( timeout() ), this, SLOT( sendMouseMoveEvent() ));
fake_mouse_move_event_timer_->start( 33 /*milliseconds*/ );void RenderPanel::sendMouseMoveEvent()
{...QMouseEvent fake_event( QEvent::MouseMove,mouse_rel_widget,QApplication::mouseButtons(),QApplication::keyboardModifiers() );onRenderWindowMouseEvents( &fake_event );
}void RenderPanel::onRenderWindowMouseEvents( QMouseEvent* event )
{int last_x = mouse_x_;int last_y = mouse_y_;if (context_){setFocus( Qt::MouseFocusReason );ViewportMouseEvent vme(this, getViewport(), event, last_x, last_y);context_->handleMouseEvent(vme);event->accept();}...}

在visualization_manager.cpp中:

handleMouseEvent( vme )从ToolManager获取当前工具,调用current_tool->processMouseEvent( _vme );(终于找到你了!)

void VisualizationManager::handleMouseEvent( const ViewportMouseEvent& vme )
{//process pending mouse eventsTool* current_tool = tool_manager_->getCurrentTool();if( current_tool ){ViewportMouseEvent _vme = vme;flags = current_tool->processMouseEvent( _vme );vme.panel->setCursor( current_tool->getCursor() );}...
}

1.3 实现工具类的无注册调用

上面我们了解了已注册的工具类如何加载和调用,那么能不能在程序中引入插件类的头文件,实现我们自己实例化的插件类的添加和调用呢,当然是可以的,而且基于librviz优秀的代码设计,这实现起来很容易。

在tool.h中:

虚函数,提供给子类重新实现,实现多样的鼠标事件处理。

virtual int processMouseEvent( ViewportMouseEvent& event ) { return 0; }

举个例子,在move_tool.cpp中:

int MoveTool::processKeyEvent( QKeyEvent* event, RenderPanel* panel )
{if( context_->getViewManager()->getCurrent() ){context_->getViewManager()->getCurrent()->handleKeyEvent( event, panel );}return Render;
}

自己创建不被注册的工具类,想要其被启用,并且处理鼠标事件,关键在于这两点:

  • Tool::initialize( VisualizationManager ); // 实例化你的工具类,调用initialize函数,把render_panel的VisualizationManager传进去。
  • ToolManager::setCurrentTool( Tool ); // 设置为ToolManager的当前工具后,VisualizationManager便可以传递鼠标事件给工具了,让它进行处理了!

举个例子:

void initialize()
{// 创建3D面板、中央管理器和tool管理器render_panel_ = new rviz::RenderPanel();visualization_manager_ = new rviz::VisualizationManager(render_panel_);tool_manager_ = visualization_manager_->getToolManager();render_panel_->initialize(visualization_manager_->getSceneManager(), visualization_manager_);visualization_manager_->initialize();visualization_manager_->startUpdate();// 初始化工具 route_goal_tool_ = new rviz_plugins::RouteGoalTool();route_goal_tool_->initialize(visualization_manager_);
}// 启动工具
void startTool()
{tool_manager_->setCurrentTool(route_goal_tool_);
}

当然,这样虽然可以实现,但也有很明显的缺点,ToolManager::addTool()中除了创建工具,还会维护tools_和shortkey_to_tool_map_列表,一些操作如删除工具、属性更改等都是依赖tools_列表实现,快捷键映射则依赖于shortkey_to_tool_map_列表。而没有注册的插件需要自己管理,容易造成混乱。

Tool* ToolManager::addTool( const QString& class_id )
{Tool* tool = factory_->make( class_id, &error );tools_.append( tool );tool->setName( addSpaceToCamelCase( factory_->getClassName( class_id )));tool->setIcon( factory_->getIcon( class_id ) );tool->initialize( context_ );if( tool->getShortcutKey() != '\0' ){uint key;QString str = QString( tool->getShortcutKey() );if( toKey( str, key ) ){shortkey_to_tool_map_[ key ] = tool;}}Property* container = tool->getPropertyContainer();connect( container, SIGNAL( childListChanged( Property* )), this, SLOT( updatePropertyVisibility( Property* )));updatePropertyVisibility( container );Q_EMIT configChanged();return tool;
}

总结

第一次比较深入地去看源码,希望有一天也能写出这样的好代码~

更多推荐

【librviz源码解读】Tool类的添加和鼠标事件处理

本文发布于:2024-03-08 11:08:52,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1720705.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:鼠标   源码   事件   librviz   Tool

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!