xin hỏi về vấn đề khai báo mảng và cách dùng private, public, static function (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

khongnhienttt

Thành viên hoạt động
Tham gia
15/7/15
Bài viết
137
Được thích
33
mình có 2 vấn đề cần hỏi
- thứ nhất theo mình biết mảng là tập hợp các phần tử co cấu trúc giống nhau, vậy ví dụ như mình muốn gán 1 vùng dữ liệu trong excel vùng này có định dạng số, chuỗi, ngày tháng ... thì mình khai báo dim Arr() và gán Arr bằng vùng đó, vậy mỗi biến trong Arr thì nó tự hiểu là viriant phải không ạ.
+ tiếp theo nếu vùng dữ liệu của mình toàn chuỗi mình làm thế này
Mã:
Sub Rectangle1_Click()
 Dim a() As String
 a = Range("a1:h1").Value
 MsgBox a(5)
End Sub

hoặc

Mã:
Sub Rectangle1_Click()
 Dim a() As String
 a = Range("a1:a10").Value
 MsgBox a(5)
End Sub

nó báo lỗi type missmacth là sao thế các bạn

- thứ 2 dù đã đọc rất nhiều về dùng private, public, static function nhưng mình vẫn chưa rõ lắm, theo mình hiểu nếu khai báo hàm là private thì mình khi ở module khác sẽ không gọi được hàm đó, còn khi là public thì từ module khác có thể gọi tới hàm đó được, còn static function mình nghĩ khi thực hiện xong hàm thì giá trị của hàm sẽ được lưu giữ lại ( nhưng chưa tường tận được giữ lại thế nào)
+ thấy trong Hàm CommPic phiên bản mới nhất với nhiều tùy chọn của thầy ndu96081631: thì tại sao lại dùng private cho hàm URLExists.Code:
Function CommPic(ByVal PicPath As String, Optional ByVal PicCel As Range, _
Optional ByVal ScaleWidth As Single = 1, _
Optional ByVal ScaleHeight As Single = 1) As String
Dim mRng As Range, cmt As Comment, fso As Object, bChk As Boolean
On Error Resume Next
Application.Volatile
Set fso = CreateObject("Scripting.FileSystemObject")
If PicCel Is Nothing Then Set PicCel = Application.ThisCell
PicCel(1, 1).Comment.Delete
If Left(PicPath, 7) = "http://" Then
bChk = URLExists(PicPath)
Else
bChk = fso.FileExists(PicPath)
If bChk = False Then
PicPath = ThisWorkbook.Path & "" & PicPath
bChk = fso.FileExists(PicPath)
End If
End If
If bChk Then
If PicCel(1, 1).Comment Is Nothing Then PicCel(1, 1).AddComment
PicCel(1, 1).Comment.Text vbLf
Set mRng = PicCel(1, 1).MergeArea
If mRng Is Nothing Then Set mRng = PicCel(1, 1)
Set cmt = mRng(1, 1).Comment
cmt.Visible = True
With cmt.Shape
.LockAspectRatio = msoFalse
.Placement = xlMoveAndSize
.Shadow.Visible = msoFalse
.Line.ForeColor.RGB = PicCel.Interior.Color
.AutoShapeType = msoShapeRectangle
.Left = mRng.Left: .Top = mRng.Top
.Width = mRng.Width: .Height = mRng.Height
.ScaleWidth ScaleWidth, msoFalse, msoScaleFromMiddle
.ScaleHeight ScaleHeight, msoFalse, msoScaleFromMiddle
.Fill.UserPicture PicPath
End With
End If
End Function
Private Function URLExists(ByVal URL As String) As Boolean
Application.Volatile
On Error Resume Next
If Left(UCase(URL), 7) <> "HTTP://" Then URL = "http://" & URL
With CreateObject("MSXML2.XMLHTTP")
.Open "HEAD", URL, False: .send
URLExists = .Status = 200

End With
End Function
 
có bạn nào giúp mình với

Có câu hỏi liên quan đến tui thì tui trả lời câu này thôi nha!
Hàm CommPic mới nhất có tổng cộng 2 hàm: CommPic và URLExists, trong đó hàm CommPic là hàm chính và URLExists là hàm hỗ trợ. Chính vì là hàm hỗ trợ, tôi không muốn người dùng gõ trên bảng tính nên tôi khai báo Private (để người ta không nhìn thấy, đở rối)
Cũng giống như tình huống này:
- Trong file tôi có 8 thủ tục (8 Sub)
- Trong 8 sub trên, chỉ có 1 sub chính và 7 sub hỗ trợ
- Vậy tôi sẽ khai báo Private cho 7 sub hỗ trợ trên
Mục đích: Để khi người dùng mở file, bấm Alt + F8 sẽ chỉ thấy 1 sub duy nhất là cái sub chính mà tôi muốn người ta chạy (đở mất công nhìn cả đống chẳng biết chọn cái nào)
Vậy thôi!
 
Upvote 0
Có câu hỏi liên quan đến tui thì tui trả lời câu này thôi nha!
Hàm CommPic mới nhất có tổng cộng 2 hàm: CommPic và URLExists, trong đó hàm CommPic là hàm chính và URLExists là hàm hỗ trợ. Chính vì là hàm hỗ trợ, tôi không muốn người dùng gõ trên bảng tính nên tôi khai báo Private (để người ta không nhìn thấy, đở rối)
Cũng giống như tình huống này:
- Trong file tôi có 8 thủ tục (8 Sub)
- Trong 8 sub trên, chỉ có 1 sub chính và 7 sub hỗ trợ
- Vậy tôi sẽ khai báo Private cho 7 sub hỗ trợ trên
Mục đích: Để khi người dùng mở file, bấm Alt + F8 sẽ chỉ thấy 1 sub duy nhất là cái sub chính mà tôi muốn người ta chạy (đở mất công nhìn cả đống chẳng biết chọn cái nào)
Vậy thôi!
rất cảm ơn câu trả lời của thầy, nhưng thầy đã làm ơn thì làm ơn cho trót trả lời giúp em câu hỏi về mảng đi và cách phân biệt public, stastic function
 
Upvote 0
cách phân biệt public, stastic function

Cái này mình đọc được trong sách của tác giả PhanTuHuong xin chia sẻ như sau

Public : Với từ khóa public đứng trước, biến đó tồn tại và hoạt động trong toàn bộ ứng dụng (toàn cục). từ bất kỳ nơi nào trong VBA Project cũng có thể khai thác được hoặc thay đổi giá trị biến này. Kể cả khi thủ tục chấm dứt nhưng chưa thoát khỏi excel, giá trị biến đó vẫn được lưu lại để làm việc cho lần sau. Biến này chỉ mất đi khi ta thoát khỏi Excel

Private : Với từ khóa này, biến chỉ hoạt động trong Module chứa nó (cục bộ).

Static: Thông thường khi 1 thủ tục kết thúc, tất cả các biến được thiết lập lại. Biến static là trương hợp đặc biệt vì chúng vẫn giữ được giá trị ngay cả khi thủ tục kết thúc, tức là biến được lưu lại trong bộ nhớ. Khác với biến Public, biến này được khai báo trong thủ tục và chỉ có phạm vi hoạt động trong thủ tục đó

P/S: Viết vậy ra để chia sẻ cho bạn biết thôi chứ thực ra tớ cũng chưa hiểu gì hết đâu -0-/.-0-/.-0-/.
 
Lần chỉnh sửa cuối:
Upvote 0
rất cảm ơn câu trả lời của thầy, nhưng thầy đã làm ơn thì làm ơn cho trót trả lời giúp em câu hỏi về mảng đi và cách phân biệt public, stastic function
Sub, Function, Public, Private, Dim, Static, v.v...

Là những thủ tục khai báo trước một cái gì đó, hoặc khai báo một biến.

Đứng trước 1 thủ tục ta dùng SUB và kết thúc là END SUB

Đứng trước một hàm tự tạo ta dùng FUNCTION và kết thúc là END FUNCTION

Để 1 biến, 1 Const, 1 thủ tục, 1 hàm, v.v... được khai báo toàn cục, tức ở mọi thủ tục, mọi hàm, mọi sub ta đều dùng được thì ta dùng tiền tố Public đứng trước các biến, hàm, thủ tục, const đó. Nhưng khi khai báo Public chỉ được sử dụng trong một Standard Module chứ không thể để trong code trong UserForm hay trong Sheet Module. Chẳng hạn:

Public Sub, Public Function, Public TenBien As Variant, Public Const TenConst As Byte = 10 v.v...

Cũng giống như Public, nhưng Private có thể khai báo trong bất cứ môi trường Module nào. Khi khai báo với Private thì các thủ tục trong Module đó được sử dụng biến này, hàm này hay thủ tục này mà thôi.

Khi khai báo biến, Public và Private luôn để ở ngoài Function và Sub. Chúng phải được đặt ở trên cùng của một Module. Các biến này chỉ giải phóng khi thoát file.

Dim, Static dùng để khai báo các biến, vẫn có thể để ở ngoài thủ tục hoặc hàm, nhưng thông thường chúng được khai báo trong các thủ tục, các hàm và sau khi thủ tục, hàm được thực thi thì biến này sẽ được giải phóng, song với biến Static lại khác, nó có thể thay đổi theo thủ tục, hàm và tồn tại trong thủ tục, hàm đó cho đến khi đóng file.
 
Upvote 0
Rất cảm ơn câu trả lời cặn cẽ của anh Hoàng Trọng Nghĩa, và bạn khuongvietphong đã đánh máy giúp mình, qua câu trả lời mặc dù chưa lĩnh hội được hết nhưng cũng phần nào mường tượng ra được
- xin bạn nào rành về phần mảng, giải thích giúp mình cầu hỏi 1 ạ
 
Upvote 0
Rất cảm ơn câu trả lời cặn cẽ của anh Hoàng Trọng Nghĩa, và bạn khuongvietphong đã đánh máy giúp mình, qua câu trả lời mặc dù chưa lĩnh hội được hết nhưng cũng phần nào mường tượng ra được
- xin bạn nào rành về phần mảng, giải thích giúp mình cầu hỏi 1 ạ

tôi chẳng biết......cứ cho bằng variant hết.........nó chạy tuốt luốt.....tôi cũng bao giờ thắc mét......hihihihihi
 
Upvote 0
mình có 2 vấn đề cần hỏi
- thứ nhất theo mình biết mảng là tập hợp các phần tử co cấu trúc giống nhau, vậy ví dụ như mình muốn gán 1 vùng dữ liệu trong excel vùng này có định dạng số, chuỗi, ngày tháng ... thì mình khai báo dim Arr() và gán Arr bằng vùng đó, vậy mỗi biến trong Arr thì nó tự hiểu là viriant phải không ạ.
+ tiếp theo nếu vùng dữ liệu của mình toàn chuỗi mình làm thế này
Mã:
Sub Rectangle1_Click()
 Dim a() As String
 a = Range("a1:h1").Value
 MsgBox a(5)
End Sub

hoặc

Mã:
Sub Rectangle1_Click()
 Dim a() As String
 a = Range("a1:a10").Value
 MsgBox a(5)
End Sub

Mảng là một tập hợp mà các phần tử của nó có thể chứa tất cả các Kiểu dữ liệu (Data Type) như Number, String, Date, Object v.v...

Nếu ta quy định nó là một kiểu dữ liệu nào đó chẳng hạn:

Dim sArray() As String

Thì ta phải hiểu rằng những phần tử chứa trong nó phải là dạng chuỗi.

Nếu ta không quy định một kiểu dữ liệu nào (mỗi phần tử chứa trong có thể đủ loại "hầm bà lằng xắng cấu") thì ta khai báo:

Dim sArray() As Variant

Hoặc:

Dim sArray()

Khi không quy định nó thuộc kiểu dữ liệu nào thì mặc nhiên chúng là kiểu dữ liệu Variant vậy.
 
Upvote 0
Public, Private, Static là các từ khoá dùng để xác định phạm vi (còn gọi là tầm vực) của một vật thể (biến, sub, hoặc function)

Phạm vi/tầm vực có hai tính chất: tính chất "có thể thấy được" và tính chất "tồn tại"
tồn tại: chỉ áp dụng cho biến, không tồn tại có nghĩa là chưa được thiết lập, hoặc đã bị huỷ.
có thể thấy được: áp dụng cho mọi loại. Tùy theo cách khai báo mà vật thể có thể thấy được trong một phạm vi nhưng lại bị che khuất trong phạm vi khác. Lưu ý là vật thể có thể vẫn tồn tại, chỉ ở ngoài phạm vi thì không chạm được tới nó mà thôi.

Public là phạm vi toàn cục, ở đâu cũng có thể thấy. Tuy nhiên, nếu nó được khai báo trong module mức thấp thì qua mức cao hơn có thể phải thêm tên của module vào đầu để VBA biết nó ở đâu mà tìm.

Private là phạm vi nội bộ, chỉ đúng vùng nó khai bào mới thấy nó. Nếu nó khai báo trong module thì nó là nội bộ của module, các code trong module đều thấy nó. Nếu nó khai báo trong sub/function thì chỉ có code trong sub/function mới thấy nó.

Static là loại vật thể cố định. Cái này hơi rắc rối một chút. Trong chương trình có 2 vùng bộ nhớ, vùng heap và vùng stack. Biến khai báo toàn cục thuộc về heap và biến khai báo nội bộ sub/function là biến thuộc về stack. Các vật thể nằm trong vùng stack sẽ bị huỷ sau khi sub/function exit hoặc end. Riêng biến Static thì luôn thuộc về heap bất kể nó là public hay private. Vì vậy biến Static không bị huỷ khi sub/function thoát.
 
Upvote 0
Public, Private, Static là các từ khoá dùng để xác định phạm vi (còn gọi là tầm vực) của một vật thể (biến, sub, hoặc function)

Phạm vi/tầm vực có hai tính chất: tính chất "có thể thấy được" và tính chất "tồn tại"
tồn tại: chỉ áp dụng cho biến, không tồn tại có nghĩa là chưa được thiết lập, hoặc đã bị huỷ.
có thể thấy được: áp dụng cho mọi loại. Tùy theo cách khai báo mà vật thể có thể thấy được trong một phạm vi nhưng lại bị che khuất trong phạm vi khác. Lưu ý là vật thể có thể vẫn tồn tại, chỉ ở ngoài phạm vi thì không chạm được tới nó mà thôi.

Public là phạm vi toàn cục, ở đâu cũng có thể thấy. Tuy nhiên, nếu nó được khai báo trong module mức thấp thì qua mức cao hơn có thể phải thêm tên của module vào đầu để VBA biết nó ở đâu mà tìm.

Private là phạm vi nội bộ, chỉ đúng vùng nó khai bào mới thấy nó. Nếu nó khai báo trong module thì nó là nội bộ của module, các code trong module đều thấy nó. Nếu nó khai báo trong sub/function thì chỉ có code trong sub/function mới thấy nó.

Static là loại vật thể cố định. Cái này hơi rắc rối một chút. Trong chương trình có 2 vùng bộ nhớ, vùng heap và vùng stack. Biến khai báo toàn cục thuộc về heap và biến khai báo nội bộ sub/function là biến thuộc về stack. Các vật thể nằm trong vùng stack sẽ bị huỷ sau khi sub/function exit hoặc end. Riêng biến Static thì luôn thuộc về heap bất kể nó là public hay private. Vì vậy biến Static không bị huỷ khi sub/function thoát.

em thấy rằng trong SUB hoặc Function khai báo thì chỉ có DIM hoặc STATIC chứ không có kiểu này
Mã:
Public Sub hell()
Private abc As String
abc = "ag"
MsgBox abc
End Sub

2/biến Static không bị huỷ khi sub/function thoát.
Như vậy mạng sống của biến Static kết thúc khi nào ? xin thầy nói rõ hơn
 
Upvote 0
2/biến Static không bị huỷ khi sub/function thoát.
Như vậy mạng sống của biến Static kết thúc khi nào ? xin thầy nói rõ hơn
Như tôi đã nói ở #6, biến này sẽ giải phóng khi thoát file. Nhưng tất cả các kiểu biến, kể cả Public hay Static đều được giải phóng khi code bị bất cứ lỗi nào nếu không được chỉnh ngay đó mà bấm Stop là coi như tất cả các biến được giải phóng ngay tức thì.
 
Upvote 0
Phạm vi/tầm vực của heap và stack:

Heap là vùng nhớ chung của chương trình. Khi chương trình còn chạy thì những gì nằm trong heap còn tồn tại.

Stack là vùng nhớ riêng của mỗi function/sub. Khi chương đang ở trong function/code thì những gì trong stack còn tồn tại. Khi thoát function/sub thì những gì trong stack (của function/sub này) bị huỷ hết (*).

(*) Để ý ôi dùng từ huỷ. Đó là từ chuyên của LT Hướng Đối Tượng. Đối với các biến đơn giản thì khong quan trọng lắm. Nhưng đối với các biến object thì khá quan trọng. Khi một COM Oject (ví dụ ADO) huỷ, thì nó cũng giải phóng tất cả những tài nguyên mà nó đang khoá (ví dụ ADO sẽ giải phóng các kết nối của nó)
 
Upvote 0
rất cám ơn các bác đã nhiệt tình giúp đỡ nhưng em vẫn chưa thông chỗ này
Mã:
Sub Rectangle1_Click()
Dim a() As String
a = Range("a1:i1").Value
MsgBox a(5)
End Sub



Mã:
Sub Rectangle1_Click()
Dim a() As String
9a = Range("a1:a15").Value
MsgBox a(5)
End Sub

2 đoạn code trên sai ở đâu mà báo lỗi type missmatch, mặc dù 2 vùng dữ liệu đó mình đều đánh chuỗi vào
 
Upvote 0
rất cám ơn các bác đã nhiệt tình giúp đỡ nhưng em vẫn chưa thông chỗ này
Mã:
Sub Rectangle1_Click()
Dim a() As String
a = Range("a1:i1").Value
MsgBox a(5)
End Sub



Mã:
Sub Rectangle1_Click()
Dim a() As String
9a = Range("a1:a15").Value
MsgBox a(5)
End Sub

2 đoạn code trên sai ở đâu mà báo lỗi type missmatch, mặc dù 2 vùng dữ liệu đó mình đều đánh chuỗi vào
Sai quá trời luôn!
1> Range (vùng dữ liệu) nếu đưa vào mảng thì mảng ấy luôn là 2 chiều (trừ trường hợp đặc biệt khi vùng dữ liệu là 1 cell duy nhất)
2> Mảng được tạo thành bằng cách gán từ vùng dữ liệu thì kiểu dữ liệu của mảng chính là kiểu dữ liệu của từng cell trong vùng dữ liệu. Có nghĩa là ta không thể khai báo Dim a() as String được (mà as cái gì cũng không được luôn)
3> Ta chỉ có thể khai báo kiểu dữ liệu cho mảng trong trường hợp mảng ấy do chính ta xây dựng (chèn từng phần tử vào)
Do vậy mà:
1> Mảng a() trong code của bạn sẽ là mảng 2 chiều ---> Dẫn đến MsgBox a(5) là sai cú pháp
2> Dim a() as String cũng sai luôn. Chỉ có thể Dim a() as Variant hoặc Dim a() hoặc Dim a
Sửa lại:
Mã:
Sub Rectangle1_Click()
 [COLOR=#ff0000] Dim a  ''<--- không được khai báo kiểu dữ liệu[/COLOR]
  a = Range("a1:i1").Value
  [COLOR=#ff0000]MsgBox a(1, 5)  [COLOR=#ff0000] ''<--- Mảng 2 chiều[/COLOR][/COLOR]
End Sub
và:
Mã:
Sub Rectangle1_Click()
 [COLOR=#ff0000]Dim a[COLOR=#ff0000]  ''<--- không được khai báo kiểu dữ liệu[/COLOR][/COLOR]
 a = Range("a1:a15").Value
 [COLOR=#ff0000]MsgBox a(5, 1) [COLOR=#ff0000] [COLOR=#ff0000] ''<--- Mảng 2 chiều[/COLOR][/COLOR][/COLOR]
End Sub
 
Upvote 0
Theo gảii tich học căn bản, ta có đường thẳng (1 chiều), mặt phẳng (2 chiều) và khối (3 chiều), và các loại khác chả biết gọi là gì (n chiều)

Excel định nghĩa một range là trường hợp 2, tức là phẳng. Một range luôn luôn có 2 chiều row và column.
Khi bạn copy giá trị của một range ra mảng, VBA dùng một hàm copy. Hàm này mặc định kết quả là mảng 2 chiều.
Các trường hợp đăc biệt gồm có:
1. khi range chỉ gồm 1 cell. VBA tự động biết và không dùng hàm copy mảng, mà dùng hàm copy trị đơn
2. khi bạn dùng hàm Transpose áp dụng vào range chỉ có 1 cột hoặc 1 dòng. VBA dùng loại hàm copy khác, kết quả là mảng 1 chiều. Tuy nhiên ở diễn đàn này bạn khong thấy ai dùng là vì hàm này hay bị quá tải, cho dữ liệu có khi bị cắt bớt.
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom