Tiếp nội dung phần 1 Giáo trình Nhập môn hệ quản trị cơ sở dữ liệu: Phần 2 cung cấp kiến thức về Lập trình cơ sở dữ liệu trong MS Access cụ thể như: Giới thiệu lập trình Visual Basic Application, Kiểu dữ liệu, hằng và biến, Các cấu trúc điều khiển,...
Trang 1131
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
Trang 2132
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
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
Trang 3133
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
Trang 4134
Kết quả bạn nhận được là cửa sổ để viết code trong Standard Module như trong hình 7.2
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
Code panel Project
Explorer Panel
Trang 5135
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
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
Nút lệnh save
Bạn nhập tên mới cho
module ở thuộc tính
(Name)
Trang 6136
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
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
Trang 7137
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
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
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
Trang 8138
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
Trang 9‘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
‘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
‘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()
Trang 10‘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)
Trang 11141
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
Trang 12142
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
Trang 13Hì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
Trang 14144
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
Trang 15145
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
Trang 16Next
containInArray = kt
Trang 17Trong đ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
Trang 18148
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
Trang 19149
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
Hình 7.14 Cửa sổ để viết mã lệnh cho Class Module
Code Panel
Project Explorer Panel
Trang 20150
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:
Trang 21151
+ 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
Trang 22152
Quan sát ví dụ trên, bạn thấy cần thêm đoạn mã:
Public Property Get count() As Integer
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:
Trang 23153
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
Trang 24154
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
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
Trang 25‘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)
Trang 27157
Exit For End If
đó và chạy thử bằng cách ấn phím F5 Bạn hãy quan sát các kết quả
Hình 7.15 Viết mã thử nghiệm lớp doubleArray
+ Kết quả chạy test() là: Tạo ra một đối tượng (thể hiện) của lớp doubleArray Gọi phương thức InitArray() để khởi tạo giá trị cho thuộc tính mảng a() và n của a1 Gọi phương thức showArray() để hiển thị các phẩn tử của a1.a(), lần lượt mỗi phần tử được
Trang 28158
hiển thị trong một hộp msgBox Gọi phương thức sortArrayASC() để sắp xếp các phần
tử của a1.a() theo trật tự tăng dần
2.3 Module của form/report (Form/report Module)
Module này thuộc phần Microsoft Access Class Object (MSCO) trong cửa sổ code VBA
Mặc định tất cả các form/report đều có module ẩn sau nó (thuộc tính HasModule được thiết lập mặc định là True) Có thể dùng từ khóa Me khi tham chiếu đến các module ẩn sau form/report
Trong Form/Report Module chúng ta có thể tạo các thủ tục theo sự kiện (thủ tục được
tự động gọi khi có sự kiện tương ứng với nó xảy ra) hoặc các thủ tục độc lập có thể được gọi từ các thủ tục khác trong cùng hoặc khác module Tuy nhiên, trong phần này chúng ta chỉ nên viết các thủ tục hành xử theo các sự kiện của các điều khiển trên form/report
Để tạo được các MSCO này, bạn cần tạo form/report trước Ứng với mỗi form/report, trong trường hợp bạn cần viết code cho các điều khiển trên form/report, hệ thống sẽ tự động tạo ra một module tương ứng gắn với form/report đó Tên của module đó sẽ
được đặt tự động là Form_Tên_Form/Report_Tên_Report
Hình ảnh trên cho thấy, chúng ta có 02 form với tên lần lượt là: frmArrayCalculate và frmSearch, do vậy hệ thống sẽ tự sinh cho ta 02 module MACO là Form_frmArrayCalculate và Form_frmSearch Tương tự như vậy với 02 Report rptArrayCalculate và rptSearch
Trang 29159
Như vậy, module MACO sẽ dùng để viết (chứa) các hàm hành xử dựa trên các sự kiện của form/report và các sự kiện của các điều khiển nằm trên form/report Mỗi form/report sẽ có một module MACO tương ứng
Các thành phần của module MSCO cũng tương tự như 02 loại module trên, bao gồm:
Các khai báo tùy chọn, các khai báo biến toàn cục và định nghĩa các hàm hành xử cho các sự kiện của form/report và các sự kiện của các điều khiển trên form/report
Phần khai báo các tùy chọn và các biến toàn cục hoàn toàn tương tự như Standard Module Ở đây, chúng ta chỉ quan tâm đến phần định nghĩa các hàm hành xử tương ứng cho các sự kiện của form/report và các sự kiện của các điều khiển trên form/report
2.3.1 Tạo MSCO module
Trước hết bạn cần tạo form/report trước Sau đó hãy tạo một vài các điều khiển như TextBox, Button trên form/report
Tiếp theo, để tạo MSCO module, từ thực đơn CREATE của MS Access, bạn cần chọn
lệnh Visual Basic như trong hình dưới đây
Kết quả bạn nhận được cửa sổ có dạng như hình sau Tại cửa sổ này, bạn có thể khai báo các tùy chọn, khai báo các biến dùng chung cho các hàm phía sau và định nghĩa các hàm hành xử cho các sự kiện của form/report và các sự kiện của các điều khiển trên form/report
Trang 30định nghĩa hàm này (và các hàm tương tự) trong một Standard Module Ở đây bạn vẫn
sẽ gọi được các hàm đó bình thường, cách tiếp cận như vậy sẽ giúp chương trình của bạn sáng hơn và dễ kiểm soát hơn
+ Các hàm hành xử theo sự kiện ở đây có danh sách tham số và tên phải được khớp với các quy tắc về định nghĩa hàm hành xử cho sự kiện tương ứng của MS Access
2.3.2 Định nghĩa các hàm hành xử cho các sự kiện
Xuất phát từ quan điểm lập trình của VBA ở đây là chương trình hướng đối tượng và hướng sự kiện Theo đó, toàn bộ chương trình sẽ vận hành theo các sự kiện của các điều khiển nằm trên form/report và các sự kiện của form/report khi có tác động của người dùng hoặc khi biên dịch
Để định nghĩa các hàm hành xử cho các sự kiện, bạn cần thiết kế form/report và các điều khiển trên form/report trước Bạn nhớ đặt tên cho các điều khiển sau này sẽ có các sự kiện trên nó Ví dụ một nút lệnh trên form là bạn muốn sau này người dùng click vào nó (sự kiện OnClick), chương trình sẽ thực hiện một đoạn mã nào đó đáp ứng sự kiện này Như vậy, bạn nên đặt tên rõ ràng cho nút lệnh này
Sau khi thiết kế điều khiển trên form, bạn mở của sổ property của nó (kích chọn vào điều khiển, sau đó ấn phím F4 ) và lựa chọn mục Event là danh sách các sự kiện có thể
có dành cho điều khiển đó Trong phần danh sách các sự kiện của điều khiển, bạn
Trang 31kiện xảy ra với điều khiển
+ Các tham số của hàm có thể có hoặc không tùy theo điểu khiển và sự kiện Bạn cũng không thể thay đổi các kiểu dữ liệu của các tham số này Tất nhiên, bạn có thể thay tên của chúng
Ví dụ:
Trang 32162
Hàm hành xử cho sự kiện OnClick của nút lệnh không có tham số:
Private Sub cmdSortArrayASC_Click()
End Sub
Hàm hành xử cho sự kiện KeyDown của TextBox có 2 tham số
Private Sub txtNum_KeyDown(KeyCode As Integer,
Shift As Integer)
End Sub
2.3.3 Nhận xét
MSCO module có các đặc điểm sau đây:
+ Toàn bộ mã cần để tự động hóa form/report thường trú ngay trong form/report đó, không cần phải nhớ tên của đối tượng module riêng biệt liên quan đến form/report + Các thủ tục hướng sự kiện trong module được tự động thi hành dựa trên các sự kiện xảy ra với form/report và các điều khiển trên form/report, không cần phải xác định lời gọi tường minh cho chúng
+ MS Access tải Standard Module (được tham chiếu bởi đối tượng module) vào bộ nhớ khi chỉ cần có một tham chiếu đến thủ tục hoặc biến trong module và cho phép nó thường trú trong bộ nhớ chừng nào CSDL còn mở Trong khi đó, Form/Report Module chỉ được MS Access tải vào bộ nhớ khi form/report được mở Khi form/report bị đóng lại thì Form/Report Module tương ứng với nó cũng bị giải phóng khỏi bộ nhớ
+ Khi xuất đi một form/report, toàn bộ mã lệnh trong Form/Report Module tương ứng với nó cũng được kết xuất theo
+ Form/report module có module lớn đi kèm sẽ được mở ra, đóng lại chậm hơn so với form/report có module nhỏ hoặc không có module đi kèm
2.3.4 Ví dụ
Mục tiêu: Ví dụ sau đây sẽ minh họa một chương trình hoàn thiện tương tác với người
dùng cuối thông qua form giao diện
Nội dung: Chương trình gồm hai chức năng:
+ Khởi tạo một mảng ngẫu nhiên các số thực với số lượng các phần tử do người dùng nhập
+ Sắp xếp các phần tử của mảng theo trật tự tăng dần
Các bước thực hiện: Gồm 03 bước sau
Trang 33163
+ Thiết kế giao diện
+ Cài đặt 1 lớp doubleArray hỗ trợ xử lý các thao tác cần thiết với mảng số thực
+ Cài đặt các hàm hành xử cho các sự kiện ứng với giao diện trên form, sử dụng lớp doubleArray
Chạy thử chương trình
Như vậy, ở đây chúng ta cần quan tâm đến các bươc thực hiện, các phần khác đã rõ ràng
Thiết kế giao diện
Đề nghị bạn hãy thiết kế một form đặt tên là frmArrayCalculate có giao diện dạng như sau:
Giao diện trên bao gồm:
+ 03 Lable, bạn đặt tên tùy ý Thuộc tính Text của mỗi Lable bạn thiết lập như trên hình
+ 03 TextBox, bạn đặt tên lần lượt là txtNum, txtResult, txtSortedArray theo thứ tự từ trên xuống dưới
+ 02 nút lệnh, bạn đặt tên lần lượt là cmdInitArray và cmdSortArrayASC theo thứ tự
từ trái sang phải
Cài đặt lớp doubleArray
Bạn hãy định nghĩa một Class Module, đặt tên là doubleArray như trong đoạn mã dưới
đây Các thuộc tính và hàm của lớp đã được mô tả chi tiết trong ví dụ của phần Class
Trang 35Cài đặt các hàm cho các sự kiện
Ở đây, ta cài đặt 02 sự kiện OnClick của 02 nút lệnh nhƣ sau Toàn bộ đoạn mã lệnh
sau đƣợc đặt trong một MSCO Module có tên là Form_frmArrayCalcute
Option Compare Database
Option Explicit
'Khai bao mot doi tuong doubleArray su dung chung trong toan chuong trinh Dim DA As doubleArray
Private Sub cmdInitArray_Click()
Dim stResult As String
stResult = ""
Dim stNum As String
Trang 36'Kiem tra xem co nhap vao mot so hay khong?
If (IsNumeric(stNum) = False) Then
MsgBox "So phan tu cua mang phai la mot so nguyen <= 350!"
Exit Sub
End If
'Kiem tra xem co la mot so thap phan hay khong?
Dim pos1, pos2 As Integer
pos1 = -1
pos2 = -1
pos1 = InStr(1, stNum, ",", vbTextCompare)
pos2 = InStr(1, stNum, ".", vbTextCompare)
If (pos1 > 0) Or (pos2 > 0) Then
MsgBox "So phan tu cua mang phai la mot so nguyen <= 350!"
If (num = Null) Or (num > 350) Then
MsgBox "So phan tu cua mang phai la mot so nguyen <= 350!"
Exit Sub
End If
Set DA = New doubleArray
DA.count = num
Trang 37If (DA Is Nothing) Then
MsgBox "Ban can khoi tao ngau nhien mang truoc!"
Exit Sub
End If
If (IsEmpty(DA) = True) Then
MsgBox "Ban can khoi tao ngau nhien mang truoc!"
Exit Sub
End If
If (IsNull(DA) = True) Then
MsgBox "Ban can khoi tao ngau nhien mang truoc!"
Trang 38168
End Sub
Kết quả
Bạn hãy nhập vào ô “Số phần tử của mảng” (ví dụ: 10) sau đó click vào nút lệnh
“Khởi tạo ngẫu nhiên mảng” Kết quả khởi tạo sẽ được hiển thị trong ô “Kết quả khởi tạo ngẫu nhiên mảng”
Bạn tiếp tục click vào nút lệnh “Sắp xếp mảng ASC” Kết quả sắp xếp mảng được hiển thị trong ô “Kết quả sắp xếp mảng”
Bạn hãy tự thử nghiệm các trường hợp khác của chương trình
Đây là một trường hợp chạy chương trình
3 Kiểu dữ liệu, hằng và biến
3.1 Kiểu dữ liệu
Một kiểu dữ liệu là tập hợp các giá trị mà một biến thuộc về kiểu đó có thể nhận được Kiểu dữ liệu được đặc trưng bởi hai yếu tố:
Tập các giá trị thuộc về nó
Tập hợp các phép toán (toán tử) có thể được thực hiện trên nó
VBA cung cấp các kiểu dữ liệu sau đây:
Trang 39169
Single 4 ! Số dấu chấm động từ -3.4*1038 đến 3.4*1038 Double 8 # Số dấu chấm động từ -1.79*10308 đến
1.79*10308 Currency 8 @ Số nguyên được chia tỷ lệ với 4 số lẻ phần
thập phân từ -922,337,203,685,477.5808 đến 922,337,203,685,477.5807
String 10 + 2 byte
cho mỗi ký tự
$ Chuỗi ký tự dài tối đa 2 tỷ byte, chuỗi có độ
dài cố định có thể dài tối đa 65400 ký tự Boolean 2 Không có True hoặc False
Date 8 Không có Giá trị ngày giờ từ 1/1/100 đến 31/12/9999 Object 4 Không có Bất kỳ tham chiếu đối tượng nào
Variant 16 đến
khoảng 2 tỷ byte
Không có Bất kỳ loại dữ liệu nào
Có thể ngầm định định nghĩa kiểu dữ liệu cho biến bằng cách nối thêm một ký tự phân loại dữ liệu vào sau tên biến trong lần đầu tiên sử dụng biến
Ngoài những kiểu dữ liệu VBA đã xây dựng sẵn, VBA còn cung cấp cho người dùng
cú pháp để họ tự xây dựng kiểu dữ liệu của riêng mình, phù hợp với yêu cầu của ứng dụng Đó là kiểu dữ liệu do người dùng định nghĩa (Kiểu cấu trúc)
Cú pháp khai báo:
[Private | Public]
Type varname
elementname [([subscripts])] As type
[elementname [([subscripts])] As type]
End Type
Trong đó:
Public | Private: từ khóa xác định phạm vi truy xuất của kiểu dữ liệu tương ứng cho tất
cả các thủ tục trong tất cả các module thuộc tất cả các dự án | chỉ trong phạm vi module chứa nó
varname: tên kiểu dữ liệu được đặt theo quy tắc đặt tên của VB
elementname: tên các thành phần của kiểu dữ liệu
Trang 40170
subscript: đặt chỉ số cho mảng nếu thành phần dữ liệu tương ứng là mảng
type: là một trong những kiểu của VBA hoặc kiểu đã được định nghĩa trước
Dim Washington(1 To 100) As StateData
Kiểu cấu trúc chỉ được định nghĩa trong phần khai báo của các loại module, không được định nghĩa trong các hàm, thủ tục con Trong Standard Module và Class Module, phạm vi truy xuất của kiểu cấu trúc mặc định là public
Cú pháp truy xuất các thành phần của kiểu cấu trúc:
varname.elementname
Trong đó:
varname: là tên biến kiểu cấu trúc
elementname: tên thành phần của kiểu cấu trúc