Tải bản đầy đủ (.pdf) (112 trang)

Giáo trình Nhập môn hệ quản trị cơ sở dữ liệu: Phần 2

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.42 MB, 112 trang )

CHƢƠNG 7: LẬP TRÌNH CƠ SỞ DỮ LIỆU TRONG MS ACCESS
1. Giới thiệu lập trình Visual Basic Application
MS Access không chỉ đơn thuần là một hệ quản trị cơ sở dữ liệu (CSDL) quan hệ mà
nó còn cung cấp một môi trƣờng lập trình với các công cụ khá đầy đủ, dễ sử dụng để
phát triển các ứng dụng quản lý vừa và nhỏ.
Ngôn ngữ lập trình đƣợc phát triển trong MS Access là Access Basic. Tuy nhiên từ
phiên bản MS Access for Windows 95, Access Basic đƣợc thay thế bởi Visual Basic
(VB). Hai ngôn ngữ này khá giống nhau và đều đƣợc phát triển từ một thành phần
thiết kế chung. Nhƣng ngày nay, VB trở thành ngôn ngữ lập trình chung của chƣơng
trình ứng dụng MS Office bao gồm: Access, Excel, Word, PowerPoint và đƣợc gọi là
VBA (Visual Basic for Applications). Việc có đƣợc một ngôn ngữ lập trình chung
xuyên suốt mọi chƣơng trình ứng mang lại một số lợi điểm quan trọng là:
 Ngƣời lập trình chỉ cần biết một ngôn ngữ lập trình để tùy biến, phát triển
ứng dụng.
 Dễ dàng hợp nhất các đối tƣợng trong các chƣơng trình ứng dụng.
VBA là ngôn ngữ có một số đặc điểm:
 Không phân biệt chữ hoa, thƣờng
 Hƣớng sự kiện và hƣớng đối tƣợng
Việc tổ chức chƣơng trình theo mô hình hƣớng đối tƣợng và hƣớng sự kiện khiến cho
các mã lệnh của chƣơng trình, suy cho đến cùng nhất, chỉ đƣợc gọi khi có sự kiện
(event) nào đó xảy ra trên các đối tƣợng (object) cụ thể. Sự kiện của các đối tƣợng
đƣợc sinh ra có thể do ngƣời dùng tác động chuột/bàn phím vào điều khiển. Ví dụ sự
kiện OnClick() của điều khiển Button trên form. Sự kiện cũng có thể đƣợc sinh ra
trong quá trình biên dịch. Ví dụ sự kiện Load() của một form. Tuy nhiên, không phải
bất kỳ đối tƣợng nào cũng có các sự kiện. Các đối tƣợng là các điều khiển (control)
đƣơng nhiên có các sự kiện. Ví dụ TextBox, CommandButton, Form, … đều có các sự
kiện; trong khi đó đối tƣợng DBEngine lại không thể có sự kiện nào.
Nhƣ vậy, toàn bộ mã lệnh của chƣơng trình ứng dụng Access đƣợc tổ chức là các
hàm/thủ tục (function/sub) độc lập, bình đẳng (chúng ta sẽ phân biệt hàm và thủ tục
trong phần sau). Không có hàm/thủ tục nào là cha, chứa các hàm/thủ tục khác. Không
có “điểm vào” của chƣơng trình. Nghĩa là, không có hàm/thủ nào đƣợc chƣơng trình


gọi trƣớc nhất để từ đó gọi đến các hàm/thủ tục khác. Tất cả các hàm/thủ tục chỉ đƣợc
gọi để đáp ứng các sự kiện tƣơng ứng hoặc đƣợc gọi tƣờng minh trong hàm/thủ tục
khác.
131


Chƣơng này sẽ trình bày các nội dung sau:
 Module và Access Class Object
 Các kiểu dữ liệu, hằng và biến
 Các cấu trúc điều khiển
 Hàm và thủ tục
 Các mô hình truy cập CSDL

2. Module
Module là một đối tƣợng nguyên thủy của môi trƣờng lập trình VBA. Toàn bộ mã
lệnh VBA trong CSDL đƣợc lƣu trong module dƣới dạng các thủ tục (gồm hàm và thủ
tục con). Các thủ tục này có thể độc lập hoặc liên quan đến form/report.
Nói cách khác, module là một phƣơng tiện của MS Access để giúp ngƣời lập trình tổ
chức mã nguồn của họ sao cho “gọn gàng”, dễ kiểm soát. Ví dụ, ngƣời lập trình nên
gom các đoạn mã (hàm/thủ tục) làm việc với CSDL vào một module đặt tên là
DataAccessModule, gom các đoạn mã là việc với form vào một module đặt tên là
FormModule hay nên viết ra một lớp Student (Class Module) để làm việc với các bản
ghi thuộc bảng Student trong CSDL, …
MS Access 2013 cung cấp 03 loại module: module chuẩn (Standard Module), module
lớp (Class Module) và module gắn với form/report (Form/Report Module)
Standard module chủ yếu bao gồm tập các hàm/thủ tục. Mỗi hàm/thủ tục này đƣợc gọi
từ các hàm/thủ tục khác hoặc từ sự kiện của đối tƣợng hay điều khiển. Khi đó, toàn bộ
mã lệnh của chƣơng trình đƣợc tổ chức thành các đơn vị hàm/thủ tục. Các đơn vị
hàm/thủ tục này đƣợc gom lại trong một hoặc một số Standard Module để giúp lập
trình viên dễ quản lý mã lệnh của mình hơn.

Class module thực chất là một lớp do ngƣời dùng định nghĩa. Mỗi Class Module là
một lớp của ngƣời dùng có tên chính là tên của Class Module. Lớp của ngƣời dùng
định nghĩa cũng đƣợc đối xử bình đẳng nhƣ các lớp đã đƣợc định nghĩa bởi hệ thống
(built-in language class).
Điều quan trọng ở đây là bạn phải biết khi nào dùng Standard Module và khi nào dùng
Class Module hay cả hai. Nó phụ thuộc vào cách thiết kế ứng dụng của bạn. Nếu ứng
dụng của bạn đƣợc tổ chức theo kiểu “hƣớng chức năng” (phần mềm là một tập các
chức năng có quan hệ với nhau) thì bạn sẽ có xu hƣớng sử dụng Standard Module
nhiều hơn. Nếu ứng dụng của bạn đƣợc thiết kế theo mô hình lập trình “phân lớp” (03
lớp chẳng hạn: giao diện, logic, truy cập dữ liệu) thì bạn sẽ đƣơng nhiên sẽ sử dụng
Class Module nhiều hơn.
Sau đây là chi tiết về các loại module.
132


2.1 Module chuẩn (Standard Module)
Module này chứa các biến, thủ tục con có thể đƣợc gọi từ query, form, report, macro,
biểu thức, thủ tục khác hoặc từ bất cứ đâu trong chƣơng trình ứng dụng.
Nhƣ vậy, ta có thể viết trong Standard Module các nội dung sau đây:


Các khai báo tùy chọn dùng chung cho tất cả các hàm/thủ tục trong Standard
Module. Ví dụ: Option Explicit là một khai báo tùy chọn yêu cầu tất cả các
biến sau này dùng trong các hàm/thủ tục phải đƣợc khai báo tƣờng minh trƣớc
khi dùng



Các khai báo hằng, biến toàn cục




Các hàm/thủ tục

Các hàm/thủ tục trong Standard Module với phạm vi truy xuất public (mặc định) có
thể đƣợc gọi từ bất kỳ đâu trong CSDL bao gồm các lời gọi từ:


Các hàm/thủ tục khác trong cùng Standard Module với nó



Các hàm/thủ tục trong các Class Module khác



Các thủ tục gắn với các form/report trong MS Access Class Objects

Các hàm/thủ tục có phạm vi truy xuất private chỉ đƣợc gọi trong các hàm/thủ tục khác
thuộc cùng module với nó.
Để tạo Standard Module, trong cửa sổ thiết kế CSDL, chọn lệnh CREATE trên thanh
menu, sau đó chọn nút lệnh Module (vùng khoanh đỏ) nhƣ trong hình 7.1

Hình 7.1: Tạo Standard Module từ cửa sổ thiết kế CSDL

133


Kết quả bạn nhận đƣợc là cửa sổ để viết code trong Standard Module nhƣ trong hình
7.2


Project
Explorer Panel

Code
panel

Hình 7.2 : Cửa sổ code của Standard Module
Trong hình 7.2, cửa sổ màn hình đƣợc chia làm 02 panel bao gồm : panel bên trái là
Project Explorer Panel để hiển thị các đối tƣợng module. Trong panel này, bạn có
thể thêm/bớt hoặc sửa tên (F4) Standard Module, …panel bên phải là Code Panel, đây
là cửa sổ để bạn viết mã cho mỗi Standard Module đƣợc chọn bên panel trái.
Chú ý : bạn có thể bật/tắt các panel này theo ý muốn để vùng quan sát của bạn đƣợc
rộng hơn. Ví dụ khi code bạn muốn cửa sổ code (Code Panel) đƣợc rộng bạn nên tắt
panel bên trái bằng cách click chuột vào biểu tƣợng dấu X ở góc trên bên phải nhất của
panel đó. Khi cần bạn có thể mở lại bằng cách chọn lệnh VIEW/Project Explore trên
thanh menu.
Khi muốn ghi lại code, bạn cần chọn lệnh File/Save …hoặc chọn biểu tƣợng save
(chiếc đĩa mềm) trên thanh menu. Lần đầu tiên lƣu, bạn sẽ đƣợc hỏi đặt tên cho
Standard Module, những lần sau, MS Access sẽ tự ghi vào tên bạn đã đặt từ lần đầu.
Hình 7.3 minh họa cửa sổ lƣu Module3 đƣợc đặt tên là commonFunction.

134


Nút lệnh save

Hình 7.3 Đặt tên cho Standard Module
Khi muốn sửa tên module đã đặt, bạn chọn vào tên module đó trong Project Explorer
Panel rồi ấn phím F4. Ví dụ hình 7.4 minh họa cửa sổ đổi tên cho module1 thành tên

mới là checkValidFunction

Bạn nhập tên mới cho
module ở thuộc tính
(Name)

Hình 7.4 Đổi tên cho Standard Module đã có
Chúng ta quan tâm nhiều đến Code Panel. Sau đây, chúng ta sẽ phân tích Panel này.
Phần trên cùng của Panel là hai hộp danh sách thả xuống. Hộp danh sách bên trái luôn
có một mục là (General), hộp danh sách bên phải là danh sách các hàm, thủ tục trong

135


Standard Module (trong hình 7.2 vì chƣa có hàm, thủ tục nào đƣợc viết trong Standard
Module nên chỉ có một mục (Declarations) đƣợc hiển thị).
Cửa sổ soạn thảo mã lệnh gồm 03 phần, phần khai báo các tùy chọn, khai báo các
hằng, biến dùng chung cho các hàm, thủ tục trong module và phần định nghĩa các
hàm, thủ tục trong Standard Module.

2.1.1 Khai báo các tùy chọn
Các tùy chọn nếu đƣợc khai báo có thể khai báo sau hằng, biến toàn cục nhƣng phải
trƣớc phần định nghĩa các hàm/thủ tục. Phần khai báo các tùy chọn ở đây có thể có các
tùy chọn sau đƣợc khai báo:
 Option Base Statement
Khai báo chỉ số thấp nhất cho mảng trong toàn module, mặc định là 0.
Cú pháp khai báo:
Option Base {0 | 1}

Ví dụ: Khi định nghĩa một mảng theo cú pháp

Dim a(100) as Integer

Mặc định ta sẽ đƣợc một mảng tên là a, các chỉ số chạy từ 0 đến 99.
Nếu có tùy chọn Option Base 1 thì mảng a sẽ có 100 phần tử, chỉ số chạy từ 1 đến
100.
Tùy chọn này (nếu có) phải đƣợc khai báo trƣớc bất kỳ hàm, thủ tục nào và nó chỉ có
tác dụng trong module chứa nó. Option Base chỉ đƣợc khai báo một lần trong một
module và phải trƣớc các khai báo mảng.
 Option Compare Statement
Khai báo phƣơng thức so sánh cho các biểu thức thuộc kiểu chuỗi (String).
Cú pháp khai báo:
Option Compare {Binary | Text | Database}

Option Compare Binary: so sánh chuỗi theo kiểu nhị phân, nghĩa là theo thứ tự sắp
xếp của các ký tự trong bảng mã ASCII. Đây là kiểu mặc định
Ví dụ: khi có khai báo Option Compare Binary thì ta sẽ có “A” < “B” < ”C” … <
“a” < “b” < “c”… vì mã ASCII của “A” và “a” tƣơng ứng là 65 và 97 (hệ thập phân)
Option Compare Text: so sánh theo kiểu trật tự của các ký tự không phân biệt chữ
hoa, thƣờng.
136


Ví dụ: Khi khai báo Option Compare Text thì "A" = "a", "B" = "b", …, "À" = "à",
"Ê" = "ê", …
Option Compare Database: so sánh xâu dựa trên trật tự đƣợc xác định cục bộ trong
Database chứa module đó.
 Option Explicit Statement
Khai báo để yêu cầu các biến phải đƣợc khai báo tƣờng minh trƣớc khi sử dụng. Tùy
chọn này (nếu có) phải đƣợc đặt trƣớc mọi khai báo biến và định nghĩa các hàm, thủ
tục con.

Cú pháp khai báo:
Option Explicit

Ví dụ 1:
[1] Option Explicit
[2] Dim a
[3] a = 100

Trong đoạn mã này:
+ dòng [1]: yêu cầu các biến phải đƣợc khai báo tƣờng minh trƣớc khi sử dụng
+ dòng [2] khai báo một biến a
+ dòng [3] gán cho a giá trị 100
Nhƣ vậy, cuối cùng biến a đƣợc nhận giá tri là 100
Ví dụ 2:
[1] Option Explicit
[2] a = 100

Trong đoạn mã này:
+ dòng [1]: yêu cầu các biến phải đƣợc khai báo tƣờng minh trƣớc khi sử dụng
+ dòng [2]: gán cho biến a giá trị 100 mà không có khai báo trƣớc
Đoạn mã này khi dịch trình biên dịch sẽ thông báo lỗi “Variable not defined”. Và do
đó cần khai báo biến a trƣớc khi gán giá trị cho nó (Dim a) hoặc ta bỏ khai báo Option
Explicit đi.
 Option Private Statement

137


Khai báo tùy chọn để cấm các truy xuất từ bên ngoài (các ứng dụng, dự án khác) vào
các thành phần của module.

Cú pháp khai báo:
Option Private Module

Chú ý: Tùy chọn này chỉ cấm các truy cập từ các dự án (có thể trong cùng ứng dụng),
ứng dụng khác tới các thành phần (hằng, biến, hàm, thủ tục, kiểu ngƣời dùng định
nghĩa) của module. Mọi truy xuất từ các module, query, form, … khác trong cùng cơ
sở dữ liệu là đƣợc.

2.1.2 Khai báo hằng, biến toàn cục
Hằng, biến toàn cục có phạm vi hoạt động trong toàn bộ module mà nó đƣợc khai báo
hoặc có thể rộng hơn (từ các module khác) tùy thuộc vào việc bạn quy định phạm vi
truy xuất cho nó là private hay public. Hằng, biến toàn cục có thể đƣợc khai báo trƣớc
hoặc sau các khai báo tùy chọn nhƣng bắt buộc phải khai báo trƣớc các hàm/thủ tục.
Mặc định hằng, biến toàn cục ở đây có phạm vi truy xuất là private. Tức là, bạn chỉ có
thể truy xuất đƣợc chúng từ các hàm, thủ tục trong cùng module với chúng. Bạn không
thể truy xuất đƣợc các hằng, biến này từ các module khác. Tuy nhiên, bạn sõ thể thiết
lập phạm vi truy xuất public cho chúng với khai báo từ khóa public trƣớc khai báo tên
hằng, biến
Chú ý: nên hạn chế việc sử dụng hằng/biến toàn cục
Cú pháp khai báo hằng, biến sẽ đƣợc trình bày chi tiết trong phần sau.

2.1.3. Hàm, thủ tục (function/sub)
Sau các khai báo tùy chọn và hằng, biến là phần định nghĩa các hàm/thủ tục của
module. Các hàm/thủ tục đƣợc ra nhƣ là một thƣ viện, việc gọi thi hành chúng phải là
tƣờng minh. Mặc định các hàm/thủ tục trong Standard Module có phạm vi truy xuất là
public. Chi tiết về hàm và thủ tục sẽ đƣợc trình bày trong phần sau.

2.1.4 Ví dụ
Sau đây chúng ta phân tích một Standard Module có tên là commonFunction với dụng
ý là module để lƣu các hàm cơ bản, dùng chung. Trong commonFunction chúng ta sẽ

định nghĩa một số hàm làm việc với mảng các số double. Mục dích của ví dụ là minh
họa các thành phần trong Standard Module
Chú ý: để viết các chú thích (comment) trong vùng viết code của MS Access ta sử
dụng dấu „ (dấu phẩy) trong dòng chú thích. Ví dụ: ‘ This is a comment. Khi gặp các
dòng bắt đầu bằng dấu „, trình biên dịch sẽ bỏ qua tất cả những gì sau dấu „ cho đến
khi gặp dòng tiếp theo.
‘Khai báo tùy chọn chỉ số bắt đầu của mảng từ 1 mặc định

138


‘là 0 và tùy chọn phải khai báo biến tường minh trước
‘khi dùng
Option Base 1
Option Explicit

‘Khai báo một biến mảng toàn cục dùng chung a
‘Khai báo một hằng n dụng ý là số phần tử của mảng
‘Phạm vi truy xuất mặc định của a, n là private

Dim a(100) As Double
Const n As Integer = 10

‘Định nghĩa các hàm/thủ tục

‘Thủ tục khởi tạo ngẫu nhiên các giá trị mảng a gồm
‘10 phần tử, các phần tử có giá trị <= 100
Sub InitArray()
Dim i As Integer
‘Khởi tạo bộ sinh số ngẫu nhiên từ 0 đến 1

‘sử dụng cho hàm rnd sau này
Randomize
For i = 1 To n
a(i) = Rnd * 100
Next
End Sub

‘Thủ tục in các giá trị của mảng a ra màn hình hộp thoại,
‘mỗi giá trị xuất hiện trong một lần hộp thoại xuất hiện,
‘click vào nút lệnh OK để hiển thị phần tử kế tiếp
Sub showArray()

139


Dim i
For i = 1 To n
MsgBox ("a[" & Str(i) & "] = " & Str(a(i)))
Next
End Sub

‘Thủ tục xếp các phần tử của mảng a theo thứ tự tăng dần
Sub sortArrayASC()
Dim i, j As Integer
For i = 1 To n - 1
For j = i + 1 To n
If (a(i) > a(j)) Then
Dim tg As Double
tg = a(i)
a(i) = a(j)

a(j) = tg
End If
Next
Next
End Sub

‘Hàm trả về giá trị True/False tương ứng khi
‘x thuộc mảng hoặc không
Function containInArray(x As Double)
Dim i As Integer
Dim kt As Boolean
kt = False
For i = 1 To n
If x = a(i) Then
kt = True

140


Exit For
Next
containInArray = kt
End Function

Bạn nên đọc kỹ các chú ý sau đây.
Trong đoạn mã trên:
+ Biến mảng a và hằng n không khai báo phạm vi truy xuất là public hay private, thì
mặc định là private. Điều này có nghĩa là, bạn không thể truy xuất đến a hay n từ bên
ngoài module commonFunction. Ví dụ sau đây minh họa với bạn điều đó. Bạn có thể
truy xuất a, n từ khắp nơi trong phạm vi module commonFunction nhƣ trong đoạn mã

trên nhƣng sang module checkValidFunction bạn không thể truy xuất chúng nữa.

Hình 7.5 Không nhìn thấy được a và n từ ngoài module commonFunction
Bạn có thể sửa cho a, n thành phạm vi public bằng cách khai báo nhƣ sau:
Public a(100) As Double
Public Const n As Integer = 10
Nhƣ hình 7.6 dƣới đây, bạn đang ở module checkvalidFunction, bạn hoàn toàn có thể
nhìn thấy (truy xuất) a và n trong module commonFunction vì bạn đã có khai báo
phạm vi truy xuất Public cho chúng theo cú pháp trên

141


Hình 7.6 Truy xuất a, n từ ngoài module chứa chúng
+ Các hàm, thủ tục có phạm vi truy xuất mặc định là Public. Do vậy, bạn có thể gọi
các hàm/thủ tục containInArray(), InitArray(), showArray(), sortArray() từ khắp nơi.
Bạn quan sát lại các hình 7.5 và 7.6. Tuy nhiên, bạn cũng có thể hạn chế phạm vi truy
xuất này chỉ trong nội module commonFunction bằng khai báo từ khóa Private trƣớc
tên hàm mà bạn muốn.
Ví dụ: Bạn khai báo cho 02 thủ tục InitArray() và showArray() có phạm vi truy xuất là
private nhƣ sau:
Private Sub InitArray()
Dim i As Integer
Randomize
For i = 1 To n
a(i) = Rnd * 100
Next
End Sub

Private Sub showArray()

Dim i
142


For i = 1 To n
MsgBox ("a[" & Str(i) & "] = " & Str(a(i)))
Next
End Sub
Khi đó, bạn không thể truy xuất đến thủ tục InitArray() và showArray() từ module
checkValidFunction nhƣ trong hình 7.7 dƣới đây. Tất nhiên, trong module
commonFunction bạn vẫn gọi đƣợc 2 thủ tục trên một cách bình thƣờng.

Hình 7.7: Không nhìn thấy InitArray() và showArray() từ module checkValidFunction
+ Để chạy thử các thủ tục trong đoạn mã trên, bạn có một vài cách, đơn giản nhất là
bạn hãy chọn (bôi đen) thủ tục đó và ấn phím F5 nhƣ trong hình 7.8 dƣới đây. Khi đó,
các mã lệnh trong phần đƣợc chọn sẽ đƣợc dịch và chạy. Bạn hãy quan sát kết quả
chạy chƣơng trình của đoạn mã vừa chọn.

143


Hình 7.8 Chạy thử thủ tục InitArray() và showArray()
+ Đối với hàm (function) thì bạn có cách khác: gọi từ các thủ tục hoặc bạn chạy thử từ
cửa sổ Immediate nhƣ trong hình 7.9 dƣới đây. Để hiển thị cửa sổ Immediate bạn chọn
lệnh View/Immediate Window từ trên thanh menu hoặc ấn tổ hợp phím Ctrl + G. Trong
cửa sổ Immediate bạn có thể quan sát đƣợc các giá trị của các biến (với điều kiện
phạm vi truy xuất public) hoặc giá trị của hàm bằng cú pháp: ? tên biến / tên hàm.
Trong hình 7.9, trƣớc tiên, thủ tục InitArray() đƣợc cho chạy và biến mảng a() có
phạm vi truy xuất public. Sau đó, ở cửa sổ Immediate, để xem giá trị của a(1) đƣợc
khởi tạo là bao nhiêu bạn cần viết: ?a(1) => kết quả a(1) = 22.3095118999481, để

xem
giá
trị
của
hàm
containInArray()
bạn
cần
viết:
?containInArray(22.3095118999481) => kết quả trả về của hàm là True. Nếu gọi
?containInArray(1) => kết quả trả về của hàm là False

144


Hình 7.9 Chạy thử hàm trong cửa sổ Immediate
Nhƣ đã trình bày, trong nhiều trƣờng hợp bạn không nên sử dụng biến, hằng toàn cục.
Do đó, ví dụ trên sẽ đƣợc viết lại không sử dụng biến toàn cục nhƣ sau:
Option Compare Database
Option Base 1
Option Explicit

Sub initArray(ByRef a() As Double, ByRef n As Integer)
Dim i As Integer
n = 10
Randomize
For i = 1 To n
a(i) = Rnd * 100
Next
End Sub


Sub showArray(a() As Double, n As Integer)

145


Dim i
For i = 1 To n
MsgBox ("a[" & Str(i) & "] = " & Str(a(i)))
Next
End Sub

Sub sortArrayASC(ByRef a() As Double, n As Integer)
Dim i, j As Integer
For i = 1 To n - 1
For j = i + 1 To n
If (a(i) > a(j)) Then
Dim tg As Double
tg = a(i)
a(i) = a(j)
a(j) = tg
End If
Next
Next
End Sub

Function containInArray(x As Double, a() As Double, n As Integer)
Dim i As Integer
Dim kt As Boolean
kt = False

For i = 1 To n
If x = a(i) Then
kt = True
Exit For
End If
Next
containInArray = kt

146


End Function

Sub callSub()
Dim a(100) As Double
Dim n As Integer
InitArray a, n
showArray a, n
End Sub

Trong đoạn mã trên:
+ Mục tiêu của các hàm/thủ tục không thay đổi
+ Thay đổi tham số đầu vào của các hàm/thủ tục. Bạn chú ý, cách truyền tham biến
cho hàm/thủ tục bằng từ khóa ByRef để sau khi kết thúc hàm/thủ tục các giá trị của các
biến truyền vào sau từ khóa ByRef giữ lại đƣợc các giá trị đã thiết lập trong nội dung
của hàm/thủ tục
+ Thêm một thủ tục callSub() đƣợc viết để gọi các thủ tục/hàm đã định nghĩa.
+ Để chạy thử các hàm/thủ tục, bạn cần chọn thủ tục callSub() và ấn F5 nhƣ hình 7.10
dƣới đây.


Hình 7.10 Truyền tham biến trong lời gọi thủ tục
147


Kết quả nhận đƣợc khi chạy callSub() là mảng a() các số double đƣợc khởi tạo trong
thủ tục InitArray() đƣợc giữ nguyên giá trị khi ra khỏi thủ tục đó (hình 7.11)

…..
Hình 7.11 Kết quả khởi tạo mảng a()

2.2 Module lớp (Class Module)
Có thể xem Class Module là loại module để định nghĩa lớp của ngƣời dùng. Lớp của
ngƣời dùng cũng đƣợc đối xử tƣơng tự nhƣ các lớp sẵn có. Mỗi Class Module có hai
hàm mặc định là Class_Initialize() và Class_Terminate(). Khi tạo đối tƣợng thuộc
Class Module, các hàm này sẽ đƣợc tự động gọi tƣơng ứng khi đối tƣợng đƣợc thiết
lập (bằng lệnh set) và hủy bỏ (tƣờng minh hoặc không tƣờng minh).

2.2.1 Tạo Class Module
Để tạo Class Module, từ menu trong cửa sổ Database, chọn lệnh CREATE/Class
Module (hình 7.12).

Hình 7.12 Trong mục CREATE, chọn mục Class Module để tạo mới 1 Module lớp
Hoặc cũng có thể tạo Class Module từ cửa sổ code nhƣ hình 7.13 dƣới đây bằng cách
click chuột phải vào mục Class Modules rồi chọn lệnh Insert/Class Module

148


Hình 7.13 Tạo mới Class Module từ cửa sổ code
Kết quả nhận đƣợc là một cửa sổ để viết mã lệnh cho Class Module nhƣ hình 7.14

dƣới đây

Project Explorer
Panel

Code Panel

Hình 7.14 Cửa sổ để viết mã lệnh cho Class Module

149


Trong phần code panel, trên cùng là 02 hộp danh sách. Hộp danh sách bên trái có 02
mục là General và Class. Hộp danh sách bên phải là tên các phƣơng thức của lớp và
mục các khai báo (Declarations).
Phần bên dƣới là cửa sổ để viết mã lệnh gồm khai báo các tùy chọn, định nghĩa các
thuộc tính và định nghĩa các phương thức của lớp.

2.2.2 Khai báo các tùy chọn
Phần khai báo gồm các khai báo nhƣ trong Standard Module.

2.2.3 Định nghĩa thuộc tính của lớp
Khai báo các thuộc tính cho lớp sau phần khai báo các tùy chọn. Các thuộc tính này
thuộc lớp đƣợc khai báo với cú pháp sau đây:
Public|Private|Dim Tên_Thuộc_Tính as Kiểu_Dữ_Liệu
Trong đó:
Tên_Thuộc_Tính: đƣợc đặt theo quy tắc đặt tên: không có dấu cách, không có các ký
tự đặc biệt, …
As: từ khóa
Kiểu_dữ_liệu: là các kiểu dữ liệu của hệ thống hoặc các lớp đã đƣợc định nghĩa

Public: chỉ định thuộc tính có phạm vi truy xuất toàn cục (khắp nơi trong CSDL). Tuy
nhiên, trong lập trình hƣớng đối tƣợng không nên khai báo phạm vi public cho các
thuộc tính
Private: chỉ định thuộc tính có phạm vi truy xuất chỉ trong nội bộ lớp. Phạm vi này nên
đƣợc khai báo cho các thuộc tính của lớp
Dim: từ khóa này bản chất dùng để khai báo biến, trong Class Module (lớp) có thể sử
dụng Dim trong trƣờng hợp này Dim và Private là nhƣ nhau. Tuy nhiên, không nên sử
dụng Dim mà nên sử dụng Public và Private để cho mã lệnh đƣợc rõ ràng theo đúng
phong cách lập trình hƣớng đối tƣợng và chƣơng trình biên dịch cũng dễ dàng thi hành
hơn.
Ví dụ: Ta khai báo một lớp doubleArray gồm các thuộc tính sau đây:

Private a(100) As Double
Public n As Integer
Trong khai báo trên:

150


+ Mảng a(100) để chứa các số double, có phạm vi truy xuất là private. Nghĩa là bạn
chỉ có thể truy xuất đƣợc thuộc tính a() của lớp khi ở trong lớp đó. Ra khỏi lớp đó, bạn
không còn nhìn thấy thuộc tính a() nữa.
+ n là một số nguyên, chỉ định số phần tử của mảng. Thuộc tính n có phạm vi truy xuất
public. Nghĩa là sau này, từ bất kỳ đâu trong ứng dụng bạn có thể tạo một thể hiện của
lớp doubleArray. Bạn đều có thể truy xuất vào thuộc tính n từ thể hiện đó.
Đoạn mã sau đây minh họa các phạm vi public và private của ví dụ trên:

Bên ngoài lớp doubleArray, đối với thể hiện a1 của lớp doubleArray, bạn chỉ thấy a1.n
(vì n đƣợc định nghĩa phạm vi truy xuất public) trong khi bạn không thể thấy a1.a() (vì
a() đƣợc định nghĩa phạm vi truy xuất private)

Nhƣ vậy, có một vấn đề đặt ra ở đây là bạn luôn muốn định nghĩa các thuộc tính của
lớp là private để cho an toàn, nhƣng một số trƣờng hợp bạn vẫn muốn cho phép truy
xuất vào các thuộc tính private này từ bên ngoài lớp. Giải pháp là bạn định nghĩa các
Property Get và Property Let. Property Get là để cho phép đọc đƣợc giá trị của thuộc
tính, Property Let là để cho phép ghi giá trị vào thuộc tính. Tất nhiên bạn có thể dùng
cả hai Property Get và Property Let để cho phép một thuộc tính vừa có thể đọc đƣợc
vừa có thể ghi đƣợc.
Trong ví dụ sau, chúng ta sẽ cho phép đọc và ghi vào thuộc tính n của lớp doubleArray
từ bên ngoài lớp thông qua Property Get và Property Let của count trong khi đó n vẫn
có phạm vi truy xuất là private.

151


Quan sát ví dụ trên, bạn thấy cần thêm đoạn mã:
Public Property Get count() As Integer
count = n
End Property

Là để cho phép đọc (lấy giá trị) đƣợc thuộc tính n của lớp doubleArray từ ngoài lớp.
Đoạn mã:
Public Property Let count(ByVal value As Integer)
n = value
End Property

Là để cho phép ghi (thiết lập) giá trị cho thuộc tính n của lớp doubleArray từ ngoài
lớp.
Chú ý: bạn có thể đặt trùng tên “count” ở đây đƣợc chấp nhận. Tất nhiên, bạn có thể
đặt 2 tên khác nhau nhƣng không nên làm thế sẽ rất lộn xộn và khó theo dõi code cũng
nhƣ sử dụng thuộc tính của lớp sau này.

Sau khi thêm vào phần định nghĩa thuộc tính của lớp 2 đoạn mã trên, bây giờ bạn có
thể đọc/ghi vào thuộc tính n của lớp doubleArray nhƣ sau:

152


Trong đoạn mã trên, bạn thấy bạn thiết lập giá trị 2 cho thuộc tính n thông qua
a1.count = 2. Bạn thử in ra giá trị của a1.n thông qua lệnh Debug.Print (a1.count). Kết
quả bạn thấy số 2 đƣợc hiển thị trong cửa sổ Immediate

2.2.4 Định nghĩa các phƣơng thức của lớp
Phƣơng thức là các hàm của đối tƣợng. Nếu so sánh với các thuộc tính thì bạn có thể
thấy: thuộc tính là dữ liệu (Data) còn phƣơng thức là các hoạt động của đối tƣợng. Tất
nhiên các hoạt động cần thiết phải có dữ liệu.
Định nghĩa phƣơng thức nhƣ sau:
Private|Public Sub|Function Tên_Phương_Thức
[(Danh_sách_tham_số)]
‘các lệnh trong phương thức
End Sub|Function
Trong đó:
Private | Public: là các khai báo phạm vi truy xuất của phƣơng thức. Ý nghĩa của
chúng tƣơng tự nhƣ trong phần định nghĩa các thuộc tính ở trên. Đối với phƣơng thức,
bạn nên để phạm vi truy xuất là public hơn là private. Bạn cũng có thể viết các phƣơng
thức để đọc, ghi các giá trị cho các thuộc tính thay cho Property Get và Property Let.
Tuy nhiên, nhƣ thế không hay và không đúng phong cách hƣớng đối tƣợng.
Sub|Function: là các từ khóa quy định phƣơng thức không trả về giá trị (Sub) và có trả
về giá trị (Function)
End Sub|Function: từ khóa quy định kết thúc phần định nghĩa của phƣơng thức.
Tên_Phương_Thức: đƣợc đặt theo quy tắc đặt tên: không có dấu cách, không có các ký
tự đặc biệt.

153


Danh_sách_tham_số: là tùy chọn. Mỗi tham số đƣợc khai báo bao theo quy tắc:
[ByVal|ByRef] Tên_Tham_Số As Kiểu_Dữ_Liệu
ByVal | ByRef là kiểu tham chiếu của tham số. ByVal là tham chiếu theo kiểu tham trị.
ByRef là tham chiếu theo kiểu tham biến. Mặc định là ByVal.
Tên_Tham_Số: đƣợc đặt theo quy tắc đặt tên.
As: từ khóa
Kiểu_Dữ_Liệu: là các kiểu dữ liệu đã đƣợc định nghĩa hoặc các lớp, kiểu dữ liệu ngƣời
dùng định nghĩa.
Các tham số đƣợc phân tách nhau bởi dấu phẩy (,).
Ví dụ sau đây sẽ định nghĩa phƣơng thức sortArrayASC() của lớp doubleArray.
Phƣơng thức này không có tham số và sẽ thực hiện sắp xếp các phần tử trong thuộc
tính mảng a theo thứ tự từ nhỏ đến lớn. sortArrayASC() không trả về giá trị nào.
Sub sortArrayASC()
Dim i, j As Integer
For i = 1 To n - 1
For j = i + 1 To n
If (a(i) > a(j)) Then
Dim tg As Double
tg = a(i)
a(i) = a(j)
a(j) = tg
End If
Next
Next
End Sub

Phƣơng thức containInArray(ByVal x as Double) sau đây sẽ kiểm tra xem giá trị x có

bằng với một phần tử nào của mảng a trong lớp doubleArray không? Nếu bằng, hàm
sẽ trả về giá trị TRUE, ngƣợc lại hàm trả về giá trị FALSE.
Public Function containInArray(ByVal x As Double)
Dim i As Integer
Dim kt As Boolean
kt = False
For i = 1 To n

154


If x = a(i) Then
kt = True
Exit For
End If
Next
containInArray = kt
End Function

2.2.5 Ví dụ
Ta viết lại Standard Module trong ví dụ trƣớc theo cách tiếp cận của Class Module và
đặt tên là doubleArray, gồm các mã lệnh sau đây:
‘Khai báo các tùy chọn
Option Compare Database
Option Base 1
Option Explicit

‘Định nghĩa các thuộc tính của lớp. Thuộc tính a() là một mảng
‘ các số double, thuộc tính n là số lượng các phần tử của mảng a()
Private a(100) As Double

Private n As Integer

‘Định nghĩa các phương thức của lớp
‘Phương thức để khởi tạo các giá trị cho các thuộc tính a() và n
‘num được truyền vào để khởi tạo cho n còn a() sẽ lấy các giá trị ngẫu nhiên
Sub initArray(num As Integer)
Dim i As Integer
n = num
Randomize
For i = 1 To n
a(i) = Rnd * 100
Next
End Sub

155


×