March 31, 2013

vLB - Tra th­ước Lỗ Ban

vLB - Phần mềm tra thước Lỗ Ban

Xin giới thiệu với các bạn một phần mềm tra thước Lỗ Ban. 

Download:
4Shared.com
hoặc
Mediafire [MF]


Mình không muốn nói nhiều về thước Lỗ Ban, chỉ xin giới thiệu sơ qua về phần mềm.
  • vLB dùng để tra nhanh thước Lỗ Ban loại 52,2cm, 42,9 và 38,8cm.
  • vLB có sử dụng 3 loại ngôn ngữ tiếng Việt là: không dấu, font chữ TCVN và font chữ Unicode. Bạn có thể tùy chọn cho phù hợp trong lúc làm việc.
  • Giới hạn của thước từ 0m đến 15m.
  • Bạn có thể dễ dàng kéo và thả để di chuyển thước.
Có lần phải chọn kích thước bàn thờ,  mình biết rằng kích thước từ bàn thờ, đến nhà cửa, đất cát nếu tuân theo thước Lỗ Ban thì rất tốt cho gia chủ (chưa kiểm chứng được :)! Việc tra thước Lỗ Ban đã có rất nhiều phần mềm của các chuyên gia phong thủy. Tuy nhiên do lần đầu phải làm việc với thước Lỗ Ban nên mình rất bối rối. Cộng với việc thông tin trên mạng rất nhiều nên thực sự không biết tra như nào cho chuẩn xác.

Sau một thời gian nghiên cứu mình đã tạo ra phần mềm này, hy vọng những bạn dùng nó sẽ không cảm thấy bỡ ngỡ như mình lúc đầu.

Tiện thể có mấy số chuẩn trong việc chọn kích thước bàn thờ để các bạn tham khảo: 81cm, 127cm, 153cm ...

Và kích thước bàn thờ mình đã chọn là 81cm - 127cm - 153cm. Hôm nào rảnh sẽ post ảnh để mọi người ngắm nghía :)

Download:
4Shared.com
hoặc
Mediafire [MF]

Trong trường hợp bị lỗi font, bạn có thể tải font MS San Serife tại đây

Tham khảo thêm:

March 17, 2013

Bài 14: Tự tạo một thực thể (từng bước một)

Xin chào,

Trong bài này, tôi sẽ tiếp tục hoàn thành bài 13 với một hướng dẫn để trình bày cho bạn biết cách tạo một thực thể đơn giản, từng bước một. Thực thể này có một vài tính năng giúp bạn thấy được cái gì có thể xảy ra khi sử dụng ObjectARX.
Hãy đọc cẩn thận những chỉ dẫn sau đây.
-Tạo một Giải pháp trống (Blank Solution) gọi là CustomEntitySample;
-Thêm một dự án DBX có tên CustEntityDBX;
-Thêm dự án ARX tên là CustEntityARX;
-Hãy nhớ bật mở rộng MFC trong cả hai dự án;
-Tạo một phụ thuộc (dependency) từ dự án ARX tới DBX:

Tạo một phụ thuộc Dependency



-Vào dự án DBX và mở Autodesk Class Explorer;
-Click chuột phải vào nhánh CustEntityDBX và chọn "Add ObjectDBX Custom Object...":


-Chọn tên lớp MyCustomEntity và dẫn xuất nó từ lớp AcDbEntity;
-Các thông tin khác sẽ được điền tự động (Bạn có thể thay đổi nếu muốn);


-Vào TAB Protocols và bật cả hai giao thức OsnapGrip-points:


-Xây dựng lại Rebuild dự án nếu mọi việc hoàn thành;
-Bây giờ mở lại Autodesk Class Explorer, vào dự án CustEntityDBX;
-Chọn nhánh MyCustomEntity (nếu không nhìn thấy, click vào biểu tượng Refresh);
-Click chuột phải vào nó và chọn "Add Variable...":


-Đặt tên nó là "m_PtA", kiểu AcGePoint3d và kiểu truy suất là protected;
-Bật "Participate to DWG filing protocol" (tham gia giao thức điền DWG), Tắt "Increase Version number" (Tăng số hiệu phiên bản);
-Bật "Implement Get/Put methods" và điền ghi chú cần thiết;
-Lặp lại quá trình trên với các biến : "m_PtB", "m_PtAB" và "m_PtBA":


-Bây giờ, thêm một biến kiểu CString có tên "m_Text";
-Nhớ sửa chữa thao tác CString và điền đầy đủ như những gì ta đã làm trong Lab3;
-Bây giờ bạn đã có thể chạy biên dịch;


Trước khi tiếp tục, chúng ta cần loại bỏ vài hàm không sử dụng đến. Đầu tiên loại bỏ trong tệp tiêu đề Header (*.h):

virtual Acad::ErrorStatus getGripPoints (
AcDbGripDataPtrArray &grips, const double curViewUnitSize, const int gripSize,
const AcGeVector3d &curViewDir, const int bitflags) const;
virtual Acad::ErrorStatus moveGripPointsAt (
const AcDbVoidPtrArray &gripAppData,
const AcGeVector3d &offset, const int bitflags);
Có 4 phương thức getOsnapPoints(). Chúng ta chỉ sử dụng một phương thức sau:

virtual Acad::ErrorStatus getOsnapPoints (
AcDb::OsnapMode osnapMode,
int gsSelectionMark,
const AcGePoint3d &pickPoint,
const AcGePoint3d &lastPoint,
const AcGeMatrix3d &viewXform,
AcGePoint3dArray &snapPoints,
AcDbIntArray &geomIds) const ;

Nào, bạn sẽ cần xóa phần thân của các hàm trong tệp tin cpp.

WORLDDRAW


-Để vẽ thực thể custom entity, chúng ta cần thêm đoạn mã sau vào phương thức worldDraw():

assertReadEnabled();
// Bounding Polyline
AcGePoint3d pts[4];
pts[0] = m_PtA;
pts[1] = m_PtAB;
pts[2] = m_PtB;
pts[3] = m_PtBA;
mode->subEntityTraits().setSelectionMarker(1); // Mark 1
mode->subEntityTraits().setColor(1); // Red
mode->geometry().polygon(4,pts);
// Entity's Text
mode->subEntityTraits().setSelectionMarker(2); // Mark 2
mode->subEntityTraits().setColor(256); // ByLayer
AcGiTextStyle style;
style.setFileName(_T("txt.shx"));
style.setBigFontFileName(_T(""));
style.setTextSize(25);
style.loadStyleRec();
AcGePoint3d txtPt((m_PtB.x+m_PtA.x)/2.0, (m_PtB.y+m_PtA.y)/2.0, m_PtA.z);
mode->geometry().text(txtPt, AcGeVector3d::kZAxis,
(m_PtAB-m_PtA),m_Text, m_Text.GetLength(),Adesk::kFalse, style);
return Adesk::kTrue;

Các điểm GRIP

-Mở phương thức getGripPoints() bên trong thực thi MyCustomEntity (cpp);
-Chúng ta sẽ bật 5 điểm grips cho thực thể. Các điểm góc (A,B,AB và BA) cộng với điểm ở tâm;
-Bên trong getGripPoints(), thêm đoạn mã sau:
gripPoints.append(m_PtA);
gripPoints.append(m_PtAB);
gripPoints.append(m_PtB);
gripPoints.append(m_PtBA);
gripPoints.append(AcGePoint3d((m_PtB.x+m_PtA.x)/2.0,
(m_PtB.y+m_PtA.y)/2.0,m_PtA.z));
-Bây giờ, khi người dùng click vào mỗi điểm Grip, chúng ta sẽ tiến hành các hành động tương ứng thông qua phương thức moveGripPointsAt();
-Chúng ta cần phải kiểm tra chỉ số của mỗi điểm Grip được kích hoạt tương ứng với phương thức getGripPoints() và áp dụng các biến đổi cần thiết;
-Trong phương thức còn lại moveGripPointsAt(), thêm đoạn mã sau:
assertWriteEnabled();
for(int i=0; i<indices.length(); i++) {
int idx = indices.at(i);
// For A and center point
if (idx==0 idx==4) m_PtA += offset;
// For AB and center point
if (idx==1 idx==4) m_PtAB += offset;
// For B and center point
if (idx==2 idx==4) m_PtB += offset;
// For BA and center point
if (idx==3 idx==4) m_PtBA += offset;
}
return (Acad::eOk);

Các điểm OSNAP

-Mở phương thức getOsnapPoints(). Chúng ta sẽ thêm 3 điểm Osnap kiểu: EndPoint, MidPoint and Center:
assertReadEnabled();
switch (osnapMode) {
case AcDb::kOsModeEnd:
snapPoints.append(m_PtA);
snapPoints.append(m_PtAB);
snapPoints.append(m_PtB);
snapPoints.append(m_PtBA);
break;
case AcDb::kOsModeMid:
snapPoints.append(m_PtA+((m_PtAB-m_PtA).length()/2.0)*((m_PtAB-m_PtA).normalize()));
snapPoints.append(m_PtAB+((m_PtB-m_PtAB).length()/2.0)*((m_PtB-m_PtAB).normalize()));
snapPoints.append(m_PtB+((m_PtBA-m_PtB).length()/2.0)*((m_PtBA-m_PtB).normalize()));
snapPoints.append(m_PtBA+((m_PtA-m_PtBA).length()/2.0)*((m_PtA-m_PtBA).normalize()));
break;
case AcDb::kOsModeCen:
snapPoints.append(AcGePoint3d((m_PtB.x+m_PtA.x)/2.0,
(m_PtB.y+m_PtA.y)/2.0, m_PtA.z));
break;
}
return (Acad::eOk);

BIẾN ĐỔI


-Thực thể biến đổi được thực hiện bởi phương thức transformBy();
-Mở Autodesk Class Explorer, mở rộng nhánh MyCustomEntity, -> nhánh Base Classes và sau cùng là nhánh AcDbEntity;
-Kéo danh sách xuống và lựa chọn:

Acad::ErrorStatus transformBy(const AcGeMatrix3d &);

-Click chuột phải trong phương thức này và chọn "Implement Base Class Method";
-Hàm logic này rất đơn giản, chỉ cần thêm đoạn mã sau:

assertWriteEnabled();
m_PtA.transformBy(xform);
m_PtAB.transformBy(xform);
m_PtB.transformBy(xform);
m_PtBA.transformBy(xform);
return (Acad::eOk);
-Hàm này sẽ cho phép thực thể có thể biến đổi được;

DỰ ÁN ARX


-Đầu tiên chúng ta sẽ thêm lệnh mới có tên "MyCustEnt";
-Nó sẽ tạo ra phương thức bên trong tệp acxrEntryPoint.cpp;
-Bây giờ, thêm chỉ thị cần cần thiết sau #include "StdAfx.h":

#include "..\CustEntityDBX\MyCustomEntity.h"
-Trong phương thức, chúng ta sẽ tạo ra thực thể:

// Input information
ads_point pt1,pt2;
if (acedGetPoint(NULL,_T("Set the first point:\n"),pt1) != RTNORM)
return;
if (acedGetCorner(pt1,_T("Set the second point:\n"),pt2) != RTNORM)
return;

TCHAR buffer[512];
if (acedGetString(0,_T("Enter the text:\n"),buffer) != RTNORM)
return;

// Setup entity
MyCustomEntity *pEnt = new MyCustomEntity();
pEnt->put_m_PtA(asPnt3d(pt1));
pEnt->put_m_PtAB(AcGePoint3d(pt2[X],pt1[Y],pt1[Z]));
pEnt->put_m_PtB(asPnt3d(pt2));
pEnt->put_m_PtBA(AcGePoint3d(pt1[X],pt2[Y],pt2[Z]));
pEnt->put_m_Text(buffer);

// Post to Database
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable,
AcDb::kForRead);

AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,AcDb::kForWrite);
pBlockTable->close();

AcDbObjectId retId = AcDbObjectId::kNull;
pBlockTableRecord->appendAcDbEntity(retId, pEnt);
pBlockTableRecord->close();
pEnt->close();

TEST


-Rebuild lại dự án;
-Mở AutoCAD và tải module DBX trước tiên rồi tải ARX;
-Bắt đầu lệnh MYCUSTENT và tạo bao nhiêu thực thể bạn muốn;
-Kiểm tra nó thông qua chỉnh sửa GRIP, MOVE, ROTATE, SCALE;
-Thực hiện lệnh LINE và thử bắt điểm (EndPoint, MidPoint và Center) trên thực thể xem sao;


Link nguồn: Arxdummies

Bài 12: Dẫn xuất từ AcDbObject

Giới thiệu

Tôi sẽ bắt đầu với những đối tượng mới và còn vấn đề thực thể mới sẽ được trình bày trong bài kế tiếp. Đối tượng mới có thể được sử dụng với nhiều mục đích khác nhau và chúng thực sự rất mạnh mẽ. Một khi ứng dụng tạo ra và quản lý một đối tượng mới, cấu trúc càng phức tạp bao nhiêu thì ứng dụng lại càng thông minh và lưu trữ dữ liệu hiệu qủa bấy nhiêu.
Bắt đầu bằng một ví dụ đơn giản, giả sử bạn sẽ xây dựng một ứng dụng ObjectARX sẽ triển khai một vài thanh ngang, chúng có thuộc tính chiều dài và mang một kiểu mẫu shape nhất định. Có thể có nhiều hơn một thanh ngang mang cùng một kiểu mẫu và sẽ thật tốt nếu bạn có thể cung cấp một ví dụ của thông tin shape và chia sẻ nó giữa tất cả các thanh ngang sử dụng kiểu mẫu này.
Đầu tiên là lặp lại thông tin trên từng thanh ngang một không quan trọng nếu có sự trùng lặp thông tin. Nó vẫn làm việc nhưng sẽ tạo thêm vấn đề dựa vào vấn đề đầu tiên cái mà  là không gian không cần thiết để lưu trữ các thông tin trùng lặp. Giả sử bạn cần cập nhật thông tin shape và bạn muốn áp dụng lên tất cả các thanh ngang sử dụng mẫu shape này. Nếu thông tin được lặp lại trên từng thành ngang, bạn sẽ cần mở mỗi thanh ngang và cập nhật thông tin cho nó. Tuy nhiên, nếu thông tin shape được cất giữ tại cùng một vị trí và thanh ngang kia phản chiểu thông thi này, bạn sẽ chỉ cần cập nhật thông tin tại một nơi duy nhất, và mọi thanh ngang sử dụng cùng mẫu shape sẽ được cập nhật ngay khi bạn cập nhật thông tin.
AutoCAD sử dụng kỹ thuật này trên nhiều tính năng như lớp, text style, nhóm group, ... Bạn sẽ sử dụng đối tượng mới để lưu trữ thông tin này và chia sẻ nó, thông qua mã ObjectId, giữa tất cả các "máy trạm" của đối tượng này.

Bắt đầu như thế nào?

Như đã thảo luận trong bài trước, bạn cần phải dẫn xuất từ AcDbObject để có thể xây dựng một đối tượng riêng. Việc này có thể thực hiện một cách đơn giản thông qua ARXWizard hoặc có thể tự làm bằng cách tạo ra lớp mới bằng tay.
Sau khi tạo được lớp mới, bạn cần xây dựng một vài phương thức như tạo, lưu trữ và thu nhận phiên bản của những đối tượng này từ khoang chứa tương ứng. Tốt thôi, nhưng bạn nên cất giữ đối tượng mới ở đâu? AutoCAD cung cấp khoang chứa cho mục đích chung gọi là NOD (từ điển đối tượng được đặt tên - Named Object Dictionary). NOD có nhiệm vụ cất giữ bất kể đối tượng nào được dẫn xuất từ AcDbObject. Nó sử dụng từ điển giống như cấu trúc lưu trữ khi bạn đặt một mã độc nhất (trong cùng một cấp độ) và một phiên bản đối tượng thông qua con trỏ và mã ObjectId. Có một vài khoang chứa đối tượng kiểu mới như Extension Dictionary sẽ được nhắc tới trong một bài khác.
Khoang chứa NOD có thể và nên được sắp xếp theo thư mục để cho từ điển có được tổ chức nhất có thể. Mấu chốt đầu tiên là tên ứng dụng để tránh xung đột với các ứng dụng ObjectARX của bên thứ ba mà sử dụng NOD cùng lúc với dựng dụng của bạn. Mức thứ hai là nên chứa tất cả các nhóm thương mại của đối tượng. Nó thực sự dựa vào việc có bao nhiêu và số lượng kiểu đối tượng mới mà bạn có. NOD không cập bạn lưu trữ các lớp khác nhau tại cùng một cấp bậc, nhưng tôi thực sự khuyên bạn tránh việc đó trừ trường hợp bạn cần lưu trữ các đối tượng chung như trong nhóm ưu tiên (Preferences group) của đối tượng.

Bạn không cần phải mở và đóng NOD thường xuyên và đi sâu tìm kiếm vị trí đối tượng dẫn xuất mỗi lúc cần truy xuất đến nó. Bạn có thể xây dựng một vài kiểu bộ đệm của đối tượng sử dụng nhiều nhất thông qua mã ObjectId và quản lý bộ đệm này để cập nhận đến từng bản vẽ đang được mở. Nhớ rằng NOD là một phần của đối tượng AcDbDatabase và nó là một per document. Vì vậy, bạn cần phải quan tâm đến việc xây dựng và điền vào từ điển cho mỗi bản vẽ mới được mở ra.

Tiếp tục với đối tượng mới như thế nào?

Như đã đề cập trước đó, nơi cất giữ đối tượng kiểu mới là NOD - một AcDbDictionary. NOD quan tâm đến các đối tượng con bởi vì nó là một khoang chứa. Vì vậy, khi đối tượng AcDbDatabase được đưa ra để ghi lại dữ liệu của nó bởi AutoCAD, nó cũng chuyển thông báo này tới đối tượng con và NOD là một trong số đó. Một khi NOD nhận được thông báo, nó kiểm tra trong cấu trúc và gọi hàm dwgOutFileds() cho từng đối tượng lưu giữ trong đó. Quá trình tương tự xảy ra khi bạn mở bản vẽ và hàm dwgInFileds() được gọi bởi AcDbDatabase trên NOD và trên đối tượng con. Nhờ có nó bạn sẽ cần ghi đè lên phương thức lấp đầy DWG để có thể tiếp tục sử dụng các đối tượng mới giữa quá trình đóng và mở DWG. Bản chất của hàm ghi đè trong lớp đối tượng kiểu mới là:
virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer);
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const;
virtual Acad::ErrorStatus dxfInFields(AcDbDxfFiler* filer);
virtual Acad::ErrorStatus dxfOutFields(AcDbDxfFiler* filer) const;
Nếu không định hỗ trợ giao diện DXF trong đối tượng riêng, bạn có thể bỏ qua chúng.

Quản lý trạng thái đối tượng

Trong bài 5, chúng ta đã nói về trạng thái đối tượng khi nó được mở. Bên trong lớp đối tượng riêng, bạn cần phải chú ý để gọi phương thức xác nhận phù hợp để chắc chắn rằng mọi sự kiện và quá trình thích hợp được kích hoạt khi trang thái đối tượng thay đổi. Việc này rất quan trọng!
Những hàm thay đổi trạng thái dữ liệu của đối tượng phải gọi hàm assertWriteEnabled() đầu tiên và sau đó áp dụng các thay đổi cần thiết. Những hàm chỉ đọc thông tin từ đối tượng và không ảnh hưởng đến trạng thái phải gọi hàm assertReadEnabled() và tôi cũng khuyên bạn làm tất cả dưới dạng hàm hằng số. Việc đó nhằm tránh tai nạn có thể làm thay đổi trạng thái đối tượng khi nó được mở để Đọc, sẽ gây ra thông báo lỗi xác nhận. Nếu quên gọi phương thức xác nhận chính xác, những việc lạ thường có thể xảy ra giống như gọi UNDO và đối tượng vẫn không thay đổi ...

Làm thế nào để tạo ra đối tượng kiểu mới

Để bổ sung một đối tượng mới, bạn cần thực hiện các bước sau đây:
  1. Dẫn xuất từ lớp cơ sởAcDbObject;
  2. Bổ sung dữ liệu;
  3. Bổ sung hàm truy xuất (Đọc/Ghi) với phương thức xác nhận phù hợp;
  4. Bổ sung phương thức lấp đầy duy trì và đọc dữ liệu;
Tôi sẽ trình bày một ví dụ đơn giản sau:
// -------------------------------------------
// Class declaration
// -------------------------------------------
 

class MyClass : public AcDbObject {

public:
ACRX_DECLARE_MEMBERS(MyClass);

MyClass() {};
virtual ~MyClass() {};

Acad::ErrorStatus getVal (int& val) const;
Acad::ErrorStatus setVal (int val);

Acad::ErrorStatus getString (CString& str) const;
Acad::ErrorStatus setString (LPCTSTR str);

virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler*);
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*) const;

private:
int m_Val;
CString m_Str;
};
// -------------------------------------------
// Class Definition
// -------------------------------------------
ACRX_DXF_DEFINE_MEMBERS(MyClass,
AcDbObject, AcDb::kDHL_CURRENT,
AcDb::kMReleaseCurrent, 0, MYCLASS, MYSAMP);
// -------------------------------------------Acad::ErrorStatus MyClass::getVal (int& val) const {
assertReadEnabled();val = m_Val;
return Acad::eOk;
}// -------------------------------------------Acad::ErrorStatus MyClass::setVal (int val) {
assertWriteEnabled();m_Val = val;
return Acad::eOk;
}// -------------------------------------------Acad::ErrorStatus MyClass::getString (CString& str) const {
assertReadEnabled();str.Format(_T("%s"),m_Str);
return Acad::eOk;

}// -------------------------------------------Acad::ErrorStatus MyClass::setString (LPCTSTR str) {
assertWriteEnabled();m_Str.Format(_T("%s"),str);
return Acad::eOk;
}// -------------------------------------------Acad::ErrorStatus MyClass::dwgInFields(AcDbDwgFiler* pFiler) {
assertWriteEnabled();
AcDbObject::dwgInFields(pFiler);
Adesk::Int16 _val = 0;
pFiler->readInt16(&_val);
m_Val = _val;
TCHAR* _temp = NULL;
pFiler->readString(&_temp);
m_Str.Format(_T("%s"),_temp);
acutDelString(_temp);

return pFiler->filerStatus();
}// -------------------------------------------Acad::ErrorStatus MyClass::dwgOutFields(AcDbDwgFiler* pFiler) const {
assertReadEnabled();
AcDbObject::dwgOutFields(pFiler);
pFiler->writeInt16(m_Val);
pFiler->writeString(static_cast<const TCHAR*>(m_Str));

return pFiler->filerStatus();
}// -------------------------------------------// -------------------------------------------
// Entry Point
// -------------------------------------------
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* appId) {
switch (msg) {
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
MyClass::rxInit();
acrxBuildClassHierarchy();
break;

case AcRx::kUnloadAppMsg:
deleteAcRxClass(MyClass::desc());
break;
}

return AcRx::kRetOK;
}

Làm cách nào để tạo và cất giữ đối tượng mới

Khoang chứa NOD dựa trên lớp AcDbDictionary có vài phương thức đọc, ghi và xóa đầu mục. Ứng dụng của bạn cần phải quan tâm đến đầu mục của NOD, chịu trách nhiệm tạo phiên bản của lớp mới và cất giữ chúng bên trong NOD. Mỗi một đối tượng được lưu giữ,  phải có một khóa định nghĩa hoặc một mã được sinh ra sử dụng  kí hiệu sao (*) trong tên của nó.
void createMyObjects() {
AcDbDictionary *pNamedobj = NULL;
acdbHostApplicationServices()->workingDatabase()->
getNamedObjectsDictionary(pNamedobj, AcDb::kForWrite);
AcDbDictionary *pDict = NULL;
if (pNamedobj->getAt(_T("MYDICT"),(AcDbObject*&) pDict,
AcDb::kForWrite) == Acad::eKeyNotFound) {
pDict = new AcDbDictionary;
AcDbObjectId DictId;
pNamedobj->setAt(_T("MYDICT"), pDict, DictId);
}
pNamedobj->close();
if (pDict) {
MyClass *pObj1 = new MyClass();pObj1->setVal(1);
pObj1->setString(_T("String1"));

MyClass *pObj2 = new MyClass();
pObj2->setVal(2);
pObj2->setString(_T("String2"));

AcDbObjectId rId1, rId2;
pDict->setAt(_T("*M"),pObj1, rId1);
pDict->setAt(_T("*M"),pObj2, rId2);

pObj1->close();
pObj2->close();

pDict->close();

}
}

Làm cách nào để xác thực đối tượng đã được cất giữ trong NOD hay chưa?

Bạn cần phải lặp qua từng đầu mục trong NOD để tìm từ điển của mình và sau đó tiền hành phép lặp với từng đầu mục của nó. Quá trình đó như sau:


void listMyObjects() {
AcDbDictionary *pNamedobj = NULL;
acdbHostApplicationServices()->workingDatabase()
->getNamedObjectsDictionary(pNamedobj, AcDb::kForRead);
AcDbDictionary *pDict = NULL;
pNamedobj->getAt(_T("MYDICT"), (AcDbObject*&)pDict,AcDb::kForRead);
pNamedobj->close();
if (pDict == NULL) {
acutPrintf(_T("\nThe dictionary MYDICT does not exist. Please create it first!"));
return;
}
AcDbDictionaryIterator* pDictIter= pDict->newIterator();
MyClass *pMyClass;
int _val;
CString _str;
for (; !pDictIter->done(); pDictIter->next()) {
pMyClass = NULL;
pDictIter->getObject((AcDbObject*&)pMyClass,AcDb::kForRead);
if (pMyClass != NULL) {
pMyClass->getVal(_val);
pMyClass->getString(_str);
pMyClass->close();
acutPrintf(_T("\nMyClass: val=%d, str=%s"),_val,_str);
}
}delete pDictIter;
pDict->close();
}
Tiếp tục đến bài tới, bạn sẽ học được cách tạo ra một thực thể mới!

Link nguồn: Arxdummies

Bài 13: Dẫn xuất từ AcDbEntity

Giới thiệu


Trong bài trước, bạn đã biết cách dẫn xuất từ AcDbObject để tạo ra một thực loại đối tượng mới mạnh mẽ và cách lưu trữ chúng trong NOD. Trong bài này, bạn sẽ được tìm hiểu về cách chúng ta có thể tạo ra một thực thể mới, dẫn xuất từ AcDbEntity hoặc một lớp dẫn xuất từ nó. Từ đó, bạn sẽ có một cách nhìn khác về sức mạnh thực sự của một ứng dụng ObjectARX là như thế nào! 
Phiên bản khởi nguồn của SDK ObjectARX trên AutoCAD 13 đã mở ra một thế giới mới cho những nhà phát triển và cho chính bản thân AutoDesk. Thực thể mới sẽ cho phép nhà lập trình xây dựng những ứng dụng đồ họa phong phú và thể hiện được nhiều tính năng mới không có trong những thực thể AutoCAD nguyên bản. AutoDesk cũng bắt đầu phát triển những ứng dụng riêng của họ dựa trên những loại thực thể mới được tạo ra, giúp mang đến những chức năng tuyệt vời, những trải nghiệm thú vị mà bạn chưa từng biết đến.
Khi bạn nghĩ về một thực thể mới, trước tiên bạn cần nghĩ đến việc sử dụng nó như thế nào, quản lý, chỉnh sửa và mọi tính năng nó thể hện trước người dùng. Việc này cho phép bạn có thể hoạch định hành vi của thực thể và liệt kê mọi công việc nó sẽ có thể hỗ trợ và tiến hành. Bước này hết sức quan trọng giúp quyết định khi nào nên sử dụng thực thể AutoCAD nguyên bản được thêm dữ liệu XData hoặc XRecords, và khi nào nên sử dụng một thực thể mới.
Mặt khác, khi sử dụng thực thể AutoCAD chuẩn, bạn cũng cần điều khiển được hành vi của chúng để hỗ trợ và quản lý mọi ứng xử của người dùng người dùng. Việc này không hề đơn giản và người dùng càng sáng tạo thì bạn sẽ càng mất thời gian. Khi bạn phát triển một thực thể mới độc lập (không dẫn xuất), nó sẽ mang lại cho bạn nhiều lợi thế trong việc điều khiển tiến trình của người dùng, nhưng nó cũng cung gây cho bạn không ít khó khăn.

Lợi thế của việc sử dụng một thực thể mới

Rất nhiều lợi thế bạn sẽ có được với một thực thể mới. Tôi muốn liệt kê một trong số những lợi thế đó chỉ để giúp bạn bạn nhận ra nó mạnh đến như thế nào:

Đồ họa mới (Custom graphics): Khi tạo một thực thể mới, bạn cũng có trách nhiệm tạo ra đồ họa của nó. ObjectARX cung cấp một vài hàm vẽ nguyên thủy cho phép bạn vẽ và sử dụng mọi thứ bạn cần. Đừng lo lắng nếu thực thể của bạn quá đơn giản hay quá phức tạp, ObjectARX cung cấp mọi công cụ để bạn có thể làm được.

Bắt điểm và điểm nút mới (Custom Grips and OSNAPs): Nó cũng cung cấp cho bạn thực thi hoặc không sử dụng lưới và chức năng bắt điểm (Object Snap). Bạn có sẽ cần một vài điểm OSNAP xác định và hàm chức năng lưới (Grip), đừng ngần ngại, hãy sử dụng nó!

Biến đổi riêng: Một thực thể mới có thể được biến đổi theo những tiêu chuẩn riêng của bạn. Nó có được đầy đủ lợi thể của thư viện AcGe bao hàm trong OjbjectARX.

Nhúng thực thể nguyên bản (Embedded native entities): Nếu bạn muốn xây dựng một thực thể mới nhìn giống những thực thể nguyên bản, bạn hoàn toàn có thể nhúng những thực thể gốc vào trong trong thực thể mới và và lấy được tính năng đã có của chúng. Giả sử bạn cần xây dựng một thực thể mới giống Polyline với hatch ở bên trong. Nó có thể dễ dàng thực hiện bằng cách nhúng một thực thể AcDbHatch vào trong thực thể dẫn xuất AcDbPolyline.

Đồ họa thực thể (Custom entity graphics)


Thư viện AcGi cung cấp mọi thứ cần thiết để xây dựng đồ họa cho thực thể của bạn. Thực thể đó sẽ được thể hiện trên màn hình AutoCAD bằng một trong hai phương thức cơ bản sau:

virtual Adesk::Boolean
AcDbEntity::worldDraw (AcGiWorldDraw * pWd);

virtual void
AcDbEntity::viewportDraw (AcGiViewportDraw * pVd);


Hàm đầu tiên là worldDraw() chịu trách nhiệm vẽ hình khối chuẩn cho thực thể. Hàm thứ hai là viewportDraw() có thể tùy chọn, nó cho phép bạn vẽ hình khối liên quan trên viewport. Hai hàm này sẽ nhận con trỏ ngữ cảnh vẽ,cho phép  bạn tiến hành vẽ.

Vì một vài lý do mà các hàm này sẽ được gọi đến một vài lần trong khi chạy. Bạn cần phải cung cấp đoạn mã nhanh và hiệu quả nhất có thể. Đừng thực hiện công việc tính toán nặng nề, vòng lặp dài và tốn thời gian ở đây. Thực thể mới được tạo nên từ các thực thể nguyên bản thì không được khai báo chúng bên trong hàm. Hãy khai báo chúng như những thành viên của lớp và chỉ cần chuyển hướng gọi hàm bên trong worldDraw() hoặc viewportDraw() tới những thực thể nhúng này.
AutoCAD tiến hành quá trình vẽ thông mọi thực thể cơ sở dữ liệu và gọi phương thức worldDraw() đầu tiên. Nếu phương thức worldDraw() trả về Adesk::kFalse, AutoCAD cũng sẽ hướng đến các viewport và gọi phương thức viewportDraw() của thực thể. Chính xác là lúc này bạn có thể vẽ hình khối khác nhau dựa trên định dạnh của mỗi viewport.
Các chức năng vẽ nguyên thủy hết sức đơn giản, chỉ bao gồm: Circle, Circular arc, Polyline, Polygon, Mesh, Shell, Text, Xline và Ray.  Xin hãy tham khảo tài liệu AcGi trong SDK ObjectARX để thấy được chỉ dẫn và thông tin chi tiết về cách sử dụng. Tất cả chúng đều được gọi đến thông qua hàm geometry().

Thực thể mới cũng cho phép bạn chia nhỏ chúng hơn nữa. Chức năng này được thực hiện bằng cách dùng đối tượng AcGiSubEntityTraits. Đối tượng này cài đặt các giá trị thông qua các hàm đặc tính:
  • Color
  • Layer
  • Linetype
  • Kiểu điền đa tuyến
  • Đánh dấu lựa chọn
Bằng cách này, bạn có thể chia các thông tin lô gics thông qua đồ họa của nó. Ví dụ, nếu thực thể có một vài text và một vài đoạn thẳng line, có thể bạn sẽ cần chia chúng vào hai tiểu nhóm thực thể. Xa hơn, nếu bạn muốn vẽ một phần thực thể dựa bằng màu hoặc đường nét xác định, nó cũng được thực hiện bằng các tiểu nhóm này. Mỗi tiểu thực thể đều có một đánh dấu riêng. Nó cho phép bạn tiến hành tương tác với người dùng bằng cách tìm ra tiểu thực thể nào đã được click. Nếu bạn muốn làm vậy, trước khi vẽ hình khối của tiểu thực thể, hãy gọi hàm setSelectionMarker() thông qua chỉ số tăng dần.
Trong hàm viewportDraw(), bạn phải truy cập đến
Dưới đây là một vài ví dụ của cả phương thức wordDraw()viewportDraw():
Đối tượng hình học viewport cung cấp

Inside viewportDraw() function you will also have access to caller viewport information through AcGiViewport object inside the AcGiViewportDraw object passed in. The viewport geometry object provides the same primitives world geometry object plus the following polygon and polyline primitives, which use eye and display space coordinates: polylineEye, polygonEye, polylineDc and polygonDc. Some examples of both worldDraw() and viewportDraw() methods are presented below:

Adesk::Boolean MyEnt::worldDraw(AcGiWorldDraw *pW) {

AcGePoint3d verts[5];

// Create some random points
verts[0] = verts[4] = AcGePoint3d(-0.5, -0.5, 0.0);
verts[1] = AcGePoint3d( 0.5, -0.5, 0.0);
verts[2] = AcGePoint3d( 0.5, 0.5, 0.0);
verts[3] = AcGePoint3d(-0.5, 0.5, 0.0);
// Set the subentity color as 3
pW->subEntityTraits().setColor(3);
// Draw the polyline primitive
pW->geometry().polyline(5, verts);
return Adesk::kTrue;
}
void MyEnt::viewportDraw(AcGiViewportDraw* pV){

AcGePoint2d lleft, uright;
// Get viewport's DC coordinates
pV->viewport().getViewportDcCorners(lleft,uright);

// Perform some math here

double xsize = uright.x - lleft.x;
double ysize = uright.y - lleft.y;
xsize /= 10.0;
ysize /= 10.0;
double xcenter = uright.x - xsize;
double ycenter = uright.y - ysize;
double hxsize = xsize / 2.0;
double hysize = ysize / 2.0;


AcGePoint3d verts[5];
// Set vertex initial value
for (int i=0; i<5; i++) {
verts[i].x = xcenter;
verts[i].y = ycenter;

verts[i].z = 0.0;

}

// Perform some adjustments
verts[0].x -= hxsize;
verts[0].y += hysize;
verts[1].x += hxsize;
verts[1].y += hysize;
verts[2].x += hxsize;
verts[2].y -= hysize;
verts[3].x -= hxsize;
verts[3].y -= hysize;
verts[4] = verts[0];


// Set the subentity color as 3

pV->subEntityTraits().setColor(3);

// Draw the polyline on DC context

pV->geometry().polylineDc(5, verts);
}

Thực thi bắt điểm (OSNAP)

Thực thể của bạn cũng cần cung cấp một vài tiêu điểm thông qua tính năng bắt điểm. Tùy thuộc vào độ phức tạp của thực thể mà bạn cần phải thực thi một vài điểm OSNAP và một số cách bắt điểm như EndPoint, Center, ... Để đưa tính năng OSNAP vào trong thực thể, bạn sẽ cần thêm phương thức sau vào trong lớp (Có rất nhiều đăng ký khác nhau):
virtual Acad::ErrorStatus AcDbEntity::getOsnapPoints(
AcDb::OsnapMode osnapMode,
int gsSelectionMark,
const AcGePoint3d& pickPoint,
const AcGePoint3d& lastPoint,
const AcGeMatrix3d& viewXform,
AcGePoint3dArray& snapPoints,
AcDbIntArray& geomIds) const;
Hàm sau sẽ giúp bạn điền các thông số vào mảng AcGePoint3dArray với những điểm phù hợp với phương thức bắt điểm. Các giá trị có thể xảy ra là:

AcDb::kOsModeEnd: điểu kết thúc trên thực thể gần điểm pickpoint nhất.
AcDb::kOsModeMid: trung điểm (của đoạn thẳng, cung tròn, ...) gần điểm pickpoint nhất.
AcDb::kOsModeCen: tâm điểm (của hình tròn hoặc cung tròn) gần điểm pickpoint nhất.
AcDb::kOsModeNode: điểm node gần pickpoint nhất.
AcDb::kOsModeQuad: điểm phần tư gần pickpoint nhất.
AcDb::kOsModeIns: điểm chèn của thực thể (của BlockReference hoặc đối tượng MText).
AcDb::kOsModePerp: giao điểm của thực thể với đường thẳng vuông góc với nó qua điểm lastPoint.
AcDb::kOsModeTan: điểm nằm trên thực thể nơi đường thẳng đi qua điểm lastPoint sẽ tiếp xúc với thực thể.
AcDb::kOsModeNear: Tìm điểm gần nhất với điểm pickPoint.


Tưởng tượng thực thể mới là một hình chữ nhật và người dùng chạy lệnh LINE muốn vẽ từ điểm EndPoint. Thực thể cần phải trả lời AutoCAD bằng cách cung cấp điểm EndPoint (nếu có). Trong trường hợp này, trong hàm getOsnapPoints() sẽ cần điền vào AcGePoint3dArray các điểm góc của hình chữ nhật. AutoCAD sẽ tìm các điểm nằm trong khung hình, và và gần con trỏ (cursor) nhất. Vì vậy hàm sẽ giống như sau:

Acad::ErrorStatus MyEnt::getOsnapPoints(
AcDb::OsnapMode osnapMode,
int gsSelectionMark,
const AcGePoint3d& pickPoint,
const AcGePoint3d& lastPoint,
const AcGeMatrix3d& viewXform,
AcGePoint3dArray& snapPoints,
AcDbIntArray& geomIds) const {

assertReadEnabled();
switch (osnapMode) {
case AcDb::kOsModeEnd:
snapPoints.append(pt[0]);
snapPoints.append(pt[1]);
snapPoints.append(pt[2]);
snapPoints.append(pt[3]);
break;
}
return Acad::eOk;

}

Điểm giao (intersection OSNAP) lại không có được thông qua phương thức getObjectSnap(). Vì rất phức tạp nên có một hàm đặc biệt gọi là intersectWith() đảm trách việc đó. Tôi không muốn giới thiệu chi tiết ở đây nhưng bạn có thể đọc và tìm hiểu thêm thông tin trong tài liều SDK.

Thực thi nắm GRIP và Kéo giãn điểm (GRIP and Stretch)

Phương thức nắm điểm (GRIP) cung cấp một cách thức đơn giản và tuyệt vời cho người dùng để chỉnh sửa và biến đổi các thực thể. Bạn có thể sẽ muốn bổ sung tính năng này trong thực thể của mình. Xa hơn, kéo dãn (stretch) điểm sẽ cho phép người dùng kéo dãn thực thể. Hai tính năng này có thể được bổ sung hết sức đơn giản,  làm cho thực thể của bạn thêm linh hoạt và mạnh mẽ.
Bạn chỉ cần cho biết điểm có bản (key point) làm điểm nắm Grip và Stretch. Những hàm khác sẽ chịu trách nhiệm trên tập hợp hành vi của thực thể khi mỗi điểm Grip và Stretch được sử dụng. Thực thể càng phức tạp thì chương trình càng phức tạp đôi chút. Với tính năng nắm điểm lưới Grip, bạn cần bổ sung một cặp hàm. Đầu tiên là hàm getGripPoints(), sẽ trả về những điểm bạn muốn kích hoạt chức năng điểm lưới. Hàm thứ hai gọi là moveGripPointsAt() sẽ thực hiện hành động khi điểm lưới bị kích hoạt.

virtual Acad::ErrorStatus
AcDbEntity::getGripPoints (AcGePoint3dArray& gripPoints,
AcDbIntArray& osnapModes,AcDbIntArray& geomIds) const;
virtual Acad::ErrorStatus
AcDbEntity::moveGripPointsAt (const AcDbIntArray& indices,
const AcGeVector3d& offset);
Nhớ rằng điểm lưới không bắt buộc phải nằm trên các hình khối. Bạn có thể tạo điểm lưới từ bất kỳ đâu, ví dụ như tâm của hình chữ nhật - nơi chẳng có hình khối nào.
Hàm getGripPoints() nhận 3 tham số. Chỉ tham số đầu tiên là đã được sử dụng. Đó là mảng điểm 3D được cung cấp bởi AutoCAD. Mảng này chứa mọi điểm liên quan đến quá trình nắm điểm lưới Grip. Như nhiều thực thể có liên quan đến quá trình này, mảng có thể đã được điền sẵn. Bạn chỉ cần thêm các điểm mong muốn vào mảng. Điểm thêm vào trong hàm getGripPoints() sẽ được xác định bằng chỉ số theo thứ tự.

Hàm moveGripPointsAt() sẽ nhận thứ tự mảng và vector 3D gửi bởi AutoCAD với quá trình biến đổi (AcGeVector3d) được áp dụng. Lần này bạn cần lặp trong mảng điểm, lấy từng giá trị (chỉ số), tùy thuộc vào giá trị khởi động quá trình biến đổi tại điểm mong muốn. Hình dung lần nữa rằng thực thể HCN của bạn có 5 điểm Grip, từng góc của HCN và điểm tâm. Với từng góc thì chỉ áp dụng biến đổi với điểm grip của nó, còn với điểm tâm bạn sẽ làm biến đổi cho toàn bộ mọi điểm. Quá trình nắm điểm góc sẽ tạo ra kết quả kéo dãn HCN tại góc và khi nằm điểm tâm, sẽ làm cho toàn bộ thực thể di chuyển. Để áp dụng biến đối với từng điểm, hãy gọi phương thức transformBy() với tham số vector AcGeVector3d nhận được từ AutoCAD.
Mặt khác, kéo điểm được định nghĩa và điều khiển bởi hai hàm. Chúng rất giống với chức năng điểm lưới Grip và đôi khi bạn chỉ cần trả về bằng cách gọi chức năng Grip bên trong hàm Stretch tương ứng:
virtual Acad::ErrorStatus
AcDbEntity::getStretchPoints(
AcGePoint3dArray& stretchPoints) const;
virtual Acad::ErrorStatus
AcDbEntity::moveStretchPointsAt(
const AcDbIntArray& indices, const AcGeVector3d& offset);
Hành vi của hàm kéo giãn tương tự giống với hàm Grip. Khi stretch một điểm, bạn chỉ cần chuyển hướng gọi hàm như sau:

Acad::ErrorStatus MyEnt::getStretchPoints(
AcGePoint3dArray& stretchPoints) const {
AcDbIntArray osnapModes,geomIds;
return MyEnt::getGripPoints(stretchPoints,osnapModes,geomIds);}

Acad::ErrorStatus MyEnt::moveStretchPointsAt(
const AcDbIntArray& indices, const AcGeVector3d& offset) {return MyEnt::moveGripPointsAt(indices,offset);}

Tương tự với khái niệm của hàm worldDraw() và viewportDraw() cũng được áp dụng vào các hàm moveGripPointAt() và moveStretchPointsAt(). Nó được gọi đến vài lần và chúng cần được thực hiện nhanh nhất có thể. Khi click vào một nút Grip, hàm moveGripPoints() sẽ được gọi tương ứng với sự di chuyển chuột nhỏ nhất.

Thực hiện một biến đổi


Thực thể mới sẽ cần hỗ trợ cho các phép biến đổi nếu bạn muốn cho phép người dùng tiến hành lệnh giống như MOVE, ROTATE và SCALE. Tính năng này được bổ sung thông qua phương thức transformBy(), nhận một ma trận biến đổi đại diện cho phép biến đối hiện hành được áp dụng với thực thể. Trong hàm, bạn sẽ áp dụng ma trận này vào dữ liệu của thực thể để mang lại các thay đổi. Lớp AcGeMatrix3d hỗ trợ tất cả các kiểu của biến đổi và đóng gói chúng vào trong một ma trận.
virtual Acad::ErrorStatus
AcDbEntity::transformBy(const AcGeMatrix3d& xform);

Thực thi điển hình của hàm transformBy() như sau:
Acad::ErrorStatus MyEnt::transformBy(
const AcGeMatrix3d& xform) {
pt[0].transformBy(xform);
pt[1].transformBy(xform);
pt[2].transformBy(xform);
pt[3].transformBy(xform);

}
Trong một vài trường hợp đặc biệt, bạn sẽ cần áp dụng biến đổi tới một tiêu bản hoặc bản sao của thực thể gốc. Thực hiện bằng phương thức getTransformedCopy() nhận ma trận biến đổi vafcon trỏ được lấp đầy với bản sao đã biến đổi của thực thể.

Cần nhiều thông tin hơn nữa? Trong bài tới, tôi sẽ trình bày một ví dụ thực hành ngắn gọn với một thực thể mới. Hãy tiếp tục theo dõi!

Link nguồn: Arxdummies

Bài 10: Sử dụng MFC

Bài học này không thật sự liên quan đến AutoCAD và ObjectARX, mà nó chỉ cho ta thấy một cái nhìn tổng quan về thư viện MFC. Thư viện này giúp bạn tạo giao diện phong phú cho ứng dụng ObjecARX một cách đơn giản với phong cách chuyên nghiệp.

Giới thiệu


MFC (Lớp nền tảng Microsoft - Microsoft Foundation Classes) là một thư viện mạnh cho lập trình viên windows dễ dàng tạo ra giao diện phong phú từ giao diện chuẩn của windows.
Cây phân lớp MFC rất đồ sộ và mạch lạc. Việc tạo một thuật sĩ (wizard) MFC không phải là mục tiêu của bài học. Mà ở đây tôi sẽ trình bày những khái niệm liên quan chính khi sử dụng MFC trong AutoCAD và làm cách nào để có được lợi thế từ sức mạnh của thư viện khổng lồ này.
Nếu muốn sử dụng MFC bên trong ứng dụng ObjectARX, bạn sẽ cần liên kết ứng dụng với thư viện MFC bằng liên kết động hoặc tĩnh. Hiện tại ObjectARX chỉ hỗ trợ liên kết động đến ứng dụng MFC DLL bởi vì một số thư viện AutoCAD đã được liên kết động với MFC và bạn không thể có lẫn hai trạng thái liên kết đến cùng một thư viện. Để tạo liên kết động với MFC trong ứng dụng, bạn cần lựa chọn MFC Extension DLL khi tạo một ứng dụng mới.

Quản lý tài nguyên


Một trong những khái niện quan trọng nhất khi làm việc với các thư viện MFC là việc chúng dựa vào các tài nguyên. Tài nguyên rất phong phú thông tin như ảnh bitmap, biểu tượng icon, bảng chuỗi ký tự, lớp hộp thoại, v.v. Mỗi một DLL có một gói tài nguyên riêng có thể được sử dụng bởi chính nó hoặc được chia sẻ với các DLL khác (Ví dụ Tài nguyên chỉ chỉ là DLL).

Vấn đề là ứng dụng ObjectARX được chạy bên trong ứng dụng nền AutoCAD mà AutoCAD đã có sẵn các nguồn tài nguyên. Để giải quyết vấn đề này, bạn nên chuyển đổi nguồn tài nguyên này vào trong DLL của bạn, sử dụng nó và chuyển đổi trở lại AutoCAD. Bạn làm việc đó thủ công hoặc có một cặp lớp sẽ giúp bạn thực hiện một cách đơn giản hơn.


Lớp đầu tiên gọi là CAcExtensionModule sẽ nắm giữ nguồn tài nguyên mà module sở hữu và nguồn tài nguyên mặc định. Để ứng dụng có thể lấy được lợi thế của lớp này, bạn sẽ cần phải tạo một đại diện của lớp bên trong mỗi hàm DllMain() module. Thực hiện như sau:
The first class, called CAcExtensionModule which will handle your module's own resource and the default resources. To make your application take advantage of this class you will need to create an instance of this class inside each module DllMain() function. This can be done using the following:
AC_IMPLEMENT_EXTENSION_MODULE(theArxDLL);
HINSTANCE _hdllInstance = NULL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
// Loại bỏ nếu bạn sử dụng lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH) {
theArxDLL.AttachInstance(hInstance);
hdllInstance = hInstance;
}
else if (dwReason == DLL_PROCESS_DETACH) {
theArxDLL.DetachInstance();
}
return 1; // ok
}
Lớp thứ hai là CAcModuleResourceOverride, là một lớp hữu ích. Nó tiến hành chuyển đổi từ tài nguyên của AutoCAD thành tài nguyên của ứng dụng khi nó được khởi tạo. Sau đó, khi bị hủy bỏ, nó chuyển đổi trở lại AutoCAD. Để sử dụng nó, chỉ cần khai báo một đối tượng của nó trước khi sử dụng tài nguyên riêng của bạn. Khi hoàn thành nghiệm vụ, nó sẽ bị hủy bỏ và và hàm hủy sẽ chuyển đổi trở lại. Cách thực hiện như sau:
CAcModuleResourceOverride res;
CMyDialo dlg;
dlg.DoModal();
Bằng cách này, bạn sẽ tạo thành công hộp thoại và không đối mặt với những lỗi lạ như "An unsupported operation was attempted". Một lỗi khác có thể xảy ravowis hộp thoại xuất hiện thay cho hộp thoại của bạn! Điên rồ không? Hãy nhớ nó áp dụng được cho bất kể tài nguyên nào bao gồm cả những chuỗi ký tự đặt bên trong của bảng chuỗi.

Sử dụng hỗ trợ MFC dựng sẵn (Built-in)

AutoDesk còn cung cấp một vài lớp tuyệt vời để làm ứng dụng của chúng ta nhìn giống như một tính năng nguyên bản của AutoCAD và làm việc hài hòa hơn với giao diện của AutoCAD. Có hai bộ sưu tập của lớp MFC dựng sẵn được nhóm bởi tiền tố AcUiAdUi. Lớp tiền tố AcUi được tạo ra để làm việc bên trong môi trường AutoCAD và lớp AdUi tạo ra để làm việc bên ngoài AutoCAD, nhưng do thỏa thuận cấp bản quyền, chỉ có thể sử dụng trong các ứng dụng tương tác với AutoCAD mà thôi.

Mỗi một lớp lại cho phép bạn tạo các nút button giống nhau mà ta vẫn nhìn thấy trong các hộp thoại nguyên bản của AutoCAD, cho phép chúng ta tạo ra những điều khiển thông minh để làm việc với góc đo, điểm, text, ... Còn có cả những hộp combo cho phép chúng ta tạo ra Lớp Layer như combo, combo đường nét, combo màu sắc ...
Các lớp này cung cấp cho ứng dụng một giao diện chuyên nghiệp nhất có thể. Và rất nhiều đặc tính nâng cao khác như xâm nhập vào trong hộp thoại tùy chọn của AutoCAD, tạo ra tab, tạo hộp thoại đính, và rất nhiều cái khác nữa.

Tìm hiểu thêm tài liệu ObjectARX để có cái nhìn đầy đủ về các lớp này.
Link nguồn: Arxdummies

Featured Post

Khóa học AutoLISP cơ bản | Tự học lập trình | AutoLISP that la don gian

Khóa học được cung cấp bởi  Thanh Trí AutoCAD       Thông tin thêm: 👉👉👉

Popular Posts