Đúng là bài này em có hỏi và Thầy có làm và liên quan đến VBA.UserForms.Add("UserForm2").Show, nhưng thực sự vì bài đó em quan tâm đến thuật toán, chưa nghĩ đến việc này nên chưa nghiên cứu và ... không nhớ hihihihi.
Em lại thấy mỗi lần có .Add là tạo ra một cái gì đó mới nên cũng ngại đụng vào vì mình chưa biết đầu đuôi ngọn ngành như thế nào, hỏi trước cho chắc ăn.
Để em thử dùng VBA.UserForms.Add("UserForm2") vào bài viết của em xem có được không rồi sẽ tính tiếp vì không biết nó có tính chất như thay thế một form hay không.
Nếu có UserForm1 có TextBox1 và lần lượt các nút lệnh:
Mã:
Private Sub CommandButton1_Click()
VBA.UserForms.Add("UserForm1").Controls("TextBox1").Text = "VBA.UserForms"
End Sub
Private Sub CommandButton2_Click()
UserForm1("TextBox1").Text = "UserForm1"
End Sub
Private Sub CommandButton3_Click()
Me("TextBox1").Text = "ME"
End Sub
Riêng với CommandButton1 là không thực hiện gì, nhưng cũng chẳng báo lỗi.
Khi thoát form, nếu đã bấm CommandButton1 thì dường như nó còn một cái gì đó ẩn ở đâu đó mà mình bấm vào nút Reset trên Toolbar của VBA thì có hiện tượng như là dừng thực thi của một form đang load hay dừng thực thi một thủ tục. Ngược lại, không bấm nút đó thì nó không xảy ra như hiện tượng trên.
Như vậy, dùng VBA.UserForms.Add("UserForm1") vẫn chưa đáp ứng được nhu cầu cần thực hiện.
Nói rõ cái nhu cầu là dùng thủ tục để tác động lên 1 form bất kỳ đang hiện hành, dùng vòng lặp quét qua các TextBox* (với * chạy từ 1 đến 5) vì thế tên của Controls luôn ở dạng chuỗi.
Nếu có UserForm1 có TextBox1 và lần lượt các nút lệnh:
Mã:
Private Sub CommandButton1_Click()
VBA.UserForms.Add("UserForm1").Controls("TextBox1").Text = "VBA.UserForms"
End Sub
Private Sub CommandButton2_Click()
UserForm1("TextBox1").Text = "UserForm1"
End Sub
Private Sub CommandButton3_Click()
Me("TextBox1").Text = "ME"
End Sub
Riêng với CommandButton1 là không thực hiện gì, nhưng cũng chẳng báo lỗi.
Khi thoát form, nếu đã bấm CommandButton1 thì dường như nó còn một cái gì đó ẩn ở đâu đó mà mình bấm vào nút Reset trên Toolbar của VBA thì có hiện tượng như là dừng thực thi của một form đang load hay dừng thực thi một thủ tục. Ngược lại, không bấm nút đó thì nó không xảy ra như hiện tượng trên.
Như vậy, dùng VBA.UserForms.Add("UserForm1") vẫn chưa đáp ứng được nhu cầu cần thực hiện.
Nói rõ cái nhu cầu là dùng thủ tục để tác động lên 1 form bất kỳ đang hiện hành, dùng vòng lặp quét qua các TextBox* (với * chạy từ 1 đến 5) vì thế tên của Controls luôn ở dạng chuỗi.
Vậy khi thực hiện code trong CommandButton1_Click thì UserForm1 đã được load và hiển thị, và nó đã được thêm vào collection "từ đời nào" rồi. Do UserForm1 đã có trong UserForms "từ đời nào" rồi nên khi Nghĩa gọi Add: VBA.UserForms.Add("UserForm1") thì một phiên bản của UserForm1 được load và .Controls("TextBox1").Text = "VBA.UserForms" được thực hiện cho phiên bản này chứ không phải cho phiên bản chính. Mà phiên bản thứ 2 mới chỉ được load chứ chưa hiển thị nên cho dù Text trong TextBox1 đã thay đổi nhưng Nghĩa không nhìn thấy.
Nếu Nghĩa sửa code thành:
Mã:
Private Sub CommandButton1_Click()
With VBA.UserForms.Add("UserForm1")
.Controls("TextBox1").Text = "VBA.UserForms"
' Show để nhìn thấy
.Show
End With
End Sub
Thì Nghĩa sẽ thấy là đúng có phiên bản thứ 2 và TextBox1 của nó được thay đổi.
---------------
Vậy thì khi UserForm đã có trong UserForms thì không dùng ADD mà chỉ ĐỌC ra thôi.
Đọc bằng cách nào? Hóa ra là khi dùng Item thì:
1. Chỉ có thể dùng Index là chỉ số
2. Chỉ số - Index tính từ 0 chứ không phải tính từ 1.
Vậy thì Nghĩa phải viết:
Mã:
Private Sub CommandButton1_Click()
VBA.UserForms.Item(0).Controls("TextBox1").Text = "VBA.UserForms"
' hoặc (do Item là mặc định)
VBA.UserForms(0).Controls("TextBox1").Text = "VBA.UserForms"
End Sub
Nếu Nghĩa muốn dùng TÊN (vd. do có 2 UserForm đã được load mà Nghĩa cứ muốn thao tác với UserForm1) thì tôi nghĩ là phải dùng FOR thôi:
Mã:
Private Sub CommandButton1_Click()
Dim Obj As Object
For Each Obj In VBA.UserForms
If StrComp(Obj.Name, "UserForm1", vbTextCompare) = 0 Then
Obj.Controls("TextBox1").Text = "VBA.UserForms"
Exit For
End If
Next Obj
End Sub
Vậy khi thực hiện code trong CommandButton1_Click thì UserForm1 đã được load và hiển thị, và nó đã được thêm vào collection "từ đời nào" rồi. Do UserForm1 đã có trong UserForms "từ đời nào" rồi nên khi Nghĩa gọi Add: VBA.UserForms.Add("UserForm1") thì một phiên bản của UserForm1 được load và .Controls("TextBox1").Text = "VBA.UserForms" được thực hiện cho phiên bản này chứ không phải cho phiên bản chính. Mà phiên bản thứ 2 mới chỉ được load chứ chưa hiển thị nên cho dù Text trong TextBox1 đã thay đổi nhưng Nghĩa không nhìn thấy.
Nếu Nghĩa sửa code thành:
Mã:
Private Sub CommandButton1_Click()
With VBA.UserForms.Add("UserForm1")
.Controls("TextBox1").Text = "VBA.UserForms"
' Show để nhìn thấy
.Show
End With
End Sub
Thì Nghĩa sẽ thấy là đúng có phiên bản thứ 2 và TextBox1 của nó được thay đổi.
---------------
Vậy thì khi UserForm đã có trong UserForms thì không dùng ADD mà chỉ ĐỌC ra thôi.
Đọc bằng cách nào? Hóa ra là khi dùng Item thì:
1. Chỉ có thể dùng Index là chỉ số
2. Chỉ số - Index tính từ 0 chứ không phải tính từ 1.
Vậy thì Nghĩa phải viết:
Mã:
Private Sub CommandButton1_Click()
VBA.UserForms.Item(0).Controls("TextBox1").Text = "VBA.UserForms"
' hoặc (do Item là mặc định)
VBA.UserForms(0).Controls("TextBox1").Text = "VBA.UserForms"
End Sub
Nếu Nghĩa muốn dùng TÊN (vd. do có 2 UserForm đã được load mà Nghĩa cứ muốn thao tác với UserForm1) thì tôi nghĩ là phải dùng FOR thôi:
Mã:
Private Sub CommandButton1_Click()
Dim Obj As Object
For Each Obj In VBA.UserForms
If StrComp(Obj.Name, "UserForm1", vbTextCompare) = 0 Then
Obj.Controls("TextBox1").Text = "VBA.UserForms"
Exit For
End If
Next Obj
End Sub
Thế bạn không kiểm tra được à? THêm 2 UserForm --> Trên mỗi Form có 1 CommandButton --> Trong CommanButton_Click của mỗi Form code duyệt từ VBA.UserForms(0) tới VBA.UserForms(VBA.UserForms.Count-1) rồi đọc tên của chúng ra --> Click Form1 để active nó --> click Button trên Form --> xem anh nào có index = 0 --> Click Form2 để active nó --> click Button trên Form --> xem anh nào có index = 0
Nhưng cái FOR kia nó có phức tạp đâu mà bạn không muốn dùng?
Thế bạn không kiểm tra được à? THêm 2 UserForm --> Trên mỗi Form có 1 CommandButton --> Trong CommanButton_Click của mỗi Form code duyệt từ VBA.UserForms(0) tới VBA.UserForms(VBA.UserForms.Count-1) rồi đọc tên của chúng ra --> Click Form1 để active nó --> click Button trên Form --> xem anh nào có index = 0 --> Click Form2 để active nó --> click Button trên Form --> xem anh nào có index = 0
Nhưng cái FOR kia nó có phức tạp đâu mà bạn không muốn dùng?