Trang chủ

March 17, 2013

Bài 8: Tập lựa chọn (selection sets)

Xin chào,

Trong bài này chúng ta sẽ khám phá những cách tương tác đầu tiên với người dùng, cho phép ứng dụng của chúng ta lấy thông tin từ màn hình của người sử dụng. Nếu bạn đã biết sử dụng AutoLISP thì việc làm quen với những khái niệm sau đây sẽ đơn giản hơn rất nhiều.

Giới thiệu

Đây là một trong những cách quan trọng nhất để tương tác với người dùng vì nó cho phép lấy thông tin từ màn hình thông qua các thực thể được chọn. Thỉnh thoảng bạn sẽ để người dùng chọn lựa một vài thực thể, cũng có khi sẽ phải dùng đến bộ lọc.
Tập lựa chọn là một nhóm các thực thể đang được lựa chọn bởi người dùng hoặc bởi chính chương trình của bạn. Khái niệm quan trọng nhất cần phải biết tiếp theo là ads_name. Khi lựa chọn thực thể từ màn hình, AutoCAD sẽ trả về tên thông qua kiểu ads_name. Kiểu này chứa tên thực thể (chỉ tồn tại trong cùng một phiên làm việc) và có thể chuyển đổi thành mã định danh ObjectId thông qua hàm acdbGetObjectId().
Acad::ErrorStatus acdbGetObjectId  (AcDbObjectId& objId, const ads_name objName);
Hàm này nhận đầu vào là ads_name và  trả về mã AcDbObjectId. Hầu hết các hàm thao tác trên tập lựa chọn sẽ sử dụng ads_name như một thông số và trong trường hợp đó, bạn không phải chuyển đổi nó. Ads_name có lưu trữ được một hoặc nhiều thực thể. Nó tùy thuộc vào việc bạn hoặc người dùng thực hiện việc lựa chọn tập đối tượng.
Lựa chọn đươc tạo ra khi sử dụng hàm acedSSGet() áp dụng với lựa chọn hoặc nhắc người dùng làm việc đó. Khai báo của hàm là:
int acedSSGet (const ACHAR *str, const void *pt1, const void *pt2,
const struct resbuf *entmask, ads_name ss);

Sử dụng như thế nào?

Nó nhận một tham số lựa chọn str, hai điểm pt1 pt2, một bộ lọc entmask (nếu có) và trả về tập lựa chọn ss. Sau khi sử dụng tập lựa chọn, chúng ta cần phải giải phóng nó thông qua hàm acedSSFree().
Tham số lựa chọn chỉ cho AutoCAD cách thức thực hiện việc lựa chọn đối tượng như sau:

Mã lựa chọn
Mô tả
NULL
Single-point selection (if pt1 is specified)
or user selection (if pt1 is also NULL)
#
Nongeometric (all, last, previous)
:$
Prompts supplied
.
User pick
:?
Other callbacks
A
All
B
Box
C
Crossing
CP
Crossing Polygon
:D
Duplicates OK
:E
Everything in aperture
F
Fence
G
Groups
I
Implied
:K
Keyword callbacks
L
Last
M
Multiple
P
Previous
:S
Force single object selection only
W
Window
WP
Window Polygon
X
Extended search (search whole database)

Từ đây, ta có thể thực hiện lựa chọn bằng nhiều cách khác nhau. Dưới đây là một vài ví dụ:
ads_point pt1, pt2;
ads_name ssname;
pt1[X] = pt1[Y] = pt1[Z] = 0.0;
pt2[X] = pt2[Y] = 5.0; pt2[Z] = 0.0;
// Lấy tập hợp đang được lựa chọn PICKFIRST hoặc yêu cầu người dùng chọn.
acedSSGet(NULL, NULL, NULL, NULL, ssname);
// Lấy tập hợp đang được lựa chọn PICKFIRST
acedSSGet(_T("I"), NULL, NULL, NULL, ssname);
// Lặp lại lựa chọn gần nhất
acedSSGet(_T("P"), NULL, NULL, NULL, ssname);
// Lựa chọn thực thể cuối cùng được tạo ra
acedSSGet(_T("L"), NULL, NULL, NULL, ssname);
// Lựa chọn thực thể đi qua điểm (5,5)
acedSSGet(NULL, pt2, NULL, NULL, ssname);
// Lựa chọn thực thể nằm trong cửa sổ từ điểm (0,0) đến điểm (5,5)
acedSSGet(_T("W"), pt1, pt2, NULL, ssname);

Sử dụng bộ lọc lựa chọn

Bộ lọc là phương thức mạnh mẽ để tăng tốc chọn lựa đối tượng và tránh quá trình xác nhận thực thể. Bạn có thể sử dụng bộ lọc đơn hoặc bộ lọc phức hợp. Mỗi một bộ lọc được xác định thông qua cấu trúc gọi là resbuf. Mỗi resbuf là một danh sách liên kết có thể lưu giữ một vài kiểu thông tin và có thể chứa một số phần tử khác. Để sử dụng bộ lọc, chúng ta cần phải xây dựng nó và đưa nó vào tham số trong phương thức acedSSGet(). Lựa chọn được tiến hành nhưng mỗi thực thể lựa chọn sẽ cần phải đáp ứng bộ lọc. Chúng ta có thể tạo ra nhiều bộ lọc và tài liệu SDK có mọi thông tin về nó. Sau đây là những ví dụ thông dụng nhất:
struct resbuf eb1, eb2;
TCHAR sbuf1[10], sbuf2[10];
ads_name ssname1, ssname2;
eb1.restype = 0; // Bộ lọc tên của thực thể
_tcscpy(sbuf1, _T("CIRCLE"));
eb1.resval.rstring = sbuf1;
eb1.rbnext = NULL;
// Nhận lấy mọi hình tròn
acedSSGet(_T("X"), NULL, NULL, &eb1, ssname1);
eb2.restype = 8; // Bộ lọc tên lớp
_tcscpy(sbuf2, _T("0"));
eb2.resval.rstring = sbuf2;
eb2.rbnext = NULL;
// Nhận mọi đối tượng thuộc lớp 0
acedSSGet(_T("X"), NULL, NULL, &eb2, ssname2);

Chỉnh sửa thực thể thông qua tập lựa chọn

Để chỉnh sửa thực thể bên trong một tập lựa chọn, chúng ta cần phải xâm nhập từng phần tử, lấy từng cái một, chuyển đổi tên ads_name sang mã định danh ObjectId, mở thực thể để ghi, chỉnh sửa rồi đóng nó lại. Nếu là một quá trình dài, bạn có thể thực hiện việc đó thông qua giao dịch.
Để chỉ ra vệc xâm nhập vào vào tập lựa chọn, tôi sẽ trình bày một đoạn mã ngắn cho phép lựa chọn tất cả thực thể Hình tròn CIRCLE trong bản vẽ và chuyển màu sắc của nó sang màu đỏ. Quá trình rất đơn giản và được thực hiện như sau:

// Xây dựng bộ lọc
struct resbuf eb1;
TCHAR sbuf1[10];
eb1.restype = 0; // Tên thực thể
_tcscpy(sbuf1, _T("CIRCLE"));
eb1.resval.rstring = sbuf1;
eb1.rbnext = NULL;

// Lựa chọn tất cả hình tròn
ads_name ss;
if (acedSSGet(_T("X"), NULL, NULL, &eb1, ss) != RTNORM){
acutRelRb(&eb1);
return;
}

// Giải phóng resbuf
acutRelRb(&eb1);

// Lấy chiều dài của tập lựa chọn (Có bao nhiêu thực thể được lựa chọn)
long length = 0;
if ((acedSSLength( ss, &length ) != RTNORM) (length == 0)) {
acedSSFree( ss );
return;
}

ads_name ent;
AcDbObjectId id = AcDbObjectId::kNull;

// Duyệt qua từng thực thể trong tập lựa chọn và mở nó dưới dạng có thể Ghi
for (long i = 0; i < length; i++) {
if (acedSSName(ss,i,ent) != RTNORM) continue;
if (acdbGetObjectId(id,ent) != Acad::eOk) continue;
AcDbEntity* pEnt = NULL;
if (acdbOpenAcDbEntity(pEnt,id,AcDb::kForWrite) != Acad::eOk)
continue;
// Thay đổi màu sắc
pEnt->setColorIndex(1);
pEnt->close();
}

// Giải phóng tập lựa chọn
acedSSFree( ss );


Tôi đã sử dụng một vài hàm mới (như acdbOpenAcDbEntity) nằm trong bộ SDK ObjectARX. Hãy chú ý giải phóng tập lựa chọn và resbuf. Nhớ rằng tôi đã sử dụng acedSSLength() để lấy được độ dài của tập lựa chọn.
Hàm acedSSName() sẽ trả về phần tử thứ index của lựa chọn. Nếu có nhiều hơn một thưucj thể được chọn, vòng lặp sẽ lấy mọi thực trong tập lựa chọn

Hẹn gặp lại bạn trong bài tiếp theo.

Link nguồn: Arxdummies

No comments:

Post a Comment