明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 352|回复: 8

ObjectARX 两文档视图同步

[复制链接]
发表于 4 天前 | 显示全部楼层 |阅读模式
本帖最后由 gzxl 于 2025-10-27 22:30 编辑




源码就是下面所贴的,应该齐全

补上 FileNavDlgCmd 类


鼠标钩子
  1. #if _MSC_VER <= 1900
  2. BOOL filterMouse(MSG *pMsg)
  3. #else
  4. bool filterMouse(MSG *pMsg)
  5. #endif
  6. {
  7.     if (pMsg->message == WM_MBUTTONDOWN ||  // 按下鼠标中键
  8.         pMsg->message == WM_MOUSEWHEEL)     // 鼠标滚轮
  9.     {
  10.         // 当前活动文档
  11.         AcApDocument* pDoc = acDocManager->mdiActiveDocument();
  12.         const ACHAR* fileName = pDoc->fileName();
  13.         CString strActiveFileName = fileName;
  14.         // a="c:\\kele8\\shootman2\\vision\\123.exe" => "123"
  15.         strActiveFileName = GetFileTitleFromFileName(strActiveFileName, FALSE);
  16.         // 当前视图中心点、左下角、右上角坐标
  17.         AcGePoint3d ptLB;
  18.         AcGePoint3d ptRT;
  19.         AcGePoint3d ptCenter;
  20.         CViewUtil::GetViewWindow(ptLB, ptRT);
  21.         ptCenter.x = (ptLB.x + ptRT.x) * 0.5;
  22.         ptCenter.y = (ptLB.y + ptRT.y) * 0.5;
  23.         // 赋值
  24.         DocVars.docData().g_ptCenter = ptCenter;
  25.         DocVars.docData().g_ptLeftBottom = ptLB;
  26.         DocVars.docData().g_ptRightTop = ptRT;
  27.         DocVars.docData().g_strActiveFileName = strActiveFileName;
  28.         DocVars.docData().g_bZoomView = true;
  29.     }
  30.     else if (pMsg->message == WM_MBUTTONUP) // 释放鼠标中键
  31.     {
  32.         StartSynView(); // 开始同步两个文档
  33.         DocVars.docData().g_bZoomView = false;
  34.     }

  35. #if _MSC_VER <= 1900
  36.     return FALSE;
  37. #else
  38.     return false;
  39. #endif
  40. }


两文档视图中心点、左下角、右上角坐标同步
  1. void StartSynView()
  2. {
  3.     // 鼠标中键、滚轮
  4.     if (!DocVars.docData().g_bZoomView)
  5.         return;

  6.     // 视图左下角、右上角坐标(用户坐标系)
  7.     AcGePoint3d ptLB;
  8.     AcGePoint3d ptRT;
  9.     if (!CViewUtil::GetViewWindow(ptLB, ptRT))
  10.         return;

  11.     // 视图中心点
  12.     AcGePoint3d ptCenter;
  13.     ptCenter.x = (ptLB.x + ptRT.x) * 0.5;
  14.     ptCenter.y = (ptLB.y + ptRT.y) * 0.5;
  15.     ptCenter.z = 0.0;
  16.     if (CViewUtil::IsEqual(ptCenter, DocVars.docData().g_ptCenter))
  17.         return;

  18.     // 当前活动文档名称
  19.     CString strActiveFileName = DocVars.docData().g_strActiveFileName;

  20.     // 遍历文档
  21.     AcApDocumentIterator *pIter = NULL;
  22.     pIter = acDocManager->newAcApDocumentIterator();
  23.     for (; !pIter->done(); pIter->step())
  24.     {
  25.         AcApDocument *pDoc = pIter->document();
  26.         const ACHAR* fileName = pDoc->fileName();
  27.         CString strFileName = fileName;
  28.         // a="c:\\kele8\\shootman2\\vision\\123.exe" => "123"
  29.         strFileName = GetFileTitleFromFileName(strFileName, FALSE);
  30.         if (_tcsicmp(strActiveFileName, strFileName) != 0)
  31.         {
  32.             acDocManager->activateDocument(pDoc);
  33.             DocVars.docData().g_ptCenter = ptCenter;
  34.             DocVars.docData().g_ptLeftBottom = ptLB;
  35.             DocVars.docData().g_ptRightTop = ptRT;
  36.             DocVars.docData().g_strActiveFileName = strFileName;
  37.             acDocManager->sendStringToExecute(pDoc, _T("MyZoom\n"), true, false, false);
  38.         }
  39.     }
  40.     delete pIter;
  41.     pIter = NULL;
  42. }


字符串处理
  1. /*
  2. a="c:\\kele8\\shootman2\\vision\\123.exe";
  3. b=this->GetFileTitleFromFileName(a,TRUE);
  4. c=this->GetFileTitleFromFileName(a,FALSE);
  5. AfxMessageBox(b); = 123.exe
  6. AfxMessageBox(c); = 123
  7. */
  8. CString GetFileTitleFromFileName(CString FileName, BOOL Ext)
  9. {
  10.     int Where;
  11.     Where = FileName.ReverseFind('\\');
  12.     if (Where == -1)
  13.         Where = FileName.ReverseFind('/');
  14.     CString FileTitle = FileName.Right(FileName.GetLength() - 1 - Where);
  15.     if (!Ext)
  16.     {
  17.         int Which = FileTitle.ReverseFind('.');
  18.         if (Which != -1)
  19.             FileTitle = FileTitle.Left(Which);
  20.     }
  21.     return FileTitle;
  22. }


修改视图
  1. static void MyGroupMyZoom()
  2. {
  3.     AcGePoint3d ptCenter = DocVars.docData().g_ptCenter;
  4.     AcGePoint3d ptLB = DocVars.docData().g_ptLeftBottom;
  5.     AcGePoint3d ptRT = DocVars.docData().g_ptRightTop;
  6.     CViewUtil::SetCenter(ptCenter);
  7.     CViewUtil::Set(ptLB, ptRT);
  8. }
复制代码
  1. AcGePoint2d CViewUtil::ToPoint2d(const AcGePoint3d &point3d)
  2. {
  3.     return AcGePoint2d(point3d.x, point3d.y);
  4. }

  5. AcGePoint3d CViewUtil::WcsToDcsPoint(const AcGePoint3d &point)
  6. {
  7.     // 转换成世界坐标
  8.     AcGePoint3d pt;
  9.     struct resbuf rbFrom, rbTo;
  10.     rbFrom.restype = RTSHORT;
  11.     rbFrom.resval.rint = 0; // from WCS
  12.     rbTo.restype = RTSHORT;
  13.     rbTo.resval.rint = 2; // to DCS
  14.     acedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));
  15.     return pt;
  16. }

  17. // 获得当前的视图设置
  18. void CViewUtil::GetCurrentView(AcDbViewTableRecord &view)
  19. {
  20.     struct resbuf rb;
  21.     struct resbuf wcs, ucs, dcs; // 转换坐标时使用的坐标系统标记
  22.     wcs.restype = RTSHORT;
  23.     wcs.resval.rint = 0;
  24.     ucs.restype = RTSHORT;
  25.     ucs.resval.rint = 1;
  26.     dcs.restype = RTSHORT;
  27.     dcs.resval.rint = 2;
  28.     // 获得当前视口的"查看"模式
  29.     acedGetVar(_T("VIEWMODE"), &rb);
  30.     view.setPerspectiveEnabled((rb.resval.rint & 1) != 0);
  31.     view.setFrontClipEnabled((rb.resval.rint & 2) != 0);
  32.     view.setBackClipEnabled((rb.resval.rint & 4) != 0);
  33.     view.setFrontClipAtEye((rb.resval.rint & 16) == 0);
  34.     // 当前视口中视图的中心点(UCS坐标)
  35.     acedGetVar(_T("VIEWCTR"), &rb);
  36.     acedTrans(rb.resval.rpoint, &ucs, &dcs, 0, rb.resval.rpoint);
  37.     view.setCenterPoint(AcGePoint2d(rb.resval.rpoint[X], rb.resval.rpoint[Y]));
  38.     // 当前视口透视图中的镜头焦距长度(单位为毫米)
  39.     acedGetVar(_T("LENSLENGTH"), &rb);
  40.     view.setLensLength(rb.resval.rreal);
  41.     // 当前视口中目标点的位置(以 UCS 坐标表示)
  42.     acedGetVar(_T("TARGET"), &rb);
  43.     acedTrans(rb.resval.rpoint, &ucs, &wcs, 0, rb.resval.rpoint);
  44.     view.setTarget(AcGePoint3d(rb.resval.rpoint[X], rb.resval.rpoint[Y], rb.resval.rpoint[Z]));
  45.     // 当前视口的观察方向(UCS)
  46.     acedGetVar(_T("VIEWDIR"), &rb);
  47.     acedTrans(rb.resval.rpoint, &ucs, &wcs, 1, rb.resval.rpoint);
  48.     view.setViewDirection(AcGeVector3d(rb.resval.rpoint[X], rb.resval.rpoint[Y], rb.resval.rpoint[Z]));
  49.     // 当前视口的视图高度(图形单位)
  50.     acedGetVar(_T("VIEWSIZE"), &rb);
  51.     view.setHeight(rb.resval.rreal);
  52.     double height = rb.resval.rreal;
  53.     // 以像素为单位的当前视口的大小(X 和 Y 值)
  54.     acedGetVar(_T("SCREENSIZE"), &rb);
  55.     view.setWidth(rb.resval.rpoint[X] / rb.resval.rpoint[Y] * height);
  56.     // 当前视口的视图扭转角
  57.     acedGetVar(_T("VIEWTWIST"), &rb);
  58.     view.setViewTwist(rb.resval.rreal);
  59.     // 将模型选项卡或最后一个布局选项卡置为当前
  60.     acedGetVar(_T("TILEMODE"), &rb);
  61.     int tileMode = rb.resval.rint;
  62.     // 设置当前视口的标识码
  63.     acedGetVar(_T("CVPORT"), &rb);
  64.     int cvport = rb.resval.rint;
  65.     // 是否是模型空间的视图
  66.     bool paperspace = ((tileMode == 0) && (cvport == 1)) ? true : false;
  67.     view.setIsPaperspaceView(paperspace);
  68.     if (!paperspace)
  69.     {
  70.         // 当前视口中前向剪裁平面到目标平面的偏移量
  71.         acedGetVar(_T("FRONTZ"), &rb);
  72.         view.setFrontClipDistance(rb.resval.rreal);
  73.         // 获得当前视口后向剪裁平面到目标平面的偏移值
  74.         acedGetVar(_T("BACKZ"), &rb);
  75.         view.setBackClipDistance(rb.resval.rreal);
  76.     }
  77.     else
  78.     {
  79.         view.setFrontClipDistance(0.0);
  80.         view.setBackClipDistance(0.0);
  81.     }
  82. }

  83. // 给定显示范围的最大、最小角点坐标和缩放比例,修改视图
  84. void CViewUtil::Set(const AcGePoint3d &ptMin, const AcGePoint3d &ptMax, double scale)
  85. {
  86.     AcDbViewTableRecord view;
  87.     GetCurrentView(view);
  88.     // 将参数的两个点从世界坐标系转换到显示坐标系
  89.     AcGePoint3d ptMinDcs = WcsToDcsPoint(ptMin);
  90.     AcGePoint3d ptMaxDcs = WcsToDcsPoint(ptMax);
  91.     // 设置视图的中心点
  92.     view.setCenterPoint(AcGePoint2d((ptMinDcs.x + ptMaxDcs.x) / 2, (ptMinDcs.y + ptMaxDcs.y) / 2));
  93.     // 设置视图的高度和宽度
  94.     view.setHeight(fabs(ptMinDcs.y - ptMaxDcs.y) * scale);
  95.     view.setWidth(fabs(ptMinDcs.x - ptMaxDcs.x) * scale);
  96.     // 将视图对象设置为当前视图
  97.     acedSetCurrentView(&view, NULL);
  98. }

  99. // 将视图移动到给定的中心点
  100. void CViewUtil::SetCenter(const AcGePoint3d &#162;er)
  101. {
  102.     AcDbViewTableRecord view;
  103.     GetCurrentView(view);
  104.     // 将参数的点从世界坐标系转换到显示坐标系
  105.     AcGePoint3d centerDcs = WcsToDcsPoint(center);
  106.     // 设置视图的中心点
  107.     view.setCenterPoint(ToPoint2d(centerDcs));
  108.     // 将视图对象设置为当前视图
  109.     acedSetCurrentView(&view, NULL);
  110. }

  111. // 获取系统变量
  112. // strName ----------- 设置对象
  113. // ptPoint ----------- 返回值
  114. BOOL CViewUtil::GetSysVar(CString strName, AcGePoint3d &ptPoint)
  115. {
  116.     BOOL bRet = FALSE;
  117.     struct resbuf rb;

  118.     ptPoint.set(0.0, 0.0, 0.0);
  119.     if (acedGetVar(strName, &rb) == RTNORM)
  120.     {
  121.         ASSERT(rb.restype == RT3DPOINT);
  122.         ptPoint.set(rb.resval.rpoint[X],
  123.             rb.resval.rpoint[Y],
  124.             rb.resval.rpoint[Z]);
  125.         bRet = TRUE;
  126.     }
  127.     return bRet;
  128. }

  129. // 获取系统变量
  130. // strName ----------- 设置对象
  131. // dVal -------------- 返回值
  132. BOOL CViewUtil::GetSysVar(CString strName, double &dVal)
  133. {
  134.     BOOL bRet = FALSE;
  135.     struct resbuf rb;

  136.     dVal = 0.0;
  137.     if (acedGetVar(strName, &rb) == RTNORM)
  138.     {
  139.         ASSERT(rb.restype == RTREAL);
  140.         dVal = rb.resval.rreal;
  141.         bRet = TRUE;
  142.     }
  143.     return bRet;
  144. }

  145. // 得到视图窗口大小(用户坐标系)  
  146. // ptPointLB  当前视图左下角坐标
  147. // ptPointRT  当前视图右上角坐标
  148. BOOL CViewUtil::GetViewWindow(AcGePoint3d &ptPointLB, AcGePoint3d &ptPointRT)
  149. {
  150.     double dViewWidth = 0.0;            // 视图宽度
  151.     double dViewHeight = 0.0;           // 视图高度
  152.     AcGePoint3d ptCenter;               // 视图中心点
  153.     AcGePoint3d ptPoint;

  154.     // 得到参数
  155.     if (!GetSysVar("VIEWCTR", ptCenter))  //(用户坐标系)  
  156.     {
  157.         return FALSE;
  158.     }
  159.     if (!GetSysVar("VIEWSIZE", dViewHeight))
  160.     {
  161.         return FALSE;
  162.     }
  163.     if (!GetSysVar("SCREENSIZE", ptPoint))
  164.     {
  165.         return FALSE;
  166.     }
  167.     dViewWidth = (ptPoint.x / ptPoint.y)*dViewHeight;

  168.     // 计算视图窗口大小  
  169.     ptPointLB.x = ptCenter.x - dViewWidth / 2;
  170.     ptPointLB.y = ptCenter.y - dViewHeight / 2;
  171.     ptPointLB.z = 0.0;
  172.     ptPointRT.x = ptCenter.x + dViewWidth / 2;
  173.     ptPointRT.y = ptCenter.y + dViewHeight / 2;
  174.     ptPointRT.z = 0.0;

  175.     return TRUE;
  176. }
复制代码


测试
  1. vector<CString> fileNames;
  2. if (CFileNavDlgCmd::FileNavCmd(fileNames))
  3. {
  4.     // 关闭开始页
  5.     int nStartmode = 0;
  6.     resbuf rb;
  7.     int nRes = acedGetVar(_T("STARTMODE"), &rb);
  8.     if (nRes != RTNORM)
  9.         return;
  10.     if (rb.restype == RTSHORT)
  11.         nStartmode = rb.resval.rint;
  12.     rb.rbnext = NULL;
  13.     rb.restype = RTSHORT;
  14.     rb.resval.rint = 0;
  15.     nRes = acedSetVar(_T("STARTMODE"), &rb);

  16.     // 打开 Dwg 文件, 命令标志为 ACRX_CMD_SESSION
  17.     for (size_t i = 0; i < fileNames.size(); i++)
  18.     {
  19.         CString strFile = fileNames;
  20.         if (acDocManager->isApplicationContext())
  21.         {
  22.             acDocManager->appContextOpenDocument((const TCHAR *)strFile);
  23.         }
  24.     }
  25.     // 遍历文档,关闭其他的Dwg文件(比如默认的 Drawing1)
  26.     AcApDocumentIterator *pIter1 = acDocManager->newAcApDocumentIterator();
  27.     for (; !pIter1->done(); pIter1->step())
  28.     {
  29.         AcApDocument *pDoc = pIter1->document();
  30.         acDocManager->activateDocument(pDoc);
  31.         acDocManager->setCurDocument(pDoc, AcAp::kWrite);
  32.         const ACHAR* fileName = pDoc->fileName();
  33.         CString strFileName = fileName;
  34.         CString str1 = GetFileTitleFromFileName(strFileName, FALSE);
  35.         bool bEqual = false;
  36.         for (size_t i = 0; i < fileNames.size(); i++)
  37.         {
  38.             CString str2 = GetFileTitleFromFileName(fileNames, FALSE);
  39.             if (_tcsicmp(str2, str1) == 0)
  40.             {
  41.                 bEqual = true;
  42.                 break;
  43.             }
  44.         }
  45.         if (!bEqual)
  46.         {
  47.             acDocManager->closeDocument(pDoc);
  48.         }
  49.     }
  50.     delete pIter1;

  51.     // 遍历文档,发送 SYSWINDOWS V 命令(垂直平铺两个文档)
  52.     AcApDocumentIterator *pIter2 = acDocManager->newAcApDocumentIterator();
  53.     for (; !pIter2->done(); pIter2->step())
  54.     {
  55.         AcApDocument *pDoc = pIter2->document();
  56.         acDocManager->activateDocument(pDoc);
  57.         acDocManager->setCurDocument(pDoc, AcAp::kWrite);
  58.         CString cmd = _T("SYSWINDOWS V ");
  59.         acDocManager->sendStringToExecute(curDoc(), cmd, true, false, false);
  60.         break;
  61.     }
  62.     delete pIter2;

  63.     // 注册鼠标消息钩子
  64.     acedRegisterFilterWinMsg(filterMouse);

  65.     // 还原开始页
  66.     rb.rbnext = NULL;
  67.     rb.restype = RTSHORT;
  68.     rb.resval.rint = nStartmode;
  69.     nRes = acedSetVar(_T("STARTMODE"), &rb);
  70. }


卸载钩子
  1.         // 移除鼠标消息钩子
  2.         acedRemoveFilterWinMsg(filterMouse);
复制代码







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1明经币 +1 收起 理由
橡皮 + 1 赞一个!

查看全部评分

回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
太神奇了 学习了
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
楼主能不能给最终的文件,让我们尝尝鲜。
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
太神奇了 膜拜
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
神奇文件同步,方便!
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
我在2019下测试,焦点没有切换回来,貌似仅支持鼠标平移,鼠标缩放未生效,键盘缩放未生效。
印象中高飞鸟版主曾经写过一个类似同步的,
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 天前 | 显示全部楼层
edata 发表于 2025-10-27 22:22
我在2019下测试,焦点没有切换回来,貌似仅支持鼠标平移,鼠标缩放未生效,键盘缩放未生效。
印象中高飞鸟 ...

钩子里面没有写键盘事件的
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 天前 | 显示全部楼层
一楼补上 FileNavDlgCmd 对话框类
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
acDocManager->sendStringToExecute(pDoc, _T("MyZoom\n"), true, false, false); 这里的"MyZoom" 是不是要改为“ MyGroupMyZoom”
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-10-31 04:20 , Processed in 0.206423 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表