libreCAD源码阅读笔记4

libreCAD源码阅读笔记4

前言

总的来说,程序主窗口QC_ApplicationWindow使用QMdiArea作为多文档主界面,每个文档QC_MDIWindow使用RS_Document作为数据存储模型,QG_Graphicview作为每个文档窗口部件;QC_ApplicationWindow主窗口构造函数中使用工具类LC_ActionFactory生成各种程序Action,这些Action触发后都将调用QG_ActionHandler中的函数作为Action信号的槽函数。QG_ActionHandler槽函数根据信号源确定是什么Action操作类型,调用其成员函数setCurrentAction()产生具体Action对象,并调用其关联的QG_GraphicView也调用其自身setCurrentAction()将Action对象传递给RS_EventHandler。此后,当用户窗口绘图后,回调用当前的Action对象进行相关操作。
在这里插入图片描述

比如画线

  • 1 当主窗口点击画线按钮,触发画线的Action,根据下面代码,程序将会调用QG_ActionHandler的slotDrawLine()函数。
LC_ActionFactory.cpp : 120行
action = new QAction(tr("&2 Points"), agm->line);
action->setIcon(QIcon(":/icons/line_2p.svg"));
connect(action, SIGNAL(triggered()),
action_handler, SLOT(slotDrawLine()));
action->setObjectName("DrawLine");
a_map["DrawLine"] = action;
QG_ActionHandler.cpp : 1329void QG_ActionHandler::slotDrawLine() {
    setCurrentAction(RS2::ActionDrawLine);
}

RS_ActionInterface* QG_ActionHandler::setCurrentAction(RS2::ActionType id) {
......
switch (id) {
......
case RS2::ActionDrawLine:
        a = new RS_ActionDrawLine(*document, *view);
        break;
......
if (a) {
        view->setCurrentAction(a);
}
  • 2 QG_ActionHandler生成具体Action后,将其传递给QG_GraphicView,作为当前需要执行的动作。
QG_GraphicView.cpp : 1054void QG_GraphicView::setCurrentQAction(QAction* q_action)
{
    eventHandler->setQAction(q_action);

    if (recent_actions.contains(q_action))
    {
        recent_actions.removeOne(q_action);
    }
    recent_actions.prepend(q_action);
}
  • 3 QG_GraphicView将此Action传递给RS_EventHandler。RS_EventHandler作为事件监听,当用户按下鼠标键或者鼠标移动时候,会触发器相应的函数。
QG_GraphicView.cpp : 288void QG_GraphicView::mouseReleaseEvent(QMouseEvent* event)
{
   ......
    switch (event->button())
    {
    case Qt::RightButton:
       ......
    default:
        eventHandler->mouseReleaseEvent(event);
        break;
    }
    RS_DEBUG->print("QG_GraphicView::mouseReleaseEvent: OK");
}
RS_EventHandler.cpp : 115void RS_EventHandler::mouseReleaseEvent(QMouseEvent* e) {
    if(hasAction()){
        //    if (actionIndex>=0 && currentActions[actionIndex] &&
        //            !currentActions[actionIndex]->isFinished()) {
        RS_DEBUG->print("call action %s",
                        currentActions.last()->getName().toLatin1().data());
        currentActions.last()->mouseReleaseEvent(e); /// 注意:调用具体Action的mouseReleaseEvent函数
        // Clean up actions - one might be finished now
        cleanUp();
        e->accept();
    } else {
        if (defaultAction) {
            defaultAction->mouseReleaseEvent(e);
        } else {
            e->ignore();
        }
    }
}
  • 4 最后将事件传递给具体实体对象,实体对象完成自身绘制。
RS_ActionDrawLine.cpp : 164void RS_ActionDrawLine::mouseReleaseEvent(QMouseEvent* e)
{
    if (e->button() == Qt::LeftButton) {
        RS_Vector snapped = snapPoint(e);

        // Snapping to angle(15*) if shift key is pressed
        if ((e->modifiers() & Qt::ShiftModifier)
            && getStatus() == SetEndpoint ) {
            snapped = snapToAngle(snapped, pPoints->data.startpoint, 15.);
        }

        RS_CoordinateEvent ce(snapped);
        coordinateEvent(&ce);
    }
    else if (e->button() == Qt::RightButton) {
        deletePreview();
        switch (getStatus()) {
        default:
        case SetStartpoint:
            init( getStatus() - 1);
            break;

        case SetEndpoint:
            next();
            break;
        }
    }
}

结束

学习记录下大体程序流程,其他还有很多细节内容需要进一步分析学习。比如libreCAD如何实现命令窗口绘制实体对象的?下次学习从RS_Commands类开始吧。

© 版权声明
THE END
喜欢就支持一下吧
点赞276 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容