dạ em copy nguyên trả lời của anh ở page1 ạ, giờ e muốn làm việc thêm với cái multipage mà chưa biết làm thế nào, google vẫn chưa ra ạ, mong anh giúp đỡ, thanks
Thì khai báo bình thường thôi. Chẳng hạn muốn khai báo TextBox2 nằm trên Page2 của MultiPage thì:
Mã:
'...........................
Public WithEvents txtBox2 As MSForms.TextBox
Private Sub Frame1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'..............................
If TypeName(txtBox2) = "Nothing" Then
Set txtBox2 = Sheet1.Frame1.Controls("MultiPage1").Pages(1).Controls("TextBox2")
End If
End Sub
Rồi code sự kiện cũng bình thường luôn, chẳng hạn:
Mã:
Private Sub txtBox2_Change()
Sheet1.Frame1.Controls("MultiPage1").Pages(1).Controls("Label2").Caption = txtBox2.Text
End Sub
anh cho em hỏi thêm là: em có cái button ở ngoài frame, giờ muốn tương tác với cái multipage, em viết như này ko đúng, ko biết lại sửa lại như nào, mong anh chỉ giúp, thanks!
Private Sub reportBtt_Click()
If Sheet1.Frame1.Controls("MultiPage1").Pages(0).Select = True Then Msgbox txtBox1.Value
If Sheet1.Frame1.Controls("MultiPage1").Pages(1).Select = True Then Msgbox txtBox2.Value
End Sub
anh cho em hỏi thêm là: em có cái button ở ngoài frame, giờ muốn tương tác với cái multipage, em viết như này ko đúng, ko biết lại sửa lại như nào, mong anh chỉ giúp, thanks!
Private Sub reportBtt_Click()
If Sheet1.Frame1.Controls("MultiPage1").Pages(0).Select = True Then Msgbox txtBox1.Value
If Sheet1.Frame1.Controls("MultiPage1").Pages(1).Select = True Then Msgbox txtBox2.Value
End Sub
Theo kinh nghiệm thì tôi thấy rằng: Nếu có "New" thì khỏi phải có động tác "Set"
Ví dụ:
Mã:
Sub Test1()
Dim x As New Application
MsgBox x.Sum(3, 2)
End Sub
Nhưng không có "New" thì phải "Set"
Mã:
Sub Test2()
Dim x As Application
Set x = New Application
MsgBox x.Sum(3, 2)
End Sub
Ví dụ khác có "New" thì khỏi "Set"
Mã:
Sub Test1()
Dim x As New Collection
x.Add 1, "1"
x.Add 2, "2"
x.Add 3, "3"
MsgBox x.Count
End Sub
Và không có "New" thì phải "Set"
Mã:
Sub Test2()
Dim x As Collection
Set x = New Collection
x.Add 1, "1"
x.Add 2, "2"
x.Add 3, "3"
MsgBox x.Count
End Sub
Nghe "thiên hạ đồn" rằng Nên dùng "Dim + Set" thì sẽ tốt hơn là "Dim New"
Chẳng biết nữa, thấy cái nào chạy thì mình dùng, cũng chưa đủ trình độ để biết cái nào tốt hơn
Theo kinh nghiệm thì tôi thấy rằng: Nếu có "New" thì khỏi phải có động tác "Set"
Ví dụ:
Mã:
Sub Test1()
Dim x As New Application
MsgBox x.Sum(3, 2)
End Sub
Nhưng không có "New" thì phải "Set"
Mã:
Sub Test2()
Dim x As Application
Set x = New Application
MsgBox x.Sum(3, 2)
End Sub
Ví dụ khác có "New" thì khỏi "Set"
Mã:
Sub Test1()
Dim x As New Collection
x.Add 1, "1"
x.Add 2, "2"
x.Add 3, "3"
MsgBox x.Count
End Sub
Và không có "New" thì phải "Set"
Mã:
Sub Test2()
Dim x As Collection
Set x = New Collection
x.Add 1, "1"
x.Add 2, "2"
x.Add 3, "3"
MsgBox x.Count
End Sub
Nghe "thiên hạ đồn" rằng Nên dùng "Dim + Set" thì sẽ tốt hơn là "Dim New"
Chẳng biết nữa, thấy cái nào chạy thì mình dùng, cũng chưa đủ trình độ để biết cái nào tốt hơn
Thấy cũng vậy thôi mà. Bạn có quyền Dim obj() as Class1 cũng đâu có vấn đề gì. Chỉ là sau đó bạn phải có động tác Set obj() = New Class1
Ví dụ: Tôi có 1 Form gồm 10 CommandButton (nằm trong 1 Frame). Thông thường tôi viết code như sau:
1> Code trong class (tên class là clsEvent)
Mã:
Public WithEvents cmdBtt As MSForms.CommandButton
Private Sub cmdBtt_Click()
MsgBox "Xin chào! Tôi là '" & cmdBtt.Caption & "'"
End Sub
2> Code trong form
Mã:
Dim btt() As New clsEvent
Private Sub UserForm_Initialize()
Dim n As Long, ctr As Control
For Each ctr In Me.Frame1.Controls
n = n + 1
ReDim Preserve btt(1 To n)
Set btt(n).cmdBtt = ctr
Next
End Sub
----------------------------------------
Tuy nhiên, nếu không thích Dim.. New thì tôi cũng có thể viết khác:
Mã:
Dim btt() As clsEvent
Private Sub UserForm_Initialize()
Dim n As Long, ctr As Control
For Each ctr In Me.Frame1.Controls
n = n + 1
ReDim Preserve btt(1 To n)
Set btt(n) = New clsEvent
Set btt(n).cmdBtt = ctr
Next
End Sub
Tóm lại: Không Dim... as New... thì phải có động tác Set... = New....
Đường nào cũng phải.. tới bến và.. ói thôi!
Nhân tiện nói về cái vụ Dim.. as New, tôi có 1 thí nghiệm khá thú vị:
Mã:
Sub Test1()
Dim app As New Application
Set app = Nothing
MsgBox app Is Nothing
End Sub
Sub Test2()
Dim app As Application
Set app = New Application
Set app = Nothing
MsgBox app Is Nothing
End Sub
Mời chạy 2 sub trên và cho biết ý kiến
Xin hỏi với Sub Test1, tôi phải giải phóng đối tượng app bằng cách nào?
Trong thời gian chờ đợi câu trả lời thì tôi cảm thấy... "hình như là" cách viết theo kiểu Sub Test2 sẽ "an toàn" hơn thì phải
(không biết nữa, chỉ đoán)
Code đầu hiện là True, code thứ 2 hiện là False. Khi khai báo với toán tử New thì thực sự đối tượng chưa hề được tạo, chỉ khi ta truy cập mà nó đang là nothing thì nó mới chính thức được tạo. Ngược lại khi không có toàn tử New thì người dùng phải tự tạo đối tượng và gán cho nó. Còn về việc giải phóng thì chắc cứ gán nó thành nothing bình thương, nhưng không truy cập nó nữa là được.
Tôi cũng nghĩ vậy (mới nghĩ)... Trước giờ dùng nhưng không để ý, hôm nay bạn hỏi tự dưng thí nghiệm mới phát hiện vấn đề. Chắc phải thay đổi cách viết code từ đây
Cảm ơn bạn!
Code đầu hiện là True, code thứ 2 hiện là False. Khi khai báo với toán tử New thì thực sự đối tượng chưa hề được tạo, chỉ khi ta truy cập mà nó đang là nothing thì nó mới chính thức được tạo. Ngược lại khi không có toàn tử New thì người dùng phải tự tạo đối tượng và gán cho nó. Còn về việc giải phóng thì chắc cứ gán nó thành nothing bình thương, nhưng không truy cập nó nữa là được.
Đúng là làm vậy thì đối tượng sẽ được giải phóng.
Rắc rối ở chỗ là nếu áp dụng cho trường hợp mảng object, khi em muốn thiết lập một phần tử của mảng về nothing để thông báo rằng phần tử này không có giá trị dùng nữa, và trong tương lại nó có thể được tái dùng lại. Đến lúc muốn dùng lại thì đương nhiên em phải check xem phần tử đó có đang nothing không, lúc đó nó sẽ thành sai.
Chính vì thế nên bỏ dùng New trong khai báo. Lúc đó ta làm chủ được tình hình. Lúc nào cần thì tạo lúc nào thích thì hủy. Ông VBA không còn tự ý làm sau lưng ta nữa.
Theo tôi thì thế này ... Theo tôi bởi tôi không dám cho là mình chắc chắn đúng.
New và khai báo sớm / trễ là hai vấn đề khác nhau.
A. Ta thêm reference "Microsoft Scripting Runtime"
Mã:
Sub test1()
Dim dic As New Scripting.Dictionary
dic.Add "a", 1
MsgBox dic.Item("a")
Set dic = Nothing
MsgBox dic Is Nothing
End Sub
Sub test2()
Dim dic As Scripting.Dictionary
Set dic = CreateObject("Scripting.Dictionary") ' hoac New Scripting.Dictionary
dic.Add "a", 1
MsgBox dic.Item("a")
Set dic = Nothing
MsgBox dic Is Nothing
End Sub
Theo tôi cả 2 trường hợp là kết nối sớm. Kiểu đối tượng được xác định cụ thể, rõ ràng. Kết nối sớm mặc dù trong trường hợp 1 có Dim dic As New Scripting.Dictionary, trường hợp sau không có New. Tức kết nối sớm ở đây chả liên quan gì tới New hay không có New.
Nếu có New thì tại mọi chỗ có truy cập tới dic (vd. dùng phương thức, thuộc tính của đối tượng) thì VBA sẽ kiểm tra dic, nếu = Nothing thì đối tượng sẽ được tạo trước khi thực hiện câu lệnh. Trong trường hợp 2 ta phải tự tạo đối tượng bằng Set dic = ...
B. Không thêm reference "Microsoft Scripting Runtime"
Rõ ràng trong trường hợp này không thể khai báo
Mã:
Dim dic As New Scripting.Dictionary
...
Dim dic As Scripting.Dictionary
Chỉ có thể
Mã:
Sub test3()
Dim dic As Object
Set dic = CreateObject("Scripting.Dictionary")
dic.Add "Nguyen van A", 47
MsgBox dic.Item("Nguyen van A")
Set dic = Nothing
End Sub
Không thể Set dic = New ... Vì New gì?
Trong trường hợp này kiểu đối tượng không được xác định. Chỉ tới khi tạo ra đối tượng mới biết nó là kiểu gì. Trong trường hợp này theo tôi là kết nối trễ.
Và thực chất với khai báo Dim dic As Object thì trong nhiều chỗ của code có thể tạo ra nhiều kiểu đối tượng khác nhau và dùng chúng.
Mã:
Sub test4()
Dim obj As Object
Set obj = CreateObject("Scripting.Dictionary")
obj.Add "Nguyen van A", 47
MsgBox obj.Item("Nguyen van A")
Set obj = Nothing
Set obj = CreateObject("Scripting.FileSystemObject")
MsgBox obj.FileExists("C:\test.txt")
Set obj = Nothing
End Sub
Nếu mà nhắc tới cái chuyện đối tượng tự động được tạo thì không thể không nhắc tới userform. Khi ta unload userform rồi, mà đột ngột ta gọi userform.show thì form lại tự động sống lại ( sự kiện khởi tạo xảy ra). Vậy cho em hỏi hai cái cơ chế này có liên quan gì tới nhau không?