美文网首页
AutoCAD中实现双击文本编辑功能

AutoCAD中实现双击文本编辑功能

作者: yumxuanyi | 来源:发表于2019-04-23 14:29 被阅读0次

@版权声明:本文为版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接https://www.jianshu.com/p/e0b52c23b19e
如有问题, 可邮件(yumxuanyi@qq.com)咨询。


关键字:Auto CAD、双击编辑

在AutoCAD中有一个很重要的功能,就是双击图形尺寸或文本后会出现一个文本编辑框,用户可在该编辑框中修改文字。本文介绍了如何使用AcEdInplaceTextEditor来实现该功能。

1. 实现cad的消息监听。

创建一个消息监听的类并在cad中注册来实现消息监听。主要是监听键盘输入。

  class CForCycloneDimText
  {
      public:
         CForCycloneDimText(void);
        ~CForCycloneDimText(void);
     private:
       bool mIsAddOneHook;//记录是否添加到了Hook
    public:
       bool HasAddListener() const;//获取是否添加了监听
       void AddListener(); //添加到消息监听
       void RemoveListener(); //移除消息监听

      //获取监听消息 并处理消息
      static BOOL MainListenerMessage(MSG *pMsg); 
  }

下面是该类的实现

   //几个全局变量 在APP中定义
   extern CForCycloneDimText*  g_CycloneDimTextHook;
   extern double g_PropertyValue; //编辑框中返回的值
  extern CTextPointMessage*  g_TextPointMessage;//记录了当前双击文字的信息。

  CForCycloneDimText::CForCycloneDimText(void)
 {
      this->mIsAddOneHook = false;
 }

 CForCycloneDimText::HasAddListener(void)
 {
     return this->mIsAddOneHook ;
 }

 //在CAD的消息注册表中注册该消息监听
 CForCycloneDimText::AddListener(void)
 {
    if(this->mIsAddOneHook)//已经注册了事件监听直接返回
   {
        return;    
   }
   if(acedRegisterFilterWinMsg(CForCycloneDimText::MainListenerMessage) ==TRUE)//添加监听
   {
           this->mIsAddOneHook = true;
   }
   else 
   {
        acedPrompt(_T("未能注册消息监听\n"));
   }
 }

 //移除消息监听函数
 CForCycloneDimText::RemoveListener(void)
{
      if(this->mIsAddOneHook)
      {
            this->mIsAddOneHook = false;
            acedRemoveFilterWinMsg(CForCycloneDimText::MainListenerMessage);//移除消息监听
      }
}


//下面是消息的处理 
//由于是尺寸数据只允许用户输入数字 获取值只允许为double类型
BOOL CForCycloneDimText::MainListenerMessage(MSG * pMsg)
{
    BOOL flag = FALSE;
   UINT tagMessage = pMsg->message;
   switch(pMsg->message)
   {
       case WN_CHAR://表示用户输入了键盘的某一个字符
       {
             if(pMsg->wParam == 13)//用户按下了回车键将结束监听保存更改
             {
                   g_CycloneDimTextHook->RemoveListener();
                   //获取文本编辑框中的内容
                   AcEdInPlaceTextEditor *pEditor = AcEdInPlaceTextEditor::current();
                   pEditor->selectAll();
                   AcDbTextEditorSelection *pSelection = pEditor->selection();
                   if(pSelection)
                   {
                        AcString strValue;
                        pSelection->getSelectionText(strValue);
                        pEditor->removeHightlight();
                        if(strValue.isEmpty())
                        { 
                              pEditor->setCanExitInplaceEditor(true);
                              pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                              flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                              return flag;
                         }
                        try
                        {
                               g_PropertyValue = atof(strValue);//获取新的值
                               pEditor->setCanExitInplaceEditor(true);
                               pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                               flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                        }
                        catch(...)
                        { 
                               pEditor->setCanExitInplaceEditor(true);
                               pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                               flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                        }                     
                   }
                   else
                   {
                              pEditor->setCanExitInplaceEditor(true);
                              pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                              flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                    }
             }  
            else if(pMsg->wParam ==27) //表示用户按下了ESC
            {
                   //用户按下了ESC 退出文本编辑器放弃修改
                   g_CycloneDimTextHook->RemoveListener();
                   AcEdInPlaceTextEditor *pEditor = AcEdInPlaceTextEditor::current();
                   pEditor->setCanExitInplaceEditor(true);
                   pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                   flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
           } 
          else
          {
                  if(pMsg->wParam ==46) //小数点只允许存在一个
                 {
                     AcEdInPlaceTextEditor *pEditor = AcEdInPlaceTextEditor::current();
                     AcDbTextEditorLocation *pStart = pEditor->startOfText();
                     AcDbTextEditorLocation *pEnd = pEditor->endOfText();
                     Acad::ErrorStatus es = pEditor->findText(TEXT("."),AcDbTextEditor::kFindMatchCase,pStart,pEnd);
                    if(pStart  != NULL) //表示找到了
                   {
                       flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                    }
             } 
            else if(pMsg->wParam < 48 || pMsg->wParam > 57) //只允许按下0-9
           {
                     flag = TRUE;//返回True表示消息终止 不再传递给CAD处理    
            }
          }          
      }break;
      case WM_LBUTTONDOWN://表示用户按下了鼠标左键
      {
          //鼠标左键单击时需要判断 单击位置于包围框的关系。
          //如果在包围框外部 单击 表示提交数据 保存更改
          //如果在包围框内部单击 表示定位到编辑框中的该位置

          //获取需要编辑的文字位置
          AcGePoint3d location = g_pTextPointMessage->get_Location();//g_pTextPointMessage为一个全局变量用于记录可编辑文字的信息

          AcEdInPlaceTextEditor *pEditor = AcEdInPlaceTextEditor::current();
          double textHeight = g_pTextPointMessage->get_Text()->height();//获取双击编辑尺寸的文字高度
          double editorHeight = pEditor->actualHeight();//获取编辑框的高度
          double editorWidth = pEditor->acturalWidth();//获取编辑框的宽度
          
          AcGeVector3d ydir(0,1,0);
          AcGePoint3d editorLocation = location;
          editorLocation.transformBy(AcGeMatrix3d::translation(ydir*textHeight/2));//这里假定双击文字水平放置,对于倾斜的文字需要设置双击时水平替代文字 这样 文字位置往上偏移文字高度就是包围框上部中心
          
          AcGeVector3d minVec(-editorWdith/2,-editorHeight,0);
          AcGeVector3d maxVec(editorWdith/2,0,0);
          
          AcGePoint3d minPoint = editorLocation + minVec;//包围框左下脚点
          AcGePoint3d maxPoint = editorLocation + maxVec;//包围框右上脚点
         
           //下面获取双击时鼠标屏幕位置对应视图中的位置 
          CView *pView = acedGetAcadDwgView();
          CPoint mousePoint;
          GetCursorPos(&mousePoint);
          ScreenToClient(acedGetAcadDwgView()->m_hWnd,&mousePoint);
          acedDwgPoint ptOut;

       int nVpNum = acedGetWinNum(pMsg->pt.x,pMsg->pt.y);//获取视口编号
       acedCoordFromPixelToWorld(nVpNum,mousePoint,ptOut);// 如何根据像素点找到视口中的位置 这个很关键

       AcGePoint3d cursPoint(ptOut[0],ptOut[1],0);

      //判断ptOut是否在包围框之内
      AcDbExtents extend(minPoint,maxPoint);
      Point3dPositionForHookArea pointMessage = GetPointPositonForArae(extend,cursPoint);//这个是自己写的方法用户判断给定的点是否位于包围框之内,Point3dPositionForHookArea表示点于包围框的相对关系
      if(pointMessage == Point3dPositionForHookArea ::InSide ||pointMessage == Point3dPositionForHookArea ::OnEdge )
     {
          flag = FALSE;//表示落在包围框内或上面 则交给cad处理
     }
    else//鼠标子啊编辑框外部 表示提交修改后的数据
    {
           g_CycloneDimTextHook->RemoveListener();
           AcEdInPlaceTextEditor *pEditor = AcEdInPlaceTextEditor::current();
           pEditor->setCanExitInplaceEditor(true);
           pEditor->selectAll();
          
          AcDbTextEditorSelection *pSelection = pEditor->selection();
          if(pSelection)
          {
              AcString strValue;
              pSelection->getSelectionText(strValue);
              pEditor->removeHightlight();
              if(strValue.isEmpty())
              { 
                   pEditor->setCanExitInplaceEditor(true);
                   pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                   flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                   return flag;
                }
                try
                {
                    g_PropertyValue = atof(strValue);//获取新的值
                    pEditor->setCanExitInplaceEditor(true);
                    pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                    flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                }
                catch(...)
                { 
                    pEditor->setCanExitInplaceEditor(true);
                    pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
                    flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
                }                    
       }
      else 
       { 
             pEditor->setCanExitInplaceEditor(true);
             pEditor->close(AcDbTextEditor::ExitStatus::kExitQuit);
              flag = TRUE;//返回True表示消息终止 不再传递给CAD处理
       }              
     }
   }break;
}
return flag;
}

响应双击事件

下面就是在自定义实体实现响应双击事件。
步骤1. 通过继承AcDbDoubleClickEdit来创建自己的DoubleClickeEditer对象。
步骤2 .实现startEdit(AcDbEntity*pEnt,AcGePoint3d pt)方法。
在该方法中根据pt来判断是哪个文字被双击, 获取可编辑文字,激活TextEditor。
返回该文字的信息到全局变量 g_pTextPointMessage。
记录对象objectID
通过命令方式来动态添加文本编辑框

    void CMyDoubleClickEditer::startEdit(AcDbEntity*pEnt,AcGePoint3d pt)
{
    AcApDocument *pDoc = acDocManager->curDocument();
    acDocManager->lockDocument(pDoc,AcAp::kWrite);
     ...//这里进行处理,判断双击对象类型,获取双击的文字信息等
    acDocManager->unlockDocument(pDoc);
    acDocManager->sendStringToExecute(pDoc,TEXT("AddTextEditor"),false,false,false);
    acDocManager->setCurDocument(acDocManager->mdiActiveDocument());
}

实例化双击编辑监听对象

在App类外部中定义了全局变量
CForCycloneDimText * g_CycloneDimTextHook = NULL;

在On_kInitAppMsg中实例化

   g_CycloneDimTextHook  = new CForCycloneDimText();

在On_kUnloadAppMsg中释放资源

   delete  g_CycloneDimTextHook;
   g_CycloneDimTextHook = NULL;

实现AddTextEditor命令

主要是在双击文字后,调用AcEdInplaceTextEditor的Invoke方法,该方法将获取文本编辑器对象

  static void CMDAddTextEditor(void)
  {
      if(g_pTextPointMessage)
      {
            if( g_CycloneDimTextHook != NULL)
           {
                AcDbText* pText = const_cast<AcDbText*>(g_pTextPointMessage->get_Text());
                g_CycloneDimTextHook->AddListener();

                g_CycloneDimTextHook->invoke(pText,NULL);

               //invoke会一直等待 直到编辑框编辑提交后返回到下面
               //因此下面就是对对象属性进行修改了
               ...//这里省略该部分代码 就是获取对象 修改属性而已
               ...//关于如何获取对象就是上面提到的 在双击事件中记录的对象的id已经保存到 全局变量中了,这里通过id获取对象即可
            }
      }
  }

相关文章

网友评论

      本文标题:AutoCAD中实现双击文本编辑功能

      本文链接:https://www.haomeiwen.com/subject/peyvgqtx.html