第7章 用户界面
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第7章 用户界面
† ObjectARX 程序中使用MFC 资源。
† AdUi 和AcUi 界面类。
†模式对话框与非模式对话框。
Microsoft 基础类库(MFC)为开发者提供了建立标准用户界面的方法,ObjectARX 也为开发者提供了一系列基于MFC 的用户界面类,可以利用这些类开发与Autodesk 用户界面完全一致的用户界面。
本章我们主要讨论如何使用AutoCAD 内部的MFC 系统来生成AutoCAD 风格的用户界面。
7.1 ObjectARX 应用程序中使用MFC
开发者可以利用MFC 提供的界面类快速方便的创建标准用户界面,另外ObjectARX 还提供了基于MFC 的界面类的扩展类,其中CAdUi 类是适用与所有Autodesk 应用程序的界面类,而CAcUi 类则派生于CAdUi 类,是专为AutoCAD 设计的界面类,它建立在AdUi 框架之上,提供AutoCAD 特定的外观和行为。
开发者可以使用ObjectARX 提供的这些界面类开发出与AutoCAD 内部相同的用户界面。
需要注意的是,开发者在使用向导创建工程的时候,需要设定工程支持MFC ObjectARX ,只有这样才能使用MFC 的用户界面类和ObjectARX 中提供的的AdUi 和AcUi 界面类,如图7-1。
7.1.1 资源管理
当ObjectARX 应用程序与AutoCAD 的其它应用程序共享MFC 库的时候,资源管理是一个重要任务,当应用程序执行资源定位时,必须事先在MFC 检查序列中插入自己的模块。
因此,我们需要管理程序中的资源,以免与AutoCAD 或者其它ObjectARX 应用程序之间发生冲突。
本章简介8
图7-1 设定ObjectARX应用程序支持MFC
ObjectARX中提供两种管理资源的方法:显式管理资源和隐式管理资源。
显式管理资源方法在执行自定义资源操作之前,需要调用函数AfxSetResourceHandle()设定自定义资源作为系统资源,在这之前还应该调用函数AfxGetResourceHandle()获得当前的系统资源,暂时保存,在执行完任何需要自定义资源的函数之后,应该立即恢复先前的系统资源。
隐式管理资源方法使用CAcModuleResourceOverride类的实例来实现资源提供者之间的自动切换。
当对象被创建时,新的资源提供者被使用,先前的资源提供者将暂时无效;当对象被析构时,先前的资源提供者将恢复有效,请参考如下代码:
void MyResourceFun()
{
CAcModuleResourceOverride myResource;
CDialogDemo dlg;
dlg.DoModal()
}
通过创建一个CAcModuleResourceOverride类的实例,其构造函数将自动把对话框CDialogDemo的资源设置为系统资源。
当函数MyResourceFun()执行完毕,CAcModuleResourceOverride的析构函数将自动把系统资源恢复为AutoCAD的资源。
如果不创建一个CAcModuleResourceOverride类的实例,将可能导致CDialogDemo的资源与AutoCAD的资源冲突,从而引起程序执行失败。
7.2 模式和非模式对话框
7.2.1 模式对话框
Windows 应用程序经常通过对话框与用户通信,Visual C++ 对话框编辑器使设计对话框和创建它们的对话框模板资源更为容易,代码向导则简化了在对话框中初始化和验证控件的过程和收集用户输入的值的过程。
大多数对话框是有模式的,即要求用户在使用程序的其他任何部分之前关闭对话框。
在ObjectARX中可以很容易的使用模式对话框,下面结合ObjectARX向导,来说明模式
对话框的使用。
我们将通过对话框来绘制三维的H型钢,示意图如图7-2,
图7-2 H型钢示意图
其中各参数的说明如下:
H:截面高
B: 腹板宽
A: 翼缘厚
W: 翼缘宽
L: 绘制的长度
另外绘制位置从当前图形中选取,以下说明创建的详细步骤。
1.通过ObjectARX向导创建工程,工程名称为CH07,需要说明的是所创建的工程支持MFC,如图7-1。
2.在OjbectARX工程中创建对话框,界面设计如图7-3。
图7-3界面设计
3.点击ObjectARX工具条的按钮(第二个),启动Autodesk class Explorer,向导,选择工程如CH07, 单击右键,在弹出的右键菜单中选择Add an ObjectARX MFC Ext.Class…如图7-4。
图7-4创建对话框类
4.选择从CAcUiDialog对话框类派生自定义的对话框,名称为CDialogSteel。
CAcUiDialog类是从CAdUiBaseDialog类派生的类,是一个提供了具有AutoCAD 对话框界面特征的对话框类,而且提供一系列通用的对话框成员函数,如图7-5所示。
图7-5创建对话框类
5.创建一个新的命令用于显示对话框,代码如下:
static void CSCH07CreateSteel(void)
{
//隐式管理资源
CAcModuleResourceOverride resOverride;
CDialogSteel dlgSteel;
dlgSteel.DoModal();
}
将程序编译后加载后,在命令行中输入命令会看到对话框可以被创建,此时的对话框不能执行任何操作,接下来的工作就是添加变量和控件的事件处理函数,用户可以参考示例程序完成该部分内容,这里只对关键的部分做一下说明。
从对话框中拾取点的时候,首先要调用BeginEditorCommand()函数说明交互式命令开始,实现隐藏对话框并调用aeedGetPoint 从当前绘图环境中选择一个点,调用CompleteEditorCommand()函数表示交互式命令完成,或者调用CancelEditorCommand()表示交互命令取消,对话框中用到于用户交互时候,通常会用到这些函数,下面我们看一下
在该对话框中选点按钮的执行内容。
void CDialogSteel::OnBnClickedButtonPick()
{
//隐藏对话框,等待用户输入
BeginEditorCommand();
ads_point pt;
if (acedGetPoint(NULL, _T("\n请拾取H型钢的绘制位置: "), pt) == RTNORM) {
//重新调出对话框
CompleteEditorCommand();
m_dPtX= pt[X];
m_dPtY= pt[Y];
m_dPtZ= pt[Z];
UpdateData(FALSE);
} else
{
//不显示对话框并且关闭
CancelEditorCommand();
}
}
当用户点击绘制按钮的时候,系统将基于用户输入的数据绘制三维的H型钢,该部分的代码如下:
void CDialogSteel::OnBnClickedOk()
{
UpdateData(TRUE);
acutPrintf(_T("创建H型钢...\n"));
// 基于用户输入的数据创建多义线
AcDbPolyline * pLine;
AcGePoint2d pt0(0.0,0.0);
AcGePoint2d pt1(m_dW,0.0);
AcGePoint2d pt2(m_dW,m_dA);
AcGePoint2d pt3(0.5*(m_dW+m_dB),m_dA);
AcGePoint2d pt4(0.5*(m_dW+m_dB),m_dH- m_dA);
AcGePoint2d pt5(m_dW,m_dH-m_dA);
AcGePoint2d pt6(m_dW,m_dH);
AcGePoint2d pt7(0.0,m_dH);
AcGePoint2d pt8(0.0,m_dH- m_dA);
AcGePoint2d pt9(0.5*(m_dW-m_dB),m_dH- m_dA);
AcGePoint2d pt10(0.5*(m_dW-m_dB),m_dA);
AcGePoint2d pt11(0.0,m_dA);
pLine = new AcDbPolyline;
pLine->setDatabaseDefaults();
pLine->reset (Adesk::kFalse, 0);
pLine->addVertexAt (0, pt0);
pLine->addVertexAt (1, pt1);
pLine->addVertexAt (2, pt2);
pLine->addVertexAt (3, pt3);
pLine->addVertexAt (4, pt4);
pLine->addVertexAt (5, pt5);
pLine->addVertexAt (6, pt6);
pLine->addVertexAt (7, pt7);
pLine->addVertexAt (8, pt8);
pLine->addVertexAt (9, pt9);
pLine->addVertexAt (10, pt10);
pLine->addVertexAt (11, pt11);
pLine->setClosed (Adesk::kTrue);
// 对创建的多义线进行平移变换
//移动到用户选择的位置点
AcGeMatrix3d mat;
mat.setToTranslation (AcGeVector3d(m_dPtX,m_dPtY,m_dPtZ));
pLine->transformBy (mat);
//拉伸为三维实体
AcDbObjectId idSolid;
CSolidHelper::extrudePoly(pLine,m_dL,idSolid);
delete pLine;
OnOK();
}
以上代码中的CSolidHelper::extrudePoly()函数将基于传入的多义线和拉伸长度创建三维的实体,该部分代码通过一个工具类CSolidHelper完成,实现内容如下:Acad::ErrorStatus
CSolidHelper::extrudePoly(AcDbPolyline* pPoly, double height, AcDbObjectId& savedExtrusionId)
{
Acad::ErrorStatus es = Acad::eOk;
// 炸开传入的对象
//
AcDbVoidPtrArray lines;
pPoly->explode(lines);
// 基于线创建区域.
//
AcDbVoidPtrArray regions;
AcDbRegion::createFromCurves(lines, regions);
assert(regions.length() == 1);
AcDbRegion *pRegion = AcDbRegion::cast((AcRxObject*)regions[0]);
assert(pRegion != NULL);
//拉伸区域生成三维体
//
AcDb3dSolid *pSolid = new AcDb3dSolid;
assert(pSolid != NULL);
es = pSolid->extrude(pRegion, height, 0.0);
for (int i = 0; i < lines.length(); i++) {
delete (AcRxObject*)lines[i];
}
for (int ii = 0; ii < regions.length(); ii++) {
delete (AcRxObject*)regions[ii];
}
if(Acad::eOk == es)
{
savedExtrusionId = CSolidHelper::AddEntityToDatabase(pSolid);
pSolid->close();
}
else
delete pSolid;
return Acad::eOk;
}
程序最终的运行结果如下:
图7-6 H型钢的运行结果
7.2.3 无模式对话框
无模式对话框与有模式对话框不同的是在创建后其他窗口都可以继续接收用户输入,因此无模式对话框有些类似一个弹出窗口。
在应用程序运行时,无模式对话框每隔一定的时间将接收到系统发来的Windows消息WM_ACAD_KEEPFOCUS。
当对话框接收到该消息时,如果需要继续将焦点保持在当前对话框窗口,则必须返回TRUE。
如果该消息的返回值是FALSE(缺省),则一旦用户将鼠标移到该对话框窗口之外,焦点也将随之失去。
对于有模式和无模式对话框,资源编辑和创建对话框的过程相同,操作步骤请参见前面的模式对话框的创建过程,我们将通过选取轮廓线来拉伸三维实体(H型钢),最后界面设计如下:
图7-7 无模式对话框
创建无模式对话框需要调用BOOL CDialog::Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );之后还需要调用BOOL CDialog::ShowWindow( SW_SHOW);进行显示,否则无模式对话框将是不可见的。
在工程中添加调用该对话框的命令,相关代码如下:
static void CSCH07ModalessSteel(void)
{
// 创建无模式对话框
CAcModuleResourceOverride resOverride;
//CModelessDialogSteel *
if(!g_pDlgModeless)
{
g_pDlgModeless = new CModelessDialogSteel();
g_pDlgModeless->Create(CModelessDialogSteel::IDD);
g_pDlgModeless->ShowWindow(SW_SHOW);
}
else
{
g_pDlgModeless->ShowWindow(SW_SHOW);
}
}
在上面的代码中生成了一个对话框对象,而且在退出函数时并没有销毁该对象。
如果此时销毁该对象(对象被销毁时窗口同时被销毁),而此时对话框还在显示,所以就会出
现错误。
可以在对话框退出时销毁自己,在对话框中重载OnOK与OnCancel在函数中调用父类的同名函数,然后调用DestroyWindow()强制销毁窗口,在对话框中映射WM_DESTROY消息,在PostNcDestroy()函数中调用强行删除自身对象。
相关代码如下:
void CModelessDialogSteel::OnBnClickedCancel()
{
CAcUiDialog::OnCancel () ;
DestroyWindow();
}
void CModelessDialogSteel::PostNcDestroy(void)
{
delete this;
if(g_pDlgModeless)
{
g_pDlgModeless = NULL;
}
}
通过上面的步骤无模式对话框就创建完成,下面完善一下对话框的内容,对话框中【选择轮廓线】按钮将提示用户选择轮廓线(多义线)并返回的AcDbObjectId,用于后面的操作,实现内容如下:
void void CModelessDialogSteel::OnBnClickedButtonPick()
{
//BeginEditorCommand();
// 将焦点放在当前视图
acedGetAcadDwgView()->SetFocus();
ads_name en;
ads_point pt;
int ret = acedEntSel(_T("\n请选择轮廓线(多义线):\n"), en, pt);
if(ret == RTNORM)
{
Acad::ErrorStatus es = acdbGetObjectId(m_idPoly, en);
}
//CompleteEditorCommand();
}
当用户点击对话框中的【绘制】按钮,后根据所选的轮廓线(多义线)的对象ID,将建三维的实体,代码内容如下:
void CModelessDialogSteel::OnBnClickedOk()
{
if(m_idPoly == AcDbObjectId::kNull )
{
acutPrintf(_T("没有选择轮廓线(多义线),退出"));
return;
}
// 锁定文档
AcApDocument* pDoc = acDocManager->curDocument();
Acad::ErrorStatus es = acDocManager->lockDocument(pDoc);
AcDbEntity *pEnt = NULL;
if(Acad::eOk == acdbOpenObject(pEnt, m_idPoly, AcDb::kForWrite))
{
AcDbPolyline* pPolyline = NULL;
if(pEnt->isKindOf (AcDbPolyline::desc ()))
{
pPolyline = AcDbPolyline::cast(pEnt);
AcDbObjectId idSolid;
CSolidHelper::extrudePoly(pPolyline,m_dL,idSolid);
}
else
{
acutPrintf(_T(" 所选择对象不是轮廓线(多义线),退出\n"));
}
pEnt->close();
}
// 焦点给当前视图
acedGetAcadDwgView()->SetFocus();
// 解锁文档
acDocManager->unlockDocument(pDoc);
}
最后,程序最终的运行结果如下:
图7-8 无模式对话框运行结果
7.3 练习
(1)下列关于AdUi和AcUi的描述中,_________是错误的。
A. AdUi是一个MFC扩展动态链接库,它用来扩充与用户界面有关的MFC类库。
B. AcUi不是基于AdUi结构框架的。
C. AdUi库使用一种内部的消息传递方法来简化对象之间的通信。
D. AdUi和AcUi库提供的类扩展了MFC提供的类,MFC开发者可以无缝的使用
这些类。
(3)判断题(正确的在括号内画“√”,错误的画“×”)
()在ObjectARX开发中,资源是被隐式管理的,开发者不需要对新加入的资源进行管理。
()在创建非模式对话框的时候,如果要让对话框保持焦点,需要处理onAcadKeepFocus()函数。
(4)创建一个非模式对话框,显示选择当前DWG文档中单线实体的起点和终点坐标。
11
PDF 文件使用 "pdfFactory Pro" 试用版本创建。