[Hỏi] Cách khai báo biến toàn cục trong VBA

Liên hệ QC

quyenpv

Thu nhặt kiến thức
Tham gia
5/1/13
Bài viết
709
Được thích
90
Giới tính
Nam
Nghề nghiệp
Decode cuộc đời!
Qua GPE được học hỏi rất nhiều điều, tuy nhiên còn hạn chế chưa biết cách viết code thế nào
Em muốn hỏi có cách nào khai báo biến toàn cục trong VBA mà sử dụng được trong nhiều Module không ạ, do code còn hoàn thiện mà chỉnh sửa liên tục xóa dòng nên đối khi mò mãi mới tìm ra nguyên nhân là do địa chỉ Target bị sai nên em nghĩ dùng biến khai báo từ đầu là hay nhất muốn sửa thế nào chỉ cần sửa biến là xong
VD: Em có lấy như sau:
Mã:
If Sheets("TS").Range("B48").Value="A" then
.....
làm gì đó
End if

Bây giờ mình khai báo
Dim Check as Sheets("TS").Range("B48")
sau đó Code dùng
Mã:
If Check.Value="A" then
.....
làm gì đó
End if

Nhờ các anh chỉ giúp với ạ
 
Upvote 0
Public Const T6 = #06:00:00 AM#

Hằng ngày giờ được ghi bằng cách nhét chúng giữa 2 dấu hash.

T24-32 thì hơi rắc rối 1 chút. VBA không hiểu giờ 32.
Vào cửa sổ immediate, gõ
? timeseriaL(32,0,0)
Enter
Copy kết quả (hình như là 8 giờ ngày 31/12/1899)
Public Const T32 = #31/12/1899 08:00:00 AM#
 
Upvote 0
Em viết thế này sao cứ báo lỗi anh nhỉ? Nó báo Variable not defined
PHP:
Sub Bien_toan_cuc()
    Public Const T6 = TimeSerial(6, 0, 0)
    Public Const T7 = TimeSerial(7, 0, 0)
    Public Const T8 = TimeSerial(8, 0, 0)
    Public Const T9 = TimeSerial(9, 0, 0)
    Public Const T10 = TimeSerial(10, 0, 0)
    Public Const T14 = TimeSerial(14, 0, 0)
    Public Const T15 = TimeSerial(15, 0, 0)
    Public Const T17 = TimeSerial(17, 0, 0)
    Public Const T18 = TimeSerial(18, 0, 0)
    Public Const T20 = TimeSerial(20, 0, 0)
    Public Const T21 = TimeSerial(21, 0, 0)
    Public Const T22 = TimeSerial(22, 0, 0)
    Public Const T23 = TimeSerial(23, 0, 0)
    Public Const T24 = TimeSerial(24, 0, 0)
    Public Const T30 = TimeSerial(30, 0, 0)
    Public Const T32 = TimeSerial(32, 0, 0)
End Sub

Về mua/lắp lại phần mềm Excel khác đi. Cái error library của compiler trong máy bạn bị sai rồi (chắc bị lệch con trỏ). Càng giữ càng tự làm khó mình trong việc code.

Capture.PNG
 
Upvote 0
Upvote 0
Ý anh nghĩa là em viết như trên không sai? Sai do phần mềm có lỗi phải không ạ?
Bạn viết như thế là sai ngữ pháp, trình dịch báo lỗi. Nhưng nó sẽ báo như cái hình tôi đưa lên ở bài #24
Nếu nó báo "variable not defined" như bạn nói ở bài #16 thì là VBE của máy bạn nát bét rồi.
 
Upvote 0
Bạn viết như thế là sai ngữ pháp, trình dịch báo lỗi. Nhưng nó sẽ báo như cái hình tôi đưa lên ở bài #24
Nếu nó báo "variable not defined" như bạn nói ở bài #16 thì là VBE của máy bạn nát bét rồi.
Đây là kiểu tập bơi: sau vài động tác sải tay thì nhẩy xuống bể sâu. Chưa qua được bước khai báo biến/hằng, chưa biết rõ về cú pháp đã viết code.
 
Upvote 0
Đây là kiểu tập bơi: sau vài động tác sải tay thì nhẩy xuống bể sâu. Chưa qua được bước khai báo biến/hằng, chưa biết rõ về cú pháp đã viết code.
Vâng, phần lớn những gì em làm đều dựa vào code mẫu anh chị diễn đàn mình viết cho. Đôi khi tùy chỉnh lại theo suy nghĩ của mình, mắc lỗi em lại tìm hiểu. Giờ nhìn lại thấy các Sub nhiều mà có gì đó không khoa học nên em tìm hiểu lại từ phần khai báo biến toàn cục anh ạ :((
 
Upvote 0
Tạm gác qua loại biến tĩnh cho đỡ rắc rối. Hãy nói về biến nội (cục bộ) và biến toàn cục.

Khái niệm về loại biến, dùng chung cho hầu hết các ngôn ngữ (lưu ý là có 1 vài ngôn ngữ như JavaScript không hoàn toàn theo luật này):
Biến nội, khai báo bên trong sub/function có 2 đặc điểm (*):
1. Nó là biến riêng của sub/function. Các sub/func khác không biết đến và không thể chạm vào.
2. Nó có đời sống trong vòng đời sống của sub/func. Tức là được tạo ra (nếu chưa có chỗ chứa thì ít nhất là có cái tên) lúc được khai báo và hoàn toàn biến mất khi sub/func ấy end hoặc exit.

Hầu hết các trường hợp người ta sử dụng biến toàn cục là vì muốn tránh/vượt qua một hoặc cả hai tính chất trên của biến nội. Tức là:
1. Biến toàn cục không phải là biến riêng của sub/func. Đối với VBA, ngừoi ta có thể công bố nó là của chung trong cả Project (ai cũng có thể thấy và sử dụng), hoặc là của riêng trong Module (chỉ các thành phần của module chứa nó mới thấy, các module khác không thể chạm vào)
2. Nó có đời sống suốt project. Tức là được tạo ra khi code bắt đầu chạy và chỉ bị huỷ khi project ngưng.

Bạn có thể hình dung khái niệm "chạm vào" theo khung cảnh một cơ quan, và biến là công cụ:
- Vật dụng của nhân viên hoàn toàn là của riêng nhân viên.
- Vật dụng chung chia ra hai loại, loại của riêng phòng ban và loại của chung cả cơ quan.

Thường thì cách code ngày xưa là dùng biến toàn cục để thay thế các trị cần được chuyển qua lại giữa nhiều sub/func - nhiều trị quá, cái dãy tham (paramater list) dài cả cây số.
Cách code ngày nay, và cũng là cách hay dùng ở diễn đàn này là:
1. Đặt những trị cần thiết cho cả Project - tức là một hình thức của thông số. Hữu hiệu nhất là các mảng (array)
2. Gần đây, nhiều người hiểu thêm về cách sử dụng những Object (đối tượng) dạng tập hợp (set, collection, table,...). Những đối tượng này có khi rất lớn và nếu phải nạp trị vào mỗi lần sử dụng thì rất lãng phí năng lượng. Vì vậy ý tưởng nạp một lần và giữ đó sử dụng cả project là rất hữu hiệu.

Đường lối code ở diễn đàn này vốn được chủ xướng bởi những tay tổ mò code. Những tay tổ này rất giỏi đọc "help" và dày công thử nghiệm cho nên code rất hiệu quả và vững chãi. Tuy nhiên, tôi vẫn dùng từ "mò" bởi vì họ đã bỏ qua giai đoạn tìm hiểu về cơ cấu hạ tầng của code.

Đối với bạn ở bài #28, chủ yếu là học code ở đây thì chỉ cần biết điều 1 và 2 ở trên thôi.

Đối với bạn tác giả các bài viết chỉ dẫn code (và một bạn khác mà tôi nghĩ là GV dạy lập trình) thì nên tìm hiểu về vị trí của biến trong bộ nhớ. Và cách sử dụng biến toàn cục trong các Project phức tạp, nhiều modules. Như tôi đã từng nói, biến toàn cục là công cụ nguy hiểm. Nếu có dịp, tôi sẽ nói sơ qua về cách dùng biến toàn cục một cách an toàn hơn.

Chú: biến toàn cục còn một vài công dụng nữa. Nhưng ở trình độ rất cao cho nên tôi không đề cập đến ở đây.
 
Upvote 0
Public Const T6 = #06:00:00 AM#

Hằng ngày giờ được ghi bằng cách nhét chúng giữa 2 dấu hash.

T24-32 thì hơi rắc rối 1 chút. VBA không hiểu giờ 32.
Vào cửa sổ immediate, gõ
? timeseriaL(32,0,0)
Enter
Copy kết quả (hình như là 8 giờ ngày 31/12/1899)
Public Const T32 = #31/12/1899 08:00:00 AM#

Em nghĩ 32h nó tương đương là #1/1/1900 8:00:00 AM# chứ nhỉ?

Em khai báo lại như anh hướng dẫn thì đã chạy rồi
PHP:
    Public Const T6 As Single = #6:00:00 AM#
    Public Const T7 As Single = #7:00:00 AM#
    Public Const T8 As Single = #8:00:00 AM#
    Public Const T9 As Single = #9:00:00 AM#
    Public Const T10 As Single = #10:00:00 AM#
    Public Const T14 As Single = #2:00:00 PM#
    Public Const T15 As Single = #3:00:00 PM#
    Public Const T17 As Single = #5:00:00 PM#
    Public Const T18 As Single = #6:00:00 PM#
    Public Const T20 As Single = #8:00:00 PM#
    Public Const T21 As Single = #9:00:00 PM#
    Public Const T22 As Single = #10:00:00 PM#
    Public Const T23 As Single = #11:00:00 PM#
    Public Const T24 As Single = #12/31/1899#
    Public Const T30 As Single = #12/31/1899 6:00:00 AM#
    Public Const T31 As Single = #12/31/1899 7:00:00 AM#
    Public Const T32 As Single = #12/31/1899 8:00:00 AM#
    Public Const T33 As Single = #12/31/1899 9:00:00 AM#

Lạ điều em không hiểu em viết vậy trong một module thì các sub ở module khác nhận ngon lành, nếu mở đầu là Sub hoặc Public Sub... và kết thúc là End sub thì báo lỗi như cái lỗi em bảo anh (Mặc dù em đã cài lại máy).
 
Lần chỉnh sửa cuối:
Upvote 0
Tạm gác qua loại biến tĩnh cho đỡ rắc rối. Hãy nói về biến nội (cục bộ) và biến toàn cục.

Khái niệm về loại biến, dùng chung cho hầu hết các ngôn ngữ (lưu ý là có 1 vài ngôn ngữ như JavaScript không hoàn toàn theo luật này):
Biến nội, khai báo bên trong sub/function có 2 đặc điểm (*):
1. Nó là biến riêng của sub/function. Các sub/func khác không biết đến và không thể chạm vào.
2. Nó có đời sống trong vòng đời sống của sub/func. Tức là được tạo ra (nếu chưa có chỗ chứa thì ít nhất là có cái tên) lúc được khai báo và hoàn toàn biến mất khi sub/func ấy end hoặc exit.

Hầu hết các trường hợp người ta sử dụng biến toàn cục là vì muốn tránh/vượt qua một hoặc cả hai tính chất trên của biến nội. Tức là:
1. Biến toàn cục không phải là biến riêng của sub/func. Đối với VBA, ngừoi ta có thể công bố nó là của chung trong cả Project (ai cũng có thể thấy và sử dụng), hoặc là của riêng trong Module (chỉ các thành phần của module chứa nó mới thấy, các module khác không thể chạm vào)
2. Nó có đời sống suốt project. Tức là được tạo ra khi code bắt đầu chạy và chỉ bị huỷ khi project ngưng.

Bạn có thể hình dung khái niệm "chạm vào" theo khung cảnh một cơ quan, và biến là công cụ:
- Vật dụng của nhân viên hoàn toàn là của riêng nhân viên.
- Vật dụng chung chia ra hai loại, loại của riêng phòng ban và loại của chung cả cơ quan.

Thường thì cách code ngày xưa là dùng biến toàn cục để thay thế các trị cần được chuyển qua lại giữa nhiều sub/func - nhiều trị quá, cái dãy tham (paramater list) dài cả cây số.
Cách code ngày nay, và cũng là cách hay dùng ở diễn đàn này là:
1. Đặt những trị cần thiết cho cả Project - tức là một hình thức của thông số. Hữu hiệu nhất là các mảng (array)
2. Gần đây, nhiều người hiểu thêm về cách sử dụng những Object (đối tượng) dạng tập hợp (set, collection, table,...). Những đối tượng này có khi rất lớn và nếu phải nạp trị vào mỗi lần sử dụng thì rất lãng phí năng lượng. Vì vậy ý tưởng nạp một lần và giữ đó sử dụng cả project là rất hữu hiệu.

Đường lối code ở diễn đàn này vốn được chủ xướng bởi những tay tổ mò code. Những tay tổ này rất giỏi đọc "help" và dày công thử nghiệm cho nên code rất hiệu quả và vững chãi. Tuy nhiên, tôi vẫn dùng từ "mò" bởi vì họ đã bỏ qua giai đoạn tìm hiểu về cơ cấu hạ tầng của code.

Đối với bạn ở bài #28, chủ yếu là học code ở đây thì chỉ cần biết điều 1 và 2 ở trên thôi.

Đối với bạn tác giả các bài viết chỉ dẫn code (và một bạn khác mà tôi nghĩ là GV dạy lập trình) thì nên tìm hiểu về vị trí của biến trong bộ nhớ. Và cách sử dụng biến toàn cục trong các Project phức tạp, nhiều modules. Như tôi đã từng nói, biến toàn cục là công cụ nguy hiểm. Nếu có dịp, tôi sẽ nói sơ qua về cách dùng biến toàn cục một cách an toàn hơn.

Chú: biến toàn cục còn một vài công dụng nữa. Nhưng ở trình độ rất cao cho nên tôi không đề cập đến ở đây.

Em đang nhận trái đắng biến toàn cục rồi :((
 
Upvote 0
...
Lạ điều em không hiểu em viết vậy trong một module thì các sub ở module khác nhận ngon lành, nếu mở đầu là Sub hoặc Public Sub... và kết thúc là End sub thì báo lỗi như cái lỗi em bảo anh (Mặc dù em đã cài lại máy).

Tất cả các Const (hằng) hay Dim (biến) khai báo bên trong Sub/Function (tức là giữa Sub và End Sub) luôn luôn là đồ nội. Không thể Public.

Chỉ khai báo bên ngoài Sub/Function (tức là ngay đầu module, trước tất cả các Sub hay Function) mới có sự chọn lựa Public (toàn cục cả project) hay Private (toàn cục trong phạm vi module)
 
Upvote 0
Em có một trích đoạn code như này
Mã:
...
If K Then
        MsgBox k 'Lần 1
        With Sh_BCC
            MsgBox k 'Lần 2
            .Range("FF8").Resize(k, 7) = BoSungGio
            .Range("J8").Resize(k, 126) = dArr
            .Range("B8").Resize(k, 1) = dArr
            .Range("A4").Resize(, 168).Copy
            .Range("A8").Resize(k, 168).PasteSpecial Paste:=xlPasteFormats
            .Rows(k + 8 & ":" & k + 5000).Delete
            MsgBox k 'Lần 3
        End With
    End If
Với k em đang khai báo là biến toàn cục (Long). Sau đó em thao tác như sau:
- Chạy Sub lần 1 em ấn Esc để dừng chương trình.
- Chạy lại Sub lần 2 thì tại dòng thông báo đầu tiên k =5000, lần thứ 2 k=5000, lần thứ 3 k=0.
- Chạy lại Sub lần 3 thì tại dòng thông báo đầu tiên k =5000, lần thứ 2 k=5000, lần thứ 3 k=5000.

Cho em hỏi tại sao có sự khác biệt k của hai lần chạy Sub lần 2 và 3. Nói cách khác nếu em cho dừng chương trình đột ngột hoặc lỗi thì chạy lần 2 không ra kết quả, chạy lại thêm lần nữa thì lại ra kết quả mong muốn.
 
Upvote 0
Em có một trích đoạn code như này
Mã:
...
If K Then
        MsgBox k 'Lần 1
        With Sh_BCC
            MsgBox k 'Lần 2
            .Range("FF8").Resize(k, 7) = BoSungGio
            .Range("J8").Resize(k, 126) = dArr
            .Range("B8").Resize(k, 1) = dArr
            .Range("A4").Resize(, 168).Copy
            .Range("A8").Resize(k, 168).PasteSpecial Paste:=xlPasteFormats
            .Rows(k + 8 & ":" & k + 5000).Delete
            MsgBox k 'Lần 3
        End With
    End If
Với k em đang khai báo là biến toàn cục (Long). Sau đó em thao tác như sau:
- Chạy Sub lần 1 em ấn Esc để dừng chương trình.
- Chạy lại Sub lần 2 thì tại dòng thông báo đầu tiên k =5000, lần thứ 2 k=5000, lần thứ 3 k=0.
- Chạy lại Sub lần 3 thì tại dòng thông báo đầu tiên k =5000, lần thứ 2 k=5000, lần thứ 3 k=5000.

Cho em hỏi tại sao có sự khác biệt k của hai lần chạy Sub lần 2 và 3. Nói cách khác nếu em cho dừng chương trình đột ngột hoặc lỗi thì chạy lần 2 không ra kết quả, chạy lại thêm lần nữa thì lại ra kết quả mong muốn.
Em tìm ra nguyên nhân rồi nhé, do em có một sự kiện khiến cho k trở về 0 cho nên gây lỗi như vậy
 
Upvote 0
Nếu tôi làm thì tôi dùng hằng toàn cục:
- đặt một module có tên là Hang_TC
- trong module đó, đặt
public const SHEETA = "Sheet1"
public const RANGE1 = "A5"
public const RANGE2 = "C5"
...
- trong các moldules khác code sẽ là:
Sheets(SHEETA).Range(RANGE1).Value ....
Đại khái vậy.

khi cần sửa, chỉ phải vào module Hang_TC để sửa thôi.

cách thức này tôi vẫn làm hoài. Tìm mấy bài tôi viết code cho mấy cái sub dài dài vài chục dòng sẽ thấy (mấy cái sub ngắn không bỏ công khai báo hằng)
Anh ơi em vừa tìm được trên mạng code
PHP:
Public Property Get ModelWorksheet As Worksheet
    Const ModelWorksheetName As String = "gs_model"
    Set ModelWorksheet = ActiveWorkbook.Worksheets(ModelWorksheetName)
End Property
Vậy cơ bản nó chỉ khác ở dòng public const SHEETA = "Sheet1" là một cái name trong cửa sổ VBA, còn một cái là name trong cửa sổ Excel, anh nhỉ.
 
Upvote 0
Web KT
Back
Top Bottom