Găp vấn đề Frame trong VBA

Liên hệ QC
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
Cụ thể bạn muốn làm điều gì trên cái multipage này?
 
Em muốn khai báo khởi tạo sự kiện cho textbox, commandbutton trong multipage, giống như trên frame ở trên ấy ạ, thanks
 
Em muốn khai báo khởi tạo sự kiện cho textbox, commandbutton trong multipage, giống như trên frame ở trên ấy ạ, 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
Quan trọng là chỉ rõ "nó nằm ở chỗ nào"
 
em code đc rồi, thanks anh nhiều ạ
 
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
e đã làm được rồi, thanks anh,

Select Case Sheet1.Frame1.Controls("MultiPage1").Value
Case 0
MsgBox "page1"
Case 1
MsgBox "page2"
Case 2
MsgBox "page3"
End Select
 
Anh cho em hỏi sự khác nhau trong câu lệnh trên khi dùng "New" và không dùng "New".
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
 
Trước mình thử bỏ new, hình như ko chạy,
Cái này để gọi cái funtion ở trong class1 ra
Bình thường nó là một mảng ojbject ( class1)
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


Nếu chỉ là object thì em hiều, em hỏi là cái chuyện dùng toán tử new khi khai báo một mảng động đối tượng cơ.

dim obj() as new class1
 
Bình thường nó là một mảng ojbject ( class1)



Nếu chỉ là object thì em hiều, em hỏi là cái chuyện dùng toán tử new khi khai báo một mảng động đối tượng cơ.

dim obj() as new class1
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!
 

File đính kèm

  • Class_CmdWasClicked.xlsm
    23 KB · Đọc: 8
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.

hình như là" cách viết theo kiểu Sub Test2 sẽ "an toàn" hơn thì phả

Cách viết dùng New sẽ nguy hiểm hơn, nhiều khi muốn nó về nothing mà nó không chịu về.
 
Cách viết dùng New sẽ nguy hiểm hơn, nhiều khi muốn nó về nothing mà nó không chịu về.
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.
Chíng xác.

Có sự khác nhau giữa (New + không có Set) và không có (New + Set)
1.
Mã:
Dim obj As myClass   ' Object
Set obj = New myClass
Set obj = Nothing
MsgBox obj Is Nothing
Với code như thế thì VBA không tạo đối tượng mà bạn phải tự lực hết. Khi nào cần dùng obj thì phải tạo - Set obj = New myClass ' = CreateObject(...)
Khi nào thích thì giải phóng - Set obj = Nothing. Nếu trong đoạn code tiếp theo muốn dùng nữa thì lại phải tự tạo - Set obj = ...
2.
Mã:
Dim obj As New myClass
Set obj = Nothing
MsgBox obj Is Nothing
Thực ra dòng Set obj = Nothing là thừa vì ở thời điểm đó thì obj = Nothing. Vì sao? Ta xét code khác.
Mã:
Dim obj As New myClass
obj.HoTen = "Nguyen Van A"   ' (A)
Set obj = Nothing       ' (B)
MsgBox obj Is Nothing   ' (C)
Khi ta khai báo biến obj thì chả có đối tượng nào được tạo. Nhưng đã khai báo thế thì VBA vào cuộc. Tức ở mọi chỗ, không chỉ riêng chỗ đầu tiên, khi code truy cập tới đối tượng obj thì VBA sẽ kiểm tra xem obj có <> Nothing không. Nếu obj = Nothing thì VBA sẽ tạo đối tượng trước khi thực hiện câu lệnh của code.
Trước khi thực hiện câu lệnh (A) VBA kiểm tra thấy obj = Nothing, vậy nên nó tạo đối tượng, tiếp theo câu lệnh (A) được thực hiện trên đối tượng vừa tạo. Câu lệnh (B) chắc chắn 300% hủy đối tượng obj. Nhưng trước khi thực hiện câu lệnh (C) thì VBA lại kiểm tra thấy là obj = Nothing nên nó lại tạo đối tượng rồi sau đó mới thực hiện (C) trên đối tượng vừa tạo.
Không phải là (B) không hủy đối tượng. Chắc chắn (B) hủy đối tượng, nhưng "obj Is Nothing" = False bởi vì VBA trước khi thực hiện (C) đã kiểm tra thấy obj = Nothing nên tạo đối tượng, sau đó mới thực hiện (C). Rõ ràng khi thực hiện (C) thì obj <> Nothing.


Cách viết dùng New sẽ nguy hiểm hơn, nhiều khi muốn nó về nothing mà nó không chịu về.
Nó ngoan ngoãn về Nothing. Chỉ có điều sau khi Set ... = Nothing thì đừng truy cập tới nó nữa. Bởi nếu truy cập thì VBA lại tạo lại đối tượng, do đang là Nothing, để có thể thực hiện câu lệnh.
 
Chỉ có điều sau khi Set ... = Nothing thì đừng truy cập tới nó nữa

Đú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.
 
Sự khác nhau giữa (1) và (2) thì liên hệ như nào với khái niệm kiểu khai báo kết nối sớm (1') và kiểu khai báo kết nối trễ (2') hả anh?
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
Trong trường hợp A kiểu đối tượng là rõ ràng, có tạo nhiều đối tượng thì luôn phải có kiểu cụ thể đó.
 
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?
 
Web KT
Back
Top Bottom