(Post 15/10/2010) Trong phương
pháp lập trình hướng đối tượng, một chương trình giải quyết vấn đề
nào đó là 1 tập hợp gồm nhiều đối tượng độc lập nhưng khi cần thì chúng
tương tác lẫn nhau để cùng hoàn thành chức năng của ứng dụng. Mỗi đối
tượng của phần mềm không nhất thiết là của riêng phần mềm đó, nó có thể
được dùng chung bởi nhiều phần mềm khác nhau...
Việc xây dựng đối tượng có thể độc lập với việc xây dựng
ứng dụng, ứng dụng có thể dùng lại những đối tượng đã có sẵn. Nhiều năm
về trước, Microsoft đã giới thiệu 2 loại đối tượng được quản lý ở cấp
hệ thống để các ứng dụng dùng chúng dễ dàng nhất, đó là đối tượng dạng
COM (Component Object Model) và đối tượng dạng ActiveX Control.
ActiveX Control là đối tượng có giao diện giống như Button,
TextBox, ListBox,... nhưng chưa có sẵn trong môi trường lập trình, chúng
được người lập trình tạo thêm, nhưng việc dùng chúng thì y như việc dùng
các điều khiển sẵn có của môi trường lập trình như Button, TextBox, ListBox,...
Sau đây chúng tôi xin giới thiệu qui trình điển hình
để xây dựng 1 ActiveX đơn giản và xây dựng 1 ứng dụng sử dụng nó bằng
môi trường lập trình VC++.
ActiveX mà chúng tôi muốn xây dựng là dàn đèn điều khiển
giao lộ gồm có 3 đèn xanh, vàng, đỏ. Nó có các nhóm chân giao tiếp với
thế giới bền ngoài như sau:
- Nhóm chân thuộc tính: có 1 chân 'Color' miêu tả trạng thái màu hiện
hành.
- Nhóm chân tác vụ: có 1 chân 'Next()' cho phép dàn đèn chuyển trạng
thái màu theo thứ tự xanh à vàng à đỏ à xanh...
- Nhóm chân sự kiện nhập có 2 chân 'LButtonDown' và 'Change' để xử lý
sự kiện ấn chuột trên dàn đèn và xử lý việc container thay đổi trạng
thái.
- Nhóm chân sự kiện xuất: có 5 chân 'Go', 'Stop', 'Caution', 'Off',
'Testing' được kích hoạt tương ứng với 5 trạng thái dàn đèn theo thời
gian là xanh, đỏ, vàng, tắt nghỉ, sáng cả 3 đèn để kiểm tra.
- Nhóm chân cung cấp nguồn: có 1 form 'Properties Page' cho phép người
dùng có thể thiết lập trạng thái dàn đèn dễ dàng tại thời điểm thiết
kế.
Ứng dụng mà chúng tôi muốn xây dựng là 1 form giao diện
demo việc điều khiển luồng giao thông ở 1 ngã tư một cách tự động theo
các tham số timer định sẵn.
I. Qui trình xây dựng ActiveX dàn đèn điển hình
gồm 17 bước như sau:
1. Chạy Visual C++ 6.0 (thí dụ chọn
mục Start.Programs.Microsoft Visual Studio 6.0.Microsoft Visual C++ 6.0)
2. Chọn menu File.New để hiển thị cửa
sổ New. Chọn tab "Project", chọn mục MFC ActiveX ControlWizard,
chọn thư mục chứa Project ở mục "Location", nhập tên project
vào textbox "Project name" (thí dụ nhập tên MyStopLite) rồi
chọn button Ok để bắt đầu các bước khai báo thông số cho Project.
3. Ở cửa sổ Step 1, bạn để các tham
số mặc định, chỉ chọn button Finish để hoàn thành qui trình Wizard tạo
Project.
4. Chọn menu View.Classwizard, cửa sổ
MFC ClassWizard sẽ hiển thị, cửa sổ này sẽ giúp bạn đặc tả các nhóm chân
giao tiếp của ActiveX.
5. Định nghĩa các chân thuộc tính: chọn
tab "Automation", chọn button "Add property" để hiển
thị cửa sổ "Add property". Bạn nhập tên "Color" vào
combobox "External Name", chọn kiểu short trong listbox "Type",
đánh dấu chọn checkbox "Get/Set methods" rồi chọn button Ok
để hoàn thành đặc tả thuộc tính Color của ActiveX. Nếu ActiveX cần xây
dựng có nhiều thuộc tính, bạn sẽ lập lại bước 5 nhiều lần.
6. Định nghĩa các chân tác vụ: chọn
tab "Automation", chọn button "Add Method" để hiển
thị cửa sổ "Add Method". Bạn nhập tên "Next" vào combobox
"External Name", chọn kiểu trả về "void" trong listbox
"Return type", rồi chọn button Ok để hoàn thành đặc tả tác vụ
Next() của ActiveX. Nếu ActiveX cần xây dựng có nhiều tác vụ, bạn sẽ lập
lại bước 6 nhiều lần.
7. Định nghĩa các chân events xuất ra
: chọn tab "ActiveX Events", chọn button "Add Event"
để hiển thị cửa sổ "Add event". Bạn nhập tên "Go"
vào combobox "External Name", rồi chọn button Ok để hoàn thành
đặc tả event "Go" của ActiveX. Lặp lại bước 7 nhiều lần để định
nghĩa các sự kiện xuất ra như Stop, Caution, Off, Testing.
8. Định nghĩa hàm xử lý sự kiện cho
1 số sự kiện nhập mà ActiveX quan tâm: chọn tab "Message Maps",
duyệt tìm và chọn mục WM_LBUTTONDOWN trong danh sách "Messages"
rồi chọn button "Add Function" để tạo hàm xử lý sự kiện ấn chuột
trái trên ActiveX. Tương tự, duyệt tìm và chọn mục "OnAmbientPropertyChange"
rồi chọn button "Add Function" để tạo hàm xử lý sự kiện Container
thay đổi.
9. Chọn tác vụ OnDraw trong listbox
"Member functions" rồi chọn button "Edit Code" để
hiển thị cửa sổ soạn code cho ActiveX. Viết code cho các tác vụ và các
hàm xử lý sự kiện vừa tạo như sau:
//Hiệu chỉnh lại hàm OnDraw
của Activex Control để vẽ nó theo yêu cầu.
void CMyStopLiteCtrl::OnDraw (CDC* pdc, const CRect& rcBounds, const
CRect& rcInvalid) {
//1. xóa background của ActiveX Control dùng màu background của container.
CBrush brAmbientBack(TranslateColor(AmbientBackColor()));
pdc->FillRect(rcBounds, &brAmbientBack);
//2. vẽ mép ActiveX Control
dùng thuộc tính stock của control : BackColor + ForeColor
// tính kích thước khoảng 40% độ cao
CRect rcBezel(rcBounds);
int nHeight = rcBounds.Height();
int nWidth = rcBounds.Width();
if (nHeight >= nWidth) {
int nBezelWidth = nHeight * 40 / 100;
if (nBezelWidth > nWidth)
nBezelWidth = nWidth; // not more then width!
int nDeflateBezel = (nWidth - nBezelWidth) / 2;
rcBezel.DeflateRect(nDeflateBezel, 0);
} else {
int nBezelHeight = nWidth * 40 / 100;
if (nBezelHeight > nHeight)
nBezelHeight = nHeight; // not more then width!
int nDeflateBezel = (nHeight - nBezelHeight) / 2;
rcBezel.DeflateRect(0,nDeflateBezel);
}
//tạo và chọn đối tượng brush, pen
CBrush brBack(TranslateColor(GetBackColor()));
CBrush * pbrOld = pdc->SelectObject(&brBack);
CPen pnFore(PS_SOLID, 2, TranslateColor(GetForeColor()));
CPen * ppnOld = pdc->SelectObject(&pnFore);
//vẽ đường viền cho ActiveX
pdc->Rectangle(rcBezel);
// select old brush, but not old pen
pdc->SelectObject(pbrOld);
//3. vẽ 3 đèn dùng thuộc tính
stock ForeColor.
int nLights = TranslateLights();
if (nHeight >= nWidth) { //hiển thị đèn từ trên xuống
//vẽ đèn đỏ ở trên
DrawLight(pdc, rcBounds, 6, 27,
(nLights & SLBIT_RED) ? SLCOLOR_RED : SLCOLOR_OFF);
//vẽ đèn vàng ở giữa
DrawLight(pdc, rcBounds, 37, 27,
(nLights & SLBIT_YELLOW) ? SLCOLOR_YELLOW : SLCOLOR_OFF);
//vẽ đèn xanh ở dưới
DrawLight(pdc, rcBounds, 68, 27,
(nLights & SLBIT_GREEN) ? SLCOLOR_GREEN : SLCOLOR_OFF);
} else { //hiển thị đèn từ trái sang phải
//vẽ đèn đỏ ở bên trái
DrawLight(pdc, rcBounds, 6, 27,
(nLights & SLBIT_RED) ? SLCOLOR_RED : SLCOLOR_OFF);
//vẽ đèn vàng ở giữa
DrawLight(pdc, rcBounds, 37, 27,
(nLights & SLBIT_YELLOW) ? SLCOLOR_YELLOW : SLCOLOR_OFF);
//vẽ đèn xanh ở bên phải
DrawLight(pdc, rcBounds, 68, 27,
(nLights & SLBIT_GREEN) ? SLCOLOR_GREEN : SLCOLOR_OFF);
}
pdc->SelectObject(ppnOld);
}
//hàm tạo sự kiện xuất khi
dàn đèn đổi màu
void CMyStopLiteCtrl::FireRightEvent() {
switch (m_color) {
case SL_RED: FireStop();
break;
case SL_YELLOW: FireCaution();
break;
case SL_GREEN: FireGo();
break;
case SL_NONE: FireOff();
break;
case SL_TEST: FireTesting();
break;
}
}
//hàm thiết lập trạng thái
tắt/sáng của 3 đèn
int CMyStopLiteCtrl::TranslateLights() {
int nLights = SLBIT_RED; //trị mặc định
switch (m_color) {
case SL_NONE: nLights = 0;
break;
case SL_RED: nLights = SLBIT_RED;
break;
case SL_GREEN: nLights = SLBIT_GREEN;
break;
case SL_YELLOW: nLights = SLBIT_YELLOW;
break;
case SL_TEST: nLights = SLBIT_RED | SLBIT_YELLOW | SLBIT_GREEN;
break;
}
return nLights;
}
//hàm vẽ đèn theo trạng thái
tắt/sáng của nó
void CMyStopLiteCtrl::DrawLight (
CDC* pdc, // DC được dùng để vẽ
const CRect& rcBounds, //vùng chữ nhật vẽ
int nPercentDown, //vị trí trên
int nPercentDiameter, // bán kính
COLORREF crColor //màu
) {
//tính bán kính theo đơn vị vẽ
int nHeight = rcBounds.Height();
int nWidth = rcBounds.Width();
if (nWidth
int nDiameter = nHeight * nPercentDiameter / 100;
if (nDiameter > nWidth)
nDiameter = nWidth; //bán kính phải <= độ rộng ActiveX
//tạo vùng chữ nhật bao quanh đèn
int nLeftEdge = (rcBounds.left + rcBounds.right - nDiameter) / 2;
int nTopEdge = rcBounds.top + nHeight * nPercentDown / 100;
CRect rcLight(nLeftEdge, nTopEdge,nLeftEdge + nDiameter,nTopEdge + nDiameter);
rcLight.IntersectRect(rcLight, rcBounds);
//tạo brush, draw, chọn brush cũ
CBrush brColor(crColor);
CBrush * brOld = pdc->SelectObject(&brColor);
pdc->Ellipse(rcLight);
pdc->SelectObject(brOld);
} else { //hiển thị dàn đèn ngang
int nDiameter = nWidth * nPercentDiameter / 100;
if (nDiameter > nHeight)
nDiameter = nHeight; //bán kính phải <= độ cao ActiveX
//tạo vùng chữ nhật bao quanh đèn
int nTopEdge = (rcBounds.top + rcBounds.bottom - nDiameter) / 2;
int nLeftEdge = rcBounds.left + nWidth * nPercentDown / 100;
CRect rcLight( nLeftEdge,nTopEdge, nLeftEdge + nDiameter, nTopEdge + nDiameter);
rcLight.IntersectRect(rcLight, rcBounds);
//tạo brush, draw, chọn brush cũ
CBrush brColor(crColor);
CBrush * brOld = pdc->SelectObject(&brColor);
pdc->Ellipse(rcLight);
pdc->SelectObject(brOld);
}
}
//hàm xử lý ấn chuột trái
void CMyStopLiteCtrl::OnLButtonDown(UINT nFlags, CPoint point) {
Next();
COleControl::OnLButtonDown(nFlags, point);
}
//tác vụ đọc thuộc tính Color
short CMyStopLiteCtrl::GetColor() {
return m_color;
}
//tác vụ hiệu chỉnh thuộc tính
Color
void CMyStopLiteCtrl::SetColor(short nNewValue) {
if (nNewValue >= SL_NONE && nNewValue <= SL_TEST) {
m_color = nNewValue;
InvalidateControl();
FireRightEvent();
SetModifiedFlag();
} else {
ThrowError(CTL_E_ILLEGALFUNCTIONCALL, "Color parameter out of range");
}
}
//tác vụ chuyển trạng thái
đèn
void CMyStopLiteCtrl::Next() {
if (m_color >= SL_LAST || m_color < SL_FIRST) {
m_color = SL_FIRST;
} else m_color++;
InvalidateControl();
FireRightEvent();
SetModifiedFlag();
}
//hàm xử lý sự kiện thay đổi
của Container
void CMyStopLiteCtrl::OnAmbientPropertyChange(DISPID dispid) {
//vẽ lại ActiveX nếu container thay đổi màu nền
if (dispid == DISPID_AMBIENT_BACKCOLOR || dispid == DISPID_UNKNOWN){
InvalidateControl();
}
//gọi class cha làm tiếp
COleControl::OnAmbientPropertyChange(dispid);
}
10. Dời lên đầu file MyStopLiteCtl.cpp,
viết đoạn lệnh định nghĩa các hằng gợi nhớ cần dùng sau đây:
//các giá trị của thuộc tính Color
enum { SL_NONE = 0,
SL_FIRST = 1, //đèn đầu trong chu kỳ chuyển màu
SL_RED = 1, SL_GREEN = 2, SL_YELLOW = 3, //thứ tự chuyển
SL_LAST = 3, //đèn cuối trong chu kỳ chuyển màu
SL_TEST = 4 };
//các bit qui định vẽ đèn nào
enum { SLBIT_RED = 1, SLBIT_GREEN = 2, SLBIT_YELLOW = 4};
//cáu màu RGB cần dùng cho các đèn
enum { SLCOLOR_OFF = RGB(63, 63, 63),
SLCOLOR_RED = RGB(255, 0, 0),
SLCOLOR_GREEN = RGB(0, 255, 0),
SLCOLOR_YELLOW = RGB(255, 255, 0) };
11. Mở file MyStopLiteCtl.h và viết
thêm đoạn lệnh khai báo các hàm viết thêm cho ActiveX như sau (vào nhóm
có tầm vực public):
public:
CMyStopLiteCtrl();
//các hàm viết thêm
void FireRightEvent();
int TranslateLights();
void CMyStopLiteCtrl::DrawLight(
CDC* pdc, // DC được dùng để vẽ
const CRect& rcBounds, //vùng chữ nhật vẽ
int nPercentDown, //vị trí trên
int nPercentDiameter, // bán kính
COLORREF crColor //màu
);
Khai báo biến miêu tả trạng thái màu của dàn đèn vào
nhóm có tầm vực protected như sau:
protected:
~CMyStopLiteCtrl();
short m_color;
...
12. Chọn tab "ResourceView"
trong cửa sổ hiển thị cây Project, mở rộng mục Dialog, ấn kép chuột mục
IDD_PROPPAGE_MYSTOPLITE để hiển thị cửa sổ thiết kế trang thuộc tính của
ActiveX, xóa label có sẵn trong form này, tạo Frame "Hãy chọn tráng
thái đầu của dàn đèn :" như hình sau:
13. Vẽ 1 Radio button, ấn phải chuột
vào button vừa tạo và chọn mục Properties để hiển thị cửa sổ thuộc tính
của nó. Đặt ID = IDC_OFF, Caption = Off, đánh dấu chọn vào 2 check box
"Group" và "Tab Stop".
14. Lập lại bước 13 để vẽ tuần tự 4
radio button với các thuộc tính như sau:
ID = IDC_RED, Caption = Red,
đánh dấu chọn vào check box "Tab Stop"
ID = IDC_GREEN, Caption = Green, đánh dấu chọn vào check box "Tab
Stop"
ID = IDC_YELLOW, Caption = Yellow, đánh dấu chọn vào check box "Tab
Stop"
ID = IDC_TESTING, Caption = Testing, đánh dấu chọn vào check box "Tab
Stop"
15. Chọn menu View.ClassWizard để hiển
thị cửa sổ ClassWizard. Chọn class "MyStopLitePropPage" ở listbox
"Class name". Chọn tab "Member Variables", chọn mục
IDC_OFF trong listbox "Control ID", chọn button "Add variable"
để hiển thị cửa sổ "Add member variable", nhập tên m_color vào
textbox "Member Variable name", nhập tên Color vào comboBox
"Optional property name" rồi ấn button Ok để hoàn tất việc định
nghĩa biến kết hợp với radion button Off.
16. Dịch ActiveX: chọn menu Build.Rebuild
all để dịch và tạo ActiveX Control, nếu có lỗi về từ vựng hay cú pháp
thì sửa cho đến khi hết lỗi.
17. Kiểm thử ActiveX: chọn menu Tools.ActiveX
Control Test Container để kiểm thử các chức năng của ActiveX Control có
đúng kỳ vọng không. Bạn không cần thực hiện bước này nếu như đã viết đúng
các đoạn code được liệt kê ở trên.
18. Sau khi dịch thành công, ActiveX
đã được đăng ký tự động vào Windows quản lý và có thể được dùng bởi bất
kỳ chương trình nào trên máy bạn. Để dùng ActiveX này trên máy khác, bạn
phải copy file MyStopLite.ocx vào vị trí nào đó trên máy cần cài đặt rồi
ra lệnh đăng ký vào Windows thông qua hàng lệnh sau (chọn Start.Run và
nhập vào):
regsvr32 <đường dẫn file
MyStopLite.ocx>
II. Qui trình xây dựng ứng
dụng thử dùng ActiveX gồm các bước như sau:
1. Chạy Visual C++ 6.0 (thí dụ chọn
mục Start.Programs.Microsoft Visual Studio 6.0.Microsoft Visual C++ 6.0).
2. Chọn menu File.New để hiển thị cửa
sổ New. Chọn tab "Project", chọn mục MFC AppWizard (exe), chọn
thư mục chứa Project ở mục "Location", nhập tên project vào
textbox "Project name" (thí dụ nhập tên MyApp) rồi chọn button
Ok để bắt đầu các bước khai báo thông số cho Project.
3. Ở cửa sổ Step 1, bạn chọn checkbox
"Dialog based", rồi chọn button Finish để hoàn thành qui trình
Wizard tạo Project.
4. Khi Form ban đầu của ứng dụng hiển
thị, bạn xóa tất cả các đối tượng có sẵn trong Form (gồm 2 button và 1
label).
5. Chọn menu Project.Add to Project.Components
and Controls để hiển thị cửa sổ "Components and Controls Gallery",
mở rộng mục "Registered ActiveX Controls", duyệt tìm và chọn
mục "MyStopLite Control", chọn button Insert để "add"
ActiveX này vào cửa sổ Toolbox của Project ứng dụng.
6. Thiết kế Form gồm 4 đèn ở 1 ngả tư
và 4 textbox kèm theo như sau:
7. Nhấn phải chuột vào đèn trên trái,
chọn mục Properties trong menu để hiển thị cửa sổ thuộc tính của nó, đặt
ID = IDC_SL1 rồi đóng cửa sổ Proterties lại. Ấn phải chuột vào Label kết
hợp với đèn trên trái, chọn mục Properties trong menu để hiển thị cửa
sổ thuộc tính của nó, đặt ID = IDC_L1 rồi đóng cửa sổ Proterties lại.
8. Lập lại bước 7 cho 3 đèn còn lại
theo chiều kim đồng hồ với ID lần lượt là IDC_SL2, IDC_SL3, IDC_SL4. ID
cho các Label kết hợp với chúng lần lượt là IDC_L2, IDC_L3, IDC_L4.
9. Chọn menu View.ClassWizard để hiển
thị cửa sổ "MFC ClassWizard" như sau:
10. Chọn mục CMyAppDlg ở listbox "ClassName",
chọn tab "Member Variables", chọn mục IDC_L1 trong listbox "Object
IDs", chọn button "Add Variable" để tạo biến kết hợp với
Label tương ứng, đặt tên biến là m_l1, Category là Value, Type là CString.
Tương tự, đặt tên biến cho 3 label còn lại là m_l2, m_l3, m_l4. Chọn mục
IDC_SL1 trong listbox "Object IDs", chọn button "Add Variable"
để tạo biến kết hợp với đèn tương ứng, đặt tên biến là m_sl1, Category
là Control, Type là CMyStopLite. Tương tự, đặt tên biến cho 3 đèn còn
lại là m_sl2, m_sl3, m_sl4.
11. Chọn mục CMyAppDlg ở listbox "ClassName",
chọn tab "Message Maps", duyệt tìm và chọn mục IDC_SL1 trong
listbox "Object IDs", chọn mục "Go" trong listbox
"Message", chọn button "Add function" để tạo hàm xử
lý sự kiện Go của đèn tương ứng (tên hàm mặc định này có tên là OnGoSl1).
Tiếp tục tạo các hàm xử lý sự kiện Stop và Caution của đèn IDC_SL1. Tương
tự, tạo 3 hàm xử lý sự kiện Go, Stop, Caution của đèn IDC_SL2.
12. Chọn button "Edit Code"
trong cửa sổ "MFC ClassWizard" để hiển thị cửa sổ soạn code
cho các hàm xử lý vừa tạo ra và viết code cho chúng như sau:
void CMyAppDlg::OnGoSl1() {
// TODO: Add your control notification
handler code here
UpdateData(TRUE);
m_l1 = m_l3 = "Den xanh. Bat dau chay.";
UpdateData(FALSE);
}
void CMyAppDlg::OnStopSl1()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_l1 = m_l3 = "Den do. Hay dung lai.";
UpdateData(FALSE);
}
void CMyAppDlg::OnCautionSl1()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_l1 = m_l3 = "Den vang. Chuan bi dung lai.";
UpdateData(FALSE);
}
void CMyAppDlg::OnGoSl2() {
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_l2 = m_l4 = "Den xanh. Bat dau chay.";
UpdateData(FALSE);
}
void CMyAppDlg::OnStopSl2()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_l2 = m_l4 = "Den do. Hay dung lai.";
UpdateData(FALSE);
}
void CMyAppDlg::OnCautionSl2()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_l2 = m_l4 = "Den vang. Chuan bi dung lai.";
UpdateData(FALSE);
}
13. Tìm đoạn code của hàm OnInitDialog(),
viết thêm đoạn code sau đây vào cuối hàm:
// TODO: Add extra initialization
here
m_status = 0;
OnNext();
return TRUE; //return TRUE unless you set the focus to a control
14. Dời chuột về trước hàm OnInitDialog()
và viết thêm các hàm dịch vụ sau đây :
//khai báo các hằng cần dùng
#define C_OFF 0
#define C_RED 1
#define C_GREEN 2
#define C_YELLOW 3
#define C_TEST 4
//khai báo các biến cần dùng
int deltat[4] = {5000,1000,7000,1000};
int m_idTimer;
short m_status;
//hàm chuyển trạng thái giao lộ
void CMyAppDlg::OnNext() {
// TODO: Add your control notification handler code here
m_status = (m_status+1)%4;
switch(m_status) {
case 0 : //đèn 1,3 xanh + đèn 2,4 đỏ
m_sl1.SetColor(C_GREEN);
m_sl3.SetColor(C_GREEN);
m_sl2.SetColor(C_RED);
m_sl4.SetColor(C_RED);
break;
case 1 : //đèn 1,3 vàng + đèn 2,4 chưa thay đổi
m_sl1.SetColor(C_YELLOW);
m_sl3.SetColor(C_YELLOW);
break;
case 2 : //đèn 1,3 đỏ + đèn 2,4 xanh
m_sl1.SetColor(C_RED);
m_sl3.SetColor(C_RED);
m_sl2.SetColor(C_GREEN);
m_sl4.SetColor(C_GREEN);
break;
case 3 : //đèn 1,3 chưa thay đổi + đèn 2,4 vàng
m_sl2.SetColor(C_YELLOW);
m_sl4.SetColor(C_YELLOW);
break;
}
//thiết lập timer đếm thời gian
m_idTimer = SetTimer(50, deltat[m_status],(TIMERPROC)NULL);
}
15. Tìm đoạn code của hàm OnPaint(),
hiệu chỉnh nội dung hàm như sau:
void CMyAppDlg::OnPaint() {
if (IsIconic()) {
//giữ nguyên nhánh này
} else { //viết lại nhánh sau đây
//khai báo các hằng tọa độ 2 điểm trên trái và dưới phải của ngã tư
//sẽ thay đổi theo tọa độ ngã tư trong Form thiết kế
const XLeft = 207;
const YTop = 133;
const XRight = 270;
const YBottom = 195;
//xác định DC của Form
CPaintDC dc(this);
CRect rect;
//xác định vùng chữ nhật của Form
GetClientRect(&rect);
//tạo bút vẽ
CBrush brColor(0x00ffffff);
CBrush * brOld = dc.SelectObject(&brColor);
//vẽ ngã tư
dc.MoveTo(10,YTop);
dc.LineTo(XLeft,YTop);
dc.LineTo(XLeft,10);
dc.MoveTo(XRight,10);
dc.LineTo(XRight,YTop);
dc.LineTo(rect.Width()-10,YTop);
dc.MoveTo(10,YBottom);
dc.LineTo(XLeft,YBottom);
dc.LineTo(XLeft,rect.Height()-10);
dc.MoveTo(XRight,rect.Height()-10);
dc.LineTo(XRight,YBottom);
dc.LineTo(rect.Width()-10,YBottom);
dc.SelectObject(brOld);
CDialog::OnPaint();
}
}
16. Mở file CMyAppDlg.h và thêm lệnh
khai báo hàm Next vào nhóm public của class như sau:
class CMyAppDlg: public CDialog
{
// Construction
public:
CMyAppDlg(CWnd* pParent = NULL); // standard constructor
void OnNext();
//giữ nguyên phần còn lại của class
17. Chọn menu Build.ReBuild All để dịch
chương trình, nếu có lỗi thì sửa cho hết lỗi (hi vọng bạn nhập đúng các
đoạn lệnh trên để chương trình không bị lỗi!).
18. Chọn menu Build.Execute MyApp.exe
để chạy chương trình. Nếu không có gì trục trặc, chương trình sẽ hiển
thị ngã tư và 4 đèn báo hiệu. Các đèn này sẽ tự động cập nhật trạng thái
theo thời gian qui định trong biến deltat của chương trình.
Nguyễn Văn Hiệp
(theo PC World VN)
Tin liên quan:
|