@版权声明:本文为版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出,
本文链接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获取对象即可
}
}
}
网友评论