Đố vui về VBA! (2 người xem)

Liên hệ QC

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

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,912
Nhằm cũng cố kiến thức về VBA cho các bạn mới bắt đầu và cả những bạn đang ứng dụng mà chưa hiểu nhiều về nó, tôi mở topic này với mong mõi qua những câu hỏi vui, các bạn sẽ nhận định lại sự hiểu biết cũa mình... (Kễ cã chính tôi cũng đang tập tành nên có rất nhiều cái chưa biết)
Mong rằng topic sẽ mang đến cho các bạn những khám phá thú vị với những cái tưỡng chừng như đã biết
Mong nhận dc bài viết về câu đố cũa các cao thủ! Còn các bạn mới thì đừng ngại khi đưa ra ý kiến cũa mình.. Có sai có sữa sẽ hoàn thiện!
Tôi xin mỡ màn trước bằng 1 câu hỏi đơn giãn
ANH TUẤN

CÂU HỎI 1: Tại sao biến K ko hoạt động?
Tôi muốn khi nhấn vào 1 button thì cell A1 sẽ tăng lên 1 đơn vị... Tôi đã làm như sau:
-Tạo 1 Command Button (nút nhấn thuộc thanh Control Toolbox), click phải chuột lên nút nhấn, chọn View code, rồi gõ vào đoạn code sau:
PHP:
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
Ban đầu K chưa có gì, xem như =0, nhấn nút lần thứ nhất thì K dc tăng thêm 1, vậy K hiện tại sẽ bằng 1, và gán K vào cell A1 thì đương nhiên A1 sẽ =1... Nhấn nút lần 2, K lại dc tăng thêm 1 nên hiện tại K sẽ =2 và cell A1 cũng sẽ =2... vân vân.. từ đó diễn tiến tiếp...
Hi.. hi.. Điều này nghe qua có vẽ rất hợp lý, ấy thế mà khi nhấn nút nó chỉ hoạt động dc duy nhất 1 lần (A1 = 1) rồi thôi ko nhút nhít nữa...
Các bạn có thể giãi thích tại sao lại như thế ko? Tại sao những lần nhấn nút sau đó K lại ko tăng thêm tí nào (vì thực tế A1 vẫn cứ = 1 hoài) ?
ANH TUẤN
 
Cách của em là vào Properties --> Font -->Script Vietnamese mà sao chỉ đúng với unicode tổ hợp còn unicode dựng sẵn bị lỗi (test ở máy em)
Anh cài Script Vietnamese, sau đó mã hóa font cho chúng thành font CP 1258 bằng sự kiện Lost_Focus mà chúng mã hóa thành chữ quái quỷ gì đâu không à! Nhưng trong khi mình thử nhập nguồn bằng font VNI và định dạng font của nó cũng là font VNI thì nó lại hiển thị tiếng Việt mới ghê! Trong khi cái thuộc tính Text và Value của nó cũng là những chữ "quái quỷ"! Lạ thật, phải chi UNI lại xài được như VNI nhỉ!
 
Upvote 0
Với ComboBox trên Sheet (hay ActiveX controls nói chung) thì việc hiển thị tiếng Việt Unicode thật sự có vấn đề:
- Khi ta bấm mũi tên xổ xuống của ComboBox, ta nhìn thấy tiếng Việt Unicode hiển thị rất tốt:

- Nhưng ngay khi chọn xong 1 Item rồi click chuột vào đâu đó trên bảng tính thì lập tức những ký tự có dấu bị biến thành dấu ?

Xin hỏi các bạn: Dùng cách gì để khắc phục tình trạng này? Tức có thể hiển thị tiếng Việt Unicode trên ComboBox trong mọi lúc
Câu hỏi này tuy là đố vui nhưng ứng dụng thiết thực đây

Thầy iu, em chơi tiểu xảo được không?

Trong Module của Sheet1:
Mã:
Option Explicit

Private Sub ComboBox1_GotFocus()
    Sheet1.Shapes("Rectangle 1").Visible = msoFalse
End Sub

Private Sub ComboBox1_LostFocus()
    With Sheet1.Shapes("Rectangle 1")
        .TextFrame.Characters.Text = ComboBox1
        .Visible = msoTrue
    End With
End Sub

[COLOR=#008000]'Gan macro nay cho Shape:[/COLOR]
Sub HideShape()
    Sheet1.Shapes(Application.Caller).Visible = msoFalse
    Sheet1.ComboBox1.Activate
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Thầy iu, em chơi tiểu xảo được không?

Trong Module của Sheet1:
Mã:
Option Explicit

Private Sub ComboBox1_GotFocus()
    Sheet1.Shapes("Rectangle 1").Visible = msoFalse
End Sub

Private Sub ComboBox1_LostFocus()
    With Sheet1.Shapes("Rectangle 1")
        .TextFrame.Characters.Text = ComboBox1
        .Visible = msoTrue
    End With
End Sub

[COLOR=#008000]'Gan macro nay cho Shape:[/COLOR]
Sub HideShape()
    Sheet1.Shapes(Application.Caller).Visible = msoFalse
    Sheet1.ComboBox1.Activate
End Sub
Cách này thì đúng là... Ẹc... Ẹc...
Thôi, gợi ý luôn. Thật ra nó khá đơn giản: Hãy cho ComboBox vào trong 1 Frame. Xong!
 
Upvote 0
Cách này thì đúng là... Ẹc... Ẹc...
Thôi, gợi ý luôn. Thật ra nó khá đơn giản: Hãy cho ComboBox vào trong 1 Frame. Xong!
Hay! Tuyệt vời, mặc dù Thầy gợi ý, nhưng khá vất vã để được nó trong Frame đấy! Đúng là Thầy mình quái kiệt mà!
 
Upvote 0
Upvote 0
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Nếu là Thầy thì Thầy có dùng Class không?
Hỏi hay ghê hen!
"Nếu là thầy" thì thầy sẽ... hổng nói, cứ để cho "trò" tự nghiên cứu
Mà dùng gì chẳng được, miễn đạt được mục đích
Ẹc... Ẹc...
--------------------
cái anh nói ko biết có kèm theo cái này ko???
[video=facebook;555533051186290]https://www.facebook.com/photo.php?v=555533051186290&saved[/video]
CÁI NÀY là CÁI GÌ vậy?
 
Upvote 0
Hỏi hay ghê hen!
"Nếu là thầy" thì thầy sẽ... hổng nói, cứ để cho "trò" tự nghiên cứu
Mà dùng gì chẳng được, miễn đạt được mục đích
Ẹc... Ẹc...
--------------------

Tại Module của Sheet1:

Những dòng trên cùng:

[GPECODE=vb]
Option Explicit
Public WithEvents Frame1_ComboBox1 As MSForms.ComboBox
[/GPECODE]

Tạo sự kiện Active & DeActive cho Sheet1:

[GPECODE=vb]
Private Sub Worksheet_Activate()
Set Frame1_ComboBox1 = Sheet1.Frame1.Controls("ComboBox1")
End Sub
[/GPECODE]

[GPECODE=vb]
Private Sub Worksheet_Deactivate()
Set Frame1_ComboBox1 = Nothing
End Sub
[/GPECODE]

Và sự kiện Change của Combobox1:

[GPECODE=vb]
Private Sub Frame1_ComboBox1_Change()
MsgBox Frame1_ComboBox1.Text
End Sub
[/GPECODE]

OK chưa Thầy iu!
 
Upvote 0

Giải thuật thì được rồi nhưng nghĩ xem cách khởi tạo sự kiện đã ổn chưa? File của tôi chỉ có 1 sheet thôi thì sao?
 
Upvote 0
cái anh nói ko biết có kèm theo cái này ko???
[video=facebook;555533051186290]https://www.facebook.com/photo.php?v=555533051186290&saved[/video]
Đối tượng Combobox của bạn trong video này là đối tượng ở trên Userform, nhưng nó là một ActiveX Control, đặt trên Form thì không vấn đề gì rồi, nhưng bạn thử chèn nó lên Sheet xem nào. Lưu ý khi chèn trên Sheet có 2 loại đối tượng ComboBox đấy nhé, 1 cái thuộc Form Controls, 1 cái thuộc ActiveX Controls. Trong video trước của bạn tại bài #897 là ComboBox của Form Controls, mà với cái này thì cứ để thiết lập mặc định của Windows cũng hiển thị được tiếng Việt Unicode.
 
Upvote 0

File đính kèm

Upvote 0
Giải thuật thì được rồi nhưng nghĩ xem cách khởi tạo sự kiện đã ổn chưa? File của tôi chỉ có 1 sheet thôi thì sao?

ThisWorkbook Module:

[GPECODE=vb]
Option Explicit


Private Sub Workbook_Open()
Sheet1.CreateFrameControlEvent
End Sub


Private Sub Workbook_BeforeClose(Cancel As Boolean)
Sheet1.EraseFrameControlEvent
End Sub


[/GPECODE]

Sheet Module:

[GPECODE=vb]
Option Explicit
Public WithEvents Frame1_ComboBox1 As MSForms.ComboBox
Public WithEvents Frame1_CommandButton1 As MSForms.CommandButton


Sub CreateFrameControlEvent()
Set Frame1_ComboBox1 = Sheet1.Frame1.Controls("ComboBox1")
End Sub


Sub EraseFrameControlEvent()
Set Frame1_ComboBox1 = Nothing
End Sub


Private Sub Frame1_ComboBox1_Change()
MsgBox Frame1_ComboBox1.Text
End Sub
[/GPECODE]

Dễ ùm đó Thầy iu! Cái quan trọng là ta đã biết nó là gì, giải thuật là như thế nào, còn sắp xếp sao cho hợp lý với file của mình thì rất ẹc ... ẹc ...
 
Upvote 0
Là cái quỷ này:
https://www.facebook.com/photo.php?v=555533051186290&saved

Nhưng đó là form. Ndu đang nói trên sheet.
May quá! Máy em hổng vào được Facebook và em cũng không có ý định tìm cách để vào
Ẹc... Ẹc...


Có ý tưởng rồi thì không khó nữa.
Cái của sư phụ là CHƠI ĂN GIAN nha! Đó không phải là cách giải quyết vấn đề triệt để!
Nếu như cho ComboBox vào 1 Frame thì lại khác à nha: Nó hiện tiếng Việt Unicode trong mọi trường hợp luôn
 
Upvote 0
Cái của sư phụ là CHƠI ĂN GIAN nha! Đó không phải là cách giải quyết vấn đề triệt để!
Nếu như cho ComboBox vào 1 Frame thì lại khác à nha: Nó hiện tiếng Việt Unicode trong mọi trường hợp luôn

Vậy chớ frame là kí rì?
Với lại xài như vậy thì thiếu trường hợp nào?
 
Upvote 0
Dễ ùm đó Thầy iu! Cái quan trọng là ta đã biết nó là gì, giải thuật là như thế nào, còn sắp xếp sao cho hợp lý với file của mình thì rất ẹc ... ẹc ...

Ừ thì dễ! Nhưng code dài quá. Tôi làm bài này đúng 10 dòng code và chỉ gọn trong sheet1
Như thế này:
Mã:
Public WithEvents cbox As MSForms.ComboBox
Private Sub cbox_Click()
  Sheet1.Frame1.Controls("TextBox1").Text = cbox.Text
End Sub
Private Sub Frame1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  If TypeName(cbox) = "Nothing" Then
    Set cbox = Sheet1.Frame1.Controls("ComboBox1")
    cbox.List() = Sheet1.Range("A1:A10").Value
  End If
End Sub
Với Range("A1:A10") là dữ liệu và Frame có chứa TextBox1
Mục đích của Frame1_MouseMove là để phòng ngừa code bị lỗi sẽ dùng nó khởi tạo lại sự kiện
-----------------------
Với lại xài như vậy thì thiếu trường hợp nào?
Sư phụ đừng ẩn ComboBox thì sẽ thấy text trong đó bị mã hóa thành dấu ? hết
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
xin lổi các thầy, người ngoài tham gia được ko ạh,

nếu làm trên sheet, thì đây cách tui hay trốn combobox, bằng cách xuất thẳng ra sheet luôn
 

File đính kèm

Upvote 0
xin lổi các thầy, người ngoài tham gia được ko ạh,

nếu làm trên sheet, thì đây cách tui hay trốn combobox, bằng cách xuất thẳng ra sheet luôn

Mình đâu có hỏi cái chuyện xuất ra sheet đâu! Đương nhiên khi xuất ra sheet thì dữ liệu được bảo toàn rồi (tiếng Việt vẫn là tiếng Việt)
Vấn đề ở đây là khi click chuột vào 1 cell, nhìn lại text trên ComboBox cảm thấy rất... ghét ---> Bạn tự nhìn vào cái ComboBox của mình đi
 
Upvote 0
Ừ thì dễ! Nhưng code dài quá. Tôi làm bài này đúng 10 dòng code và chỉ gọn trong sheet1

Mục đích của Frame1_MouseMove là để phòng ngừa code bị lỗi sẽ dùng nó khởi tạo lại sự kiện
-----------------------

Lúc đầu em cũng tính làm vậy, nhưng em lại định kích cỡ cho Frame bằng với Combobox cho không ai nhận ra có sự tồn tại của nó; nhưng làm vậy thì không chạy được sự kiện MouseMove của Frame!

Theo em nghĩ nha, em có cảm giác là một khi sử dụng sự kiện MouseMove thì y như rằng nó đang xài Do ... DoEvents ... Loop và như thế nó cứ chạy code liên tục vậy ạ!
 
Upvote 0
Lúc đầu em cũng tính làm vậy, nhưng em lại định kích cỡ cho Frame bằng với Combobox cho không ai nhận ra có sự tồn tại của nó; nhưng làm vậy thì không chạy được sự kiện MouseMove của Frame!
Thì cũng đúng! Vậy tùy trường hợp mà chọn lựa thôi


Theo em nghĩ nha, em có cảm giác là một khi sử dụng sự kiện MouseMove thì y như rằng nó đang xài Do ... DoEvents ... Loop và như thế nó cứ chạy code liên tục vậy ạ!
Chính vì sợ nó chạy liên tục nên tôi có đoạn If TypeName(cbox) = "Nothing" Then rồi đó. Bảo đảm chỉ chạy 1 lần
(không tin có thể dùng MsgBox đặt trong If để thử)
Vậy: Khi nào code gì đó bị lỗi thì cbox sẽ = Nothing và sự kiện MouseMove sẽ tự khởi tạo lại nó
------------------
Mà công nhận chú Nghĩa này tiếp cận vấn đề nhanh ghê! Gợi ý 1 chút đã làm trúng phốc!
Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Thì cũng đúng! Vậy tùy trường hợp mà chọn lựa thôi



Chính vì sợ nó chạy liên tục nên tôi có đoạn If TypeName(cbox) = "Nothing" Then rồi đó. Bảo đảm chỉ chạy 1 lần
(không tin có thể dùng MsgBox đặt trong If để thử)
Vậy: Khi nào code gì đó bị lỗi thì cbox sẽ = Nothing và sự kiện MouseMove sẽ tự khởi tạo lại nó
------------------
Mà công nhận chú Nghĩa này tiếp cận vấn đề nhanh ghê! Gợi ý 1 chút đã làm trúng phốc!
Ẹc... Ẹc...


Em nhìn thấy code Thầy chứ! Tuy nhiên Thầy đặt con trỏ vào frame rồi để y đó, không cần rê đi đâu hết, Thầy sẽ thấy màn hình nó chớp chớp nhanh liên tục và dung lượng máy tăng lên thấy rõ rệt (theo máy em); Thầy thử test xem sao!
 
Upvote 0
Em có cảm giác thế này, mà hình như là đúng: Việc ta vẽ lên sheet 1 cái Frame rồi đặt Combobox lên đó thì ComboBox hiển thị được tiếng Việt Unicode, cũng giống như đặt ComboBox này lên trên Form vậy. Như vậy cái Frame này đóng vai trò như một "điểm tựa" cho anh ComboBox đặt chân. Từ đó có thể suy ra rằng ta có thể thay Frame bởi MultiPage cũng được.
 
Upvote 0
Em nhìn thấy code Thầy chứ! Tuy nhiên Thầy đặt con trỏ vào frame rồi để y đó, không cần rê đi đâu hết, Thầy sẽ thấy màn hình nó chớp chớp nhanh liên tục và dung lượng máy tăng lên thấy rõ rệt (theo máy em); Thầy thử test xem sao!
Thì cũng giống như khi ta dùng sự kiện Change hoặc SelectionChange thôi. Dù ta đã "rào" bằng dòng lệnh If Target.Address = ... hoặc If Not Intersect(....).... gì gì đó thì code sự kiện nó vẫn có công đoạn kiểm tra vậy? Kiểm tra đúng điều kiện thì nó làm, không thì... nghỉ
Vậy chẳng lẽ vì sợ cái vụ kiểm tra ấy mà ta nghỉ xài Change và SelectionChange?
---------------------------
Còn cái vụ chớp chớp giật giật gì đó thì máy tôi không bị, CPU trong Task Manager cũng không tăng (cần quay phim màn hình để chứng minh không?)
---> Suy ra: Máy Nghĩa cùi bắp? Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Còn cái vụ chớp chớp giật giật gì đó thì máy tôi không bị, CPU trong Task Manager cũng không tăng (cần quay phim màn hình để chứng minh không?)
---> Suy ra: Máy Nghĩa cùi bắp? Ẹc... Ẹc...
Hehehehe, đâu có cùi bắp lắm đâu! Mua từ năm 2009 tới giờ, chỉ mỗi thay bàn phím thôi!
 
Upvote 0
Ừ thì dễ! Nhưng code dài quá. Tôi làm bài này đúng 10 dòng code và chỉ gọn trong sheet1
Tải file về xem cả buổi mà chẳng hiểu cách làm thế nào để ra được như thế. Hic, tạm thời lưu file khi nào cần thì cứ đem ra xào nấu lại. Em nghĩ chắc cũng có người giống em thôi. Nếu không phải thì chắc là mình thuộc dạng .... nhất.

Cái vụ chớp màn hình gì đó thì máy tính mình cũng không bị. Anh Nghĩa thay máy tính đi nha
 
Upvote 0
Cái vụ chớp màn hình gì đó thì máy tính mình cũng không bị. Anh Nghĩa thay máy tính đi nha

Nó chớp rất nhẹ chứ không phải giật giật, ở trên Window Caption đấy, không chớp trong sheet đâu! Window7 cái caption nó gần như trong suốt nên dễ nhận ra điều này.

Còn đây là "hàng" của mình đây! Làm theo hướng MouseMove (canh rất chuẩn mới không thấy "em" Frame)! Xài bằng RowSource nên không Add List!

[GPECODE=vb]
Option Explicit
Private WithEvents Fra1Cbx1 As MSForms.ComboBox
Private IsCheck As Boolean


''---------------------------------------------------
'' New version!
''---------------------------------------------------
Private Sub Frame1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If IsCheck Then Exit Sub
Set Fra1Cbx1 = Sheet1.Frame1.Controls("ComboBox1")
IsCheck = True
End Sub


Private Sub Fra1Cbx1_Change()
MsgBox Fra1Cbx1
End Sub[/GPECODE]
 

File đính kèm

Upvote 0
Đối tượng Combobox của bạn trong video này là đối tượng ở trên Userform, nhưng nó là một ActiveX Control, đặt trên Form thì không vấn đề gì rồi, nhưng bạn thử chèn nó lên Sheet xem nào. Lưu ý khi chèn trên Sheet có 2 loại đối tượng ComboBox đấy nhé, 1 cái thuộc Form Controls, 1 cái thuộc ActiveX Controls. Trong video trước của bạn tại bài #897 là ComboBox của Form Controls, mà với cái này thì cứ để thiết lập mặc định của Windows cũng hiển thị được tiếng Việt Unicode.
cái Anh hỏi là cái này chắc ko sai chứ ???? đưa file lên Youtube nó cứ đòi đợi xử lý lâu quá
[video=youtube;M7wvk_utY9g]http://www.youtube.com/watch?v=M7wvk_utY9g[/video]
 
Lần chỉnh sửa cuối:
Upvote 0
- Vẽ cái Frame
- Click chuột phải vào đó, chọn Frame Object --> Edit
- Tự nhiên sẽ thấy và.. biết liền
Bổ sung nha:

1) Vẽ Frame:

Mặc định là trong hộp ActiveX Controls là không có anh này rồi đó!

Vẽ tại đâu?

Bấm vào nút More Controls (cái biểu tượng cái búa và cái khóa chéo nhau).

Sau khi hộp More Controls hiện ra, chọn vào mục Microsoft Form 2.0 Frame, rồi OK, sau đó ta vẽ trên sheet cái Frame này.

2) Add Controls lên Frame:

Trong chế độ Design, Click phải chuột vào Frame, chọn Frame Objects > Edit

Lúc này ta sẽ có được một ToolBox để add vào Frame.

3) Tạo thuộc tính cho Controls:

Click phải vào control, lúc này có một menu hoàn toàn xa lạ, kệ nó, ta chọn vào mục Properties của nó.

Lưu ý, cái Properties này nó cũng khác với các Properties ta vẫn thường thấy, đó là ta chọn một thuộc tính bất kỳ trong đó, thì nó sẽ hiện giá trị lên trên một Combobox ở trên cùng, muốn thay đổi gì thì thay đổi tại ComboBox đó rồi bấm nút Apply.

4) Bước này là tạo sự kiện cho nó, tạo như thế nào thì đã có các bài nói về chúng rồi, mình không nói lại nữa.
 

File đính kèm

  • MoreCtrl.jpg
    MoreCtrl.jpg
    51.8 KB · Đọc: 78
Upvote 0
Mã:
Private Sub Frame1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  If TypeName(cbox) = "Nothing" Then
    Set cbox = Sheet1.Frame1.Controls("ComboBox1")
    cbox.List() = Sheet1.Range("A1:A10").Value
  End If
End Sub

Với code trên, theo em nghĩ nó vẫn chưa tối ưu. Khi một code bị lỗi, ngay lập tức TẤT CẢ CÁC BIẾN sẽ giải phóng bộ nhớ hoàn toàn và trả về dạng mặc định của chúng (kể cả biến boolean cũng sẽ trả về dạng False). Vì thế việc Set lại cbox là hoàn toàn hợp lý. Nhưng việc nạp lại List cho cbox thì thừa là vì dù cho có lỗi cách nào đi chăng nữa thì List của nó không thay đổi, có nghĩa là list của nó không tự clear, cho nên ta mỗi lần Set là mỗi lần nạp list sẽ không hay. Nếu dữ liệu ngần ấy thì chả nói gì, còn như dữ liệu vài chục ngàn dòng, sau đó Filter, tính toán, Unique v.v... rồi mới tạo ra một cái Array để gán vào thì hơi ẹc ẹc ...

Theo em thì nên làm như vầy:

Mã:
Private Sub Frame1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If TypeName(cbox) = "Nothing" Then
        With Frame1.Controls("ComboBox1")
[B][COLOR=#0000ff]            If .ListCount = 0 Then .List = Range("A1:A10").Value[/COLOR][/B]
        End With
        Set cbox= Frame1.Controls("ComboBox1")
    End If
End Sub

Có như vậy thì ta chỉ việc Set cho cbox thôi mà không cần phải nạp lại list một lần nào nữa!
 
Lần chỉnh sửa cuối:
Upvote 0
Trong Help có nói:

Join Function

Description

Returns a string created by joining a number of substrings contained in an array.

Syntax:

Join(sourcearray[, delimiter])

sourcearray: Required. One-dimensional array containing substrings to be joined.

delimiter: Optional. String character used to separate the substrings in the returned string. If omitted, the space character (" ") is used. If delimiter is a zero-length string (""), all items in the list are concatenated with no delimiters.

Như vậy hàm Join là một hàm tách thành một chuỗi từ một mảng một chiều, cách thực hiện:

Phần tử trong mảng là dạng chuỗi:

Mã:
Sub Macro8()
    Dim Arr()
    Arr = Array([COLOR=#0000ff]"Giai", "phap", "Excel", ".", "com"[/COLOR])
    MsgBox [COLOR=#ff0000]Join(Arr, "")[/COLOR]
End Sub

Phần tử trong mảng là dạng số:

Mã:
Sub Macro9()
    Dim Arr()
    Arr = Array([COLOR=#0000ff]1, 2, 3, 4, 5[/COLOR])
    MsgBox [COLOR=#ff0000]Join(Arr, ", ")[/COLOR]
End Sub


Câu đố đặt ra, Nếu thực hiện đúng cấu trúc, thì khi nào hàm Join sẽ bị lỗi?

Chắc có lẽ không ai thèm trả lời câu hỏi này, vậy mình "tự sướng" luôn! (tự sướng nên chả thú vị gì cả).

Các kiểu khai báo mảng thuộc kiểu String, Variant, hoặc không khai báo loại nào đều không phát sinh lỗi:

Mã:
Sub Test1()
    Dim i As Byte
    Dim Arr(0 To 9)
    Dim sArr(0 To 9) As String
    Dim vArray(0 To 9) As Variant
    For i = 0 To 9
        Arr(i) = i
        sArr(i) = i
        vArray(i) = i
    Next
    MsgBox Join(Arr, ",")
    MsgBox Join(sArr, ",")
    MsgBox Join(vArray, ",")
End Sub

Nhưng những dạng khai báo là kiểu Numeric (Byte, Long, Double, Date, v.v...) thì sẽ bị "dính chưởng"!

Mã:
Sub Test2()
    Dim i As Byte
    [COLOR=#008000]'Tat ca bien kieu Numeric deu bi loi:[/COLOR]
    [B][COLOR=#0000cd]Dim Arr(0 To 9) As Long [/COLOR][COLOR=#008000]' Integer, Byte, Double, Currency, Date v.v...[/COLOR][/B][COLOR=#0000cd][/COLOR]
    For i = 0 To 9
        Arr(i) = i
    Next
    MsgBox Join(Arr, ",")
End Sub

Vì thế, khi thực hiện hàm Join thì người lập trình phải luôn luôn nằm lòng vấn đề này để mà tránh vì đôi khi mình đã làm đúng với cấu trúc rồi, nhưng tại sao lại phát sinh lỗi thì là do "kiểu nó như thế".
 
Upvote 0
Nhưng những dạng khai báo là kiểu Numeric (Byte, Long, Double, Date, v.v...) thì sẽ bị "dính chưởng"!

Mã:
Sub Test2()
    Dim i As Byte
    [COLOR=#008000]'Tat ca bien kieu Numeric deu bi loi:[/COLOR]
    [B][COLOR=#0000cd]Dim Arr(0 To 9) As Long [/COLOR][COLOR=#008000]' Integer, Byte, Double, Currency, Date v.v...[/COLOR][/B]
    For i = 0 To 9
        Arr(i) = i
    Next
    MsgBox Join(Arr, ",")
End Sub

Vì thế, khi thực hiện hàm Join thì người lập trình phải luôn luôn nằm lòng vấn đề này để mà tránh vì đôi khi mình đã làm đúng với cấu trúc rồi, nhưng tại sao lại phát sinh lỗi thì là do "kiểu nó như thế".

Bạn căn cứ vào đâu để nghĩ rằng: "vì đôi khi mình đã làm đúng với cấu trúc rồi"?. Bạn lấy cái gì ra làm chuẩn, tiêu chí nào để nghĩ là mình làm đúng?.

Người lập trình nào cũng phải đọc help. Dù là ngôn ngữ nào. Không chịu đọc help thì quên luôn chuyện lập trình đi.
Mà đọc help thì phải tìm mọi cách để hiểu. Có người cũng đọc help nhưng cóc hiểu hoặc không hiểu chính xác, không hiểu hết.

Bạn đã đọc về hàm Join trong VBA. Help nói với tôi:

Mã:
Join Function 

Description

Returns a string created by joining a number of [B][COLOR=#ff0000]substrings contained in an array[/COLOR][/B].

Syntax

Join(sourcearray[, delimiter])

The Join function syntax has these named arguments:

Part Description 
sourcearray Required. One-dimensional [B][COLOR=#ff0000]array containing substrings[/COLOR][/B] to be joined. 
delimiter Optional. String character used to separate the substrings in the returned string. If omitted, the space character (" ") is used. If delimiter is a zero-length string (""), all items in the list are concatenated with no delimiters.

Chỗ đỏ đỏ nói là tất cả những phần tử của cái Array kia đều là STRING. Nếu bạn tạo Array mà các phần tử là Numeric rồi bạn bắt Join làm việc thì đâu phải là bạn "đã làm đúng"? Rõ ràng bạn đã làm sai.

Bạn mặc váy cho cậu bé, ấn vào tay nó con búp bê rồi bắt nó chơi "mẹ ru con" mà bạn nghĩ là bạn làm đúng? he he
 
Upvote 0
Bạn căn cứ vào đâu để nghĩ rằng: "vì đôi khi mình đã làm đúng với cấu trúc rồi"?. Bạn lấy cái gì ra làm chuẩn, tiêu chí nào để nghĩ là mình làm đúng?.
Mã:
Returns a string created by joining a number of [B][COLOR=#ff0000]substrings contained in an array[/COLOR][/B].

Theo em câu trên dịch là:

Mã:
Trả về một chuỗi được tạo ra bằng cách kết hợp (tham gia) [COLOR=#ff0000][B]một số chuỗi con chứa trong một mảng[/B][/COLOR]

Theo em hiểu, khi hàm xử lý chuỗi, chuyển từ một chuỗi hay một số, thì việc trả kết quả về là một dạng chuỗi hoặc số trong dạng chuỗi.

Chẳng hạn:

Mã:
[COLOR=#0000cd]?ucase(1)[/COLOR]
[COLOR=#0000cd]1[/COLOR]
[COLOR=#ff0000]?ucase("1")[/COLOR]
[COLOR=#ff0000]1[/COLOR]

Trường hợp xanh là dạng số cũng trả kết quả là 1 và trường hợp đỏ là dạng số trong chuỗi, cũng trả kết quả là 1

Thêm nữa, 2 trường hợp mảng này, một dạng là số và một dạng số trong dạng chuỗi thì hàm Join vẫn cho ra kết quả:

Mã:
Sub Macro1()
    Dim Arr()
    Arr = Array(1, 2, 3, 4, 5)
    MsgBox Join(Arr, ", ")
End Sub

Sub Macro2()
    Dim Arr()
    Arr = Array("1", "2", "3", "4", "5")
    MsgBox Join(Arr, ", ")
End Sub

vậy cái Substring (chuỗi con) đâu nhất thiết phải là một chuỗi hay một số?

Và thủ tục này, i là biến kiểu Byte, nếu một biến X nào đó (không để kiểu) mà bằng i (X = i) thì X chính là dạng Byte, điều này ai cũng biết. Thế thì:

Mã:
Sub Test()
    Dim i As Byte
    Dim Arr(0 To 9)
    For i = 0 To 9
        Arr(i) = i
    Next
[B][COLOR=#0000ff]    MsgBox TypeName(Arr(1))[/COLOR][/B]
[COLOR=#ff0000][B]    MsgBox Join(Arr, ",")[/B][/COLOR]
End Sub

Nhưng Byte thì Byte hàm JOIN vẫn "xơi" tuốt luốt, không bị "mắc xương"!

Thêm nữa, trong HELP không nói rằng "không được dùng mảng một chiều có dạng Numeric Data Type". Chính vì điều này mới đố chứ (he he) và đương nhiên nếu nó đưa câu đó ra thì ai đố làm gì vì ai cũng có thể xem Help!
 
Lần chỉnh sửa cuối:
Upvote 0
Lạ thật, phải chi UNI lại xài được như VNI nhỉ!
VNI thì khỏi nói chắc lúc xưa Microsoft hỗ trợ bây giờ chưa có người VN làm trong đội ngũ của Office nên chưa hỗ trợ Unicode quá !!!!. Sao trên máy e thi ko có hiện tượng như anh nói khi chỉnh sang Script Vietnamese thì dữ liệu đầu vào phải là Unicode tổ hợp mới chấp còn unicode dựng sẵn là bị lỗi như hình anh Ndu đưa, cách Ndu thì mọi trường hợp điều không bị lỗi mà thấy hơi bất tiện sao sao đó vì khi viết code cũng khó khăn vì dân không chuyên mà. File này em test trên máy Win 8, office 2013 với kiểu gõ unicode tổ hợp thì không bị lỗi các Bạn, Anh ,Chị xem có bị lỗi không. Cảm ơn
 

File đính kèm

Upvote 0
Theo em câu trên dịch là:

Mã:
Trả về một chuỗi được tạo ra bằng cách kết hợp (tham gia) [COLOR=#ff0000][B]một số chuỗi con chứa trong một mảng[/B][/COLOR]

Theo em hiểu, khi hàm xử lý chuỗi, chuyển từ một chuỗi hay một số, thì việc trả kết quả về là một dạng chuỗi hoặc số trong dạng chuỗi.

Chẳng hạn:

Mã:
[COLOR=#0000cd]?ucase(1)[/COLOR]
[COLOR=#0000cd]1[/COLOR]
[COLOR=#ff0000]?ucase("1")[/COLOR]
[COLOR=#ff0000]1[/COLOR]

Trường hợp xanh là dạng số cũng trả kết quả là 1 và trường hợp đỏ là dạng số trong chuỗi, cũng trả kết quả là 1

Tôi không dám nói là tôi đã ăn hết trí khôn trong thiên hạ. Nhưng tôi sẽ nói tôi đã hiểu thế nào.

Thứ nhất: substrings contained in an array
Theo tôi help nói rõ ràng là array chứa các chuỗi. Help không nói là: Array chứa các giá trị CÓ THỂ CONVERT thành chuỗi.

Thứ hai: hoặc số trong dạng chuỗi là thế nào?
Nếu giá trị trả về là "12" thì bạn còn có thể cố cãi là: đó là "số trong dạng chuỗi" vì 12 là số. Nhưng nếu trả về "12, 34, 56, 78" thì làm sao cãi được là đó là "số trong dạng chuỗi"? Vì 12, 34, 56, 78 là SỐ gì vậy?

Nếu bạn muốn tranh luận với tôi thì nên dùng từ chính xác.

Thêm nữa, 2 trường hợp mảng này, một dạng là số và một dạng số trong dạng chuỗi thì hàm Join vẫn cho ra kết quả:

Mã:
Sub Macro1()
    Dim Arr()
    Arr = Array(1, 2, 3, 4, 5)
    MsgBox Join(Arr, ", ")
End Sub

Sub Macro2()
    Dim Arr()
    Arr = Array("1", "2", "3", "4", "5")
    MsgBox Join(Arr, ", ")
End Sub

vậy cái Substring (chuỗi con) đâu nhất thiết phải là một chuỗi hay một số?
Cái SubStrings nói trong Join chắc chắn là chuỗi chứ không phải như bạn nói nó có thể là số.
Theo tôi bạn đưa vd. nhưng bạn không hiểu bản chất của vấn đề.

Trong vd. bạn đưa ra nếu bạn dùng TypeName thì bạn có thể đọc "dạng" của giá trị hiện hành. Đó có thể là "Integer" hoặc "String". Nhưng về bản chất thì mỗi phần tử của Arr là VARIANT

Bạn chạy

Mã:
Sub Macro1()
    Dim Arr()
    Arr = Array(1, 2, 3, 4, 5)
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
    Arr(0) = "hic hic"
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
End Sub

thì không có lỗi nào. Đơn giản vì mỗi phần tử của Arr là VARIANT

Nhưng chạy

Mã:
Sub Macro2()
    Dim Arr(0 To 4) As Long, index As Long
    For index = 0 To 4
        Arr(index) = index + 1
    Next
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
    Arr(0) = "hic hic"      '  <-- lỗi
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
End Sub

thì có lỗi vì mỗi phần tử của Arr là LONG. Vậy không thể viết: Arr(0) = "hic hic" được.

Nhưng code sau lại không có lỗi

Sub Macro2()
Dim Arr(0 To 4) As Long, index As Long
For index = 0 To 4
Arr(index) = index + 1
Next
MsgBox Arr(0)
MsgBox TypeName(Arr(0))
Arr(0) = "7689"
MsgBox Arr(0)
MsgBox TypeName(Arr(0))
MsgBox TypeName(Arr(1))
End Sub

Đơn giản vì VBA theo tôi quá thân thiện. Bạn có thể nhập STRING nhưng phải ở dạng có thể convert được sang LONG. Lúc đó cái bạn nhập vào sẽ được convert sang LONG nếu cần thiết (nhập Long thì không cần thiết convert, nhập string thì cần) và kiểu của nó là LONG dù bạn đã nhập vào chuỗi.

Khi phần tử là VARIANT thì nếu bạn nhập numeric hay string có thể convert sang numeric thì giá trị của phần tử đó có thể coi là numeric hay là string đều được. Tùy vào tình huống cụ thể mà nó sẽ được dùng với "tư cách" là số hay chuỗi. Tất nhiên "hic hic", "he he" thì chỉ có thể "lên sân khấu" với tư cách là string mà thôi. Nhưng 1 (hoặc "1") thì luôn có thể "lên sân khấu" với tư cách là chuỗi hoặc số.

Bạn đừng so sánh 2 trường hợp - 1 ở bài #931 và 1 ở bài này - nhé. Vì ở bài kia mỗi phần tử của mảng là LONG còn ở bài này mỗi phần tử của mảng là VARIANT. Mà đã là VARIANT thì dù nhập vào SỐ thì nó luôn được "nhìn" là SỐ hoặc CHUỖI tùy theo "nhu cầu" hiện hành.

Và thủ tục này, i là biến kiểu Byte, nếu một biến X nào đó (không để kiểu) mà bằng i (X = i) thì X chính là dạng Byte, điều này ai cũng biết. Thế thì:

Mã:
Sub Test()
    Dim i As Byte
    Dim Arr(0 To 9)
    For i = 0 To 9
        Arr(i) = i
    Next
[B][COLOR=#0000ff]    MsgBox TypeName(Arr(1))[/COLOR][/B]
[COLOR=#ff0000][B]    MsgBox Join(Arr, ",")[/B][/COLOR]
End Sub

Nhưng Byte thì Byte hàm JOIN vẫn "xơi" tuốt luốt, không bị "mắc xương"!
Chơi tuốt thì dĩ nhiên rồi. Ở code trên thì mỗi phần tử của Arr là VARIANT. Bạn có thể nhập SỐ nhưng mỗi phần tử lúc đó có thể xuất hiện với tư cách là SỐ hoặc CHUỖI tùy vào nhu cầu.
Ở bài #931 thì mỗi phần tử của mảng là LONG. Bạn không thấy sự khác biệt giữa 2 trường hợp à?

Thêm nữa, trong HELP không nói rằng "không được dùng mảng một chiều có dạng Numeric Data Type". Chính vì điều này mới đố chứ (he he) và đương nhiên nếu nó đưa câu đó ra thì ai đố làm gì vì ai cũng có thể xem Help!

Help đã nói rất rõ rồi. Sao help lại phhải liệt kê các th cấm? Vd. Hiến Pháp nói: "Ứng viên tham gia bầu cử tổng thống VN phải có quốc tịch Việt Nam, sinh ra trên lãnh thổ VN và có ít nhất 35 tuổi". Thế chưa đủ sao? Hay phải nói thêm: "Cấm những người chưa đủ 35 tuổi, không có quốc tịch VN hoặc không sinh ra trên lãnh thổ VN ...?"

Help nói rõ rồi. Còn chuyện bạn muốn truyền mảng thế nào là quyền của bạn. VBA không cấm. Chỉ có điều nếu bạn truyền mảng "không đúng" thì VBA "phạt". Đó cũng là quyền của VBA. Thế thôi.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi không dám nói là tôi đã ăn hết trí khôn trong thiên hạ. Nhưng tôi sẽ nói tôi đã hiểu thế nào.

Thứ nhất: substrings contained in an array
Theo tôi help nói rõ ràng là array chứa các chuỗi. Help không nói là: Array chứa các giá trị CÓ THỂ CONVERT thành chuỗi.

Em vẫn chưa tâm phục vì sự trả lời này, bởi vì:

Câu màu đỏ, được hiểu rằng:

1) Các chuổi (con) được chứa trong một mảng

hoặc:

2) Một mảng chứa các chuỗi (con)

Chứ không nói KIỂU DỮ LIỆU CỦA MỘT MẢNG!

Thứ hai: hoặc số trong dạng chuỗi là thế nào?

Ô A1 có giá trị là Nghia_1

Công thức: =RIGHT(A1,1)

Kết quả = 1

Nhưng thực chất đây là một số trong dạng chuỗi (Number stored as text) >> không tính toán được với số này! Thế thôi!

Mã:
Sub Macro2()
    Dim Arr(0 To 4) As Long, index As Long
    For index = 0 To 4
        Arr(index) = index + 1
    Next
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
    Arr(0) = "hic hic"      '  <-- lô~i
    MsgBox Arr(0)
    MsgBox TypeName(Arr(0))
End Sub

Vì dạng Long không chấp nhận chuỗi nên phát sinh ra lỗi. OK

Nhưng với VD dưới đây, kiểu số nó ngán kiểu chuỗi chứ thằng kiểu chuỗi nó đâu có ngán kiểu số:

Mã:
Sub test3()

    Dim Arr(0 To 3) [COLOR=#ff0000][B]As String[/B][/COLOR]
    
    Arr(0) = "Hoang"
    Arr(1) = "Trong"
    Arr(2) = "Nghia"
[COLOR=#ff0000][B]    Arr(3) = 2151[/B][/COLOR]
    
    MsgBox Arr(3)
End Sub

Vì thế, JOIN là hàm xử lý ghép các phần tử trong mảng ra chuỗi (số cũng sẽ cho ra chuỗi, mà chuỗi đương nhiên là chuỗi), thì tại sao phải vấp lỗi khi gặp mảng dữ liệu kiểu số?
 
Lần chỉnh sửa cuối:
Upvote 0
VNI thì khỏi nói chắc lúc xưa Microsoft hỗ trợ bây giờ chưa có người VN làm trong đội ngũ của Office nên chưa hỗ trợ Unicode quá !!!!. Sao trên máy e thi ko có hiện tượng như anh nói khi chỉnh sang Script Vietnamese thì dữ liệu đầu vào phải là Unicode tổ hợp mới chấp còn unicode dựng sẵn là bị lỗi như hình anh Ndu đưa, cách Ndu thì mọi trường hợp điều không bị lỗi mà thấy hơi bất tiện sao sao đó vì khi viết code cũng khó khăn vì dân không chuyên mà. File này em test trên máy Win 8, office 2013 với kiểu gõ unicode tổ hợp thì không bị lỗi các Bạn, Anh ,Chị xem có bị lỗi không. Cảm ơn
À, mình làm kiểu "lụi" đó mà, sau khi lấy nguồn từ Unicode cho ComboBox, CBB này đã được cài sẳn Script Vietnamese, sau đó chọn một mục trong list, rồi click vào một cell nào đó. Trong quá trình này mình chạy sự kiện LostFocus để chuyển chuỗi của CBB từ chuỗi Uni sang chuỗi CP1258. Kiểu "lụi" này không thành công.

Còn file của nmhung49 là đã tạo cái source ngay từ đầu rồi.
 
Upvote 0
Em vẫn chưa tâm phục vì sự trả lời này, bởi vì:

Câu màu đỏ, được hiểu rằng:

1) Các chuổi (con) được chứa trong một mảng

hoặc:

2) Một mảng chứa các chuỗi (con)

Chứ không nói KIỂU DỮ LIỆU CỦA MỘT MẢNG!



Ô A1 có giá trị là Nghia_1

Công thức: =RIGHT(A1,1)

Kết quả = 1

Nhưng thực chất đây là một số trong dạng chuỗi (Number stored as text) >> không tính toán được với số này! Thế thôi!



Vì dạng Long không chấp nhận chuỗi nên phát sinh ra lỗi. OK

Nhưng với VD dưới đây, kiểu số nó ngán kiểu chuỗi chứ thằng kiểu chuỗi nó đâu có ngán kiểu số:

Mã:
Sub test3()

    Dim Arr(0 To 3) [COLOR=#ff0000][B]As String[/B][/COLOR]
    
    Arr(0) = "Hoang"
    Arr(1) = "Trong"
    Arr(2) = "Nghia"
[COLOR=#ff0000][B]    Arr(3) = 2151[/B][/COLOR]
    
    MsgBox Arr(3)
End Sub

Vì thế, JOIN là hàm xử lý ghép các phần tử trong mảng ra chuỗi (số cũng sẽ cho ra chuỗi, mà chuỗi đương nhiên là chuỗi), thì tại sao phải vấp lỗi khi gặp mảng dữ liệu kiểu số?

Tất cả những gì tôi định viết thì thì đã viết rồi. Tôi không có gì muốn thêm
 
Upvote 0
Hùa thêm với bác Siwtom một chút nữa, theo phần tài liệu hoá của Microsoft về hàm Join tại trang dưới đây, họ viết khá rõ về tham số đầu vào cho hàm Join.
[GPECODE=csharp]Function Join(
ByVal SourceArray() As { Object | String },
Optional ByVal Delimiter As String = " "
) As String[/GPECODE]
http://msdn.microsoft.com/en-us/library/b65z3h4h(v=vs.90).aspx

Ngoài ra, còn một điểm khác, khi không đặc tả kiểu số liệu của tham số thì hàm Join sẽ sử dụng tính năng chuyển đổi kiểu dữ liệu thụ động (implicit conversion) đưa số liệu về kiểu ký tự. Xem liên kết.
[http://msdn.microsoft.com/en-us/library/kca3w8x6.aspx]
Nếu đặc tả kiểu dữ liệu đầu vào thì nó sẽ sử dụng kiểu dữ liệu đó, không chuyển đổi kiểu số liệu nữa và xử lý, nếu xử lý không được thì nó sẽ báo lỗi về sai cấu trúc dữ liệu. Tất nhiên nếu khai báo kiểu số liệu là Variant thì implicit conversion sẽ được kích hoạt để đưa tham số đầu vào về khuôn khổ.

Xin được võ vẽ thêm đôi câu cùng Nghĩa!

Ví dụ mình sửa lại một tí đoạn test của Nghĩa để thí nghiệm vụ Implicit và Explicit...
[GPECODE=vb]Sub testJoin() 'Tat ca bien kieu Numeric deu bi loi:
Dim i As Long
Dim Arr1() As Date ' Integer, Byte, Double, Currency, Date v.v...
Dim Arr() As Variant
ReDim Arr1(9)
ReDim Arr(9)
For i = 0 To 9
Arr1(i) = i
Arr(i) = Arr1(i)
Next
Debug.Print Join(Arr, ",")
End Sub[/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
Xin được võ vẽ thêm đôi câu cùng Nghĩa!
Ví dụ mình sửa lại một tí đoạn test của Nghĩa để thí nghiệm vụ Implicit và Explicit...
[GPECODE=vb]Sub testJoin() 'Tat ca bien kieu Numeric deu bi loi:
Dim i As Long
Dim Arr1() As Date ' Integer, Byte, Double, Currency, Date v.v...
Dim Arr() As Variant
ReDim Arr1(9)
ReDim Arr(9)
For i = 0 To 9
Arr1(i) = i
Arr(i) = Arr1(i)
Next
Debug.Print Join(Arr, ",")
End Sub[/GPECODE]

1) Tôi đã xem đường dẫn đó, vẫn không nói kiểu dữ liệu của mảng 1 chiều là kiểu dữ liệu nào.

2) Trong Exceptions cũng chỉ đề cập đến lỗi là không phải mảng 1 chiều

3) Với Sub TestJoin thì như bài trả lời câu đố đã nói:

Mã:
[COLOR=#ff0000]Các kiểu khai báo mảng thuộc kiểu String, Variant, hoặc không khai báo loại nào [B]đều không phát sinh lỗi[/B][/COLOR]

Thì:

Mã:
Debug.Print Join(Arr, ",")

Với Arr cũng là một mảng không khai báo kiểu dữ liệu, bởi:

Mã:
ReDim Arr(9)

Vì thế làm sao phát sinh được lỗi???

Nguyên tắc ReDim thực chất là tạo ra một mảng mới (nhưng vẫn giữ kiểu dữ liệu ban đầu), cho nên với mảng 1 chiều mà không khai báo gì ở ban đầu, hoặc khai báo kiểu chuỗi, kiểu variant thì không làm ảnh hưởng đến hàm Join.

Mà bạn làm lòng vòng chi vậy, làm như vầy là cũng test được mà:

Mã:
Sub TestDate()
    Dim Arr(2)
    Dim d As [COLOR=#ff0000]Date[/COLOR]
    For d = 0 To 2
        Arr(d) = d
    Next
    Debug.Print Join(Arr, ",")
    
    ''Hoac:

    Arr(0) = #1/1/2013#
    Arr(1) = #1/2/2013#
    Arr(2) = #1/3/2013#
    Debug.Print Join(Arr, ",")
End Sub

XIN LƯU Ý CHO CÂU ĐỐ NÀY: CẤU TRÚC JOIN KHÔNG SAI VÌ TA DÙNG MẢNG 1 CHIỀU, NÓ CŨNG KHÔNG "KÉN" KIỂU DỮ LIỆU CỦA CÁC PHẦN TỬ BÊN TRONG MẢNG, NÓ CHỈ BỊ LỖI ĐỐI VỚI KIỂU DỮ LIỆU CỦA MẢNG LÀ KIỂU NUMERIC MÀ THÔI!
 
Lần chỉnh sửa cuối:
Upvote 0
Nghĩa xem cái này nhé As { Object | String }

[GPECODE=vb]Function Join(
ByVal SourceArray() As { Object | String },
Optional ByVal Delimiter As String = " "
) As String[/GPECODE]

Nói khác hơn nó đòi hỏi kiểu dữ liệu đầu vào phải là như vậy - khi viết hướng dẫn hàm, họ sẽ không nói quá dài được, phần remark thì nó định nghĩa như thế rồi (Required. One-dimensional array containing substrings to be joined). Tạm dịch là: Bắt buộc: Mảng một chiều chứa các chuỗi con cần nối.

Nếu bẻ chữ một chút, điều này có thể coi là (1) Các chuỗi con của một mảng được đặc tả kiểu, tuy nhiên các phần tử của mảng lại được gán với các giá trị là chuỗi, vì vậy trình biên dịch sẽ tự dịch từ chuỗi sang kiểu số liệu của mảng khi thực hiện phép gán; và nếu gán được thì tốt, gán không được nó sẽ báo lỗi. hoặc (2) Muốn các chuỗi con, hay các phần tử của mảng có kiểu số liệu là chuỗi thì mảng đó cũng phải có kiểu số liệu là chuỗi.
Thiết nghĩ điều đó đã rõ ràng rồi mà!

Khi kiểu dữ liệu tham số không được đặc tả hoặc đặc tả dạng không cụ thể (variant chẳng hạn) thì cơ chế biên dịch sẽ tự động dịch sang kiểu dữ liệu cần thiết cho hàm xử lý (Implicit Conversion).
Nhưng nếu đã đặc tả kiểu (số, ngày, giờ ...vv) thì cơ chế chuyển kiểu dữ liệu sẽ không được thực hiện và nó sẽ đưa nguyên số liệu đầu vào theo cách ban đầu Nghĩa đã đặc tả. Và như vậy sẽ gây lỗi số 5 (sai cấu trúc).

Còn trong ví dụ của mình, việc redim chỉ là nghịch ngợm tí thôi - cái quan trọng là lệnh gán từ kiểu số sang mảng không định nghĩa kiểu dữ liệu ý. Cái đó nó sẽ bảo trình dịch tiếp tục thực hiện việc chuyển đổi kiểu số liệu thụ động để đưa đúng món ăn vào cho hàm Join.
Xin võ vẽ thế!
 
Lần chỉnh sửa cuối:
Upvote 0
Nghĩa xem cái này nhé As { Object | String }

[GPECODE=vb]Function Join(
ByVal SourceArray() As { Object | String },
Optional ByVal Delimiter As String = " "
) As String[/GPECODE]

Nói khác hơn nó đòi hỏi kiểu dữ liệu đầu vào phải là như vậy - khi viết hướng dẫn hàm họ sẽ không nói quá dài được, phần remark thì nó định nghĩa như thế rồi (Required. One-dimensional array containing substrings to be joined.).

Khi kiểu dữ liệu tham số không được đặc tả hoặc đặc tả dạng không cụ thể (variant chẳng hạn) thì cơ chế biên dịch sẽ tự động dịch sang kiểu dữ liệu cần thiết cho hàm xử lý (Implicit Conversion).
Nhưng nếu đã đặc tả kiểu (số, ngày, giờ ...vv) thì cơ chế chuyển kiểu dữ liệu sẽ không được thực hiện và nó sẽ đưa nguyên số liệu đầu vào theo cách ban đầu Nghĩa đã đặc tả. Và như vậy sẽ gây lỗi số 5 (sai cấu trúc).

Còn trong ví dụ của mình, việc redim chỉ là nghịch ngợm tí thôi - cái quan trọng là lệnh gán từ kiểu số sang mảng không định nghĩa kiểu dữ liệu ý. Cái đó nó sẽ bảo trình dịch tiếp tục thực hiện việc chuyển đổi kiểu số liệu thụ động để đưa đúng món ăn vào cho hàm Join.
Xin võ vẽ thế!

Câu đó tôi đã nói rõ rồi mà!

Yêu cầu là một mảng 1 chiều:

Em vẫn chưa tâm phục vì sự trả lời này, bởi vì:

Câu màu đỏ, được hiểu rằng:

1) Các chuổi (con) được chứa trong một mảng

hoặc:

2) Một mảng chứa các chuỗi (con)

Chứ không nói KIỂU DỮ LIỆU CỦA MỘT MẢNG!

Câu nào nói về kiểu dữ liệu của mảng đâu? Và câu này:

(Required. One-dimensional array containing substrings to be joined.).

Dịch ra là MẢNG CÓ KIỂU DỮ LIỆU LÀ CHUỖI hay sao?
 
Lần chỉnh sửa cuối:
Upvote 0
Nghĩa ơi, cái SourceArray() As{ Object| String} mà còn không thể hiện kiểu SourceArray là String à! Cú pháp viết tham số hàm đây thôi!

Thông thường phần giải thích thêm chỉ giúp ta hiểu thêm một chút thôi còn cái gì đã quy định trong cú pháp thì cứ y thế mà làm. Có chăng phần giải thích thêm của bác Bill nên thêm mấy chữ. Mảng chứa các phần tử cần nối phải là mảng một chiều có kiểu dữ liệu là chuỗi (One-dimensional array of string data-type containing string elements to be joined).

Ví dụ: ByVal XX() as Long hoặc ByVal YY() as String thì ta nên hiểu thế nào?
Bài viết 942 mình có viết thêm mấy chữ nữa trong lúc bạn đang viết bài!
 
Lần chỉnh sửa cuối:
Upvote 0
Nhưng nói "túm lại" là câu đố đơn giản nhưng không có người trả lời được! hehehehe.--=0

Tôi không nói về mình, nhưng theo tôi nghĩ thì có nhiều người trên GPE có thể trả lời câu hỏi của bạn. Chỉ có điều có thể người ta không quan tâm, người ta không đọc chủ đề của bạn hoặc đơn giản người ta chưa truy cập GPE. Mà tham gia trả lời có phải nghĩa vụ đâu.

Nhưng nếu cái bạn viết trên làm cho bạn thấy vui hơn thì là tốt rồi.
 
Upvote 0
Nghĩa ơi, cái SourceArray() As{ Object| String} mà còn không thể hiện kiểu SourceArray là String à! Cú pháp viết tham số hàm đây thôi!

Thông thường phần giải thích thêm chỉ giúp ta hiểu thêm một chút thôi còn cái gì đã quy định trong cú pháp thì cứ y thế mà làm. Có chăng phần giải thích thêm của bác Bill nên thêm mấy chữ. Mảng chứa các phần tử cần nối phải là mảng một chiều có kiểu dữ liệu là chuỗi (One-dimensional array of string data-type containing string elements to be joined).

Ví dụ: ByVal XX() as Long hoặc ByVal YY() as String thì ta nên hiểu thế nào?
Bài viết 942 mình có viết thêm mấy chữ nữa trong lúc bạn đang viết bài!

Cũng như ListBox ta chỉ được tạo 10 cột, nhưng với tiểu xảo ta vẫn tạo số cột nhiều hơn.

Hàm JOIN này cũng vậy, nếu ta khai báo rõ ràng, tường mình thì đôi khi lại gặp lỗi, nhưng ngược lại, nếu ta không tường minh thì lại chạy hiệu quả (mặc dù bên trong toàn dữ liệu kiểu numeric).

Nói vậy cho mọi người hiểu rằng đôi khi ta vẫn "lách luật" trong VBA được là vậy.

Mục đích đố chỉ là vậy thôi.
 
Upvote 0
Cũng như ListBox ta chỉ được tạo 10 cột, nhưng với tiểu xảo ta vẫn tạo số cột nhiều hơn.

Hàm JOIN này cũng vậy, nếu ta khai báo rõ ràng, tường mình thì đôi khi lại gặp lỗi, nhưng ngược lại, nếu ta không tường minh thì lại chạy hiệu quả (mặc dù bên trong toàn dữ liệu kiểu numeric).

Nói vậy cho mọi người hiểu rằng đôi khi ta vẫn "lách luật" trong VBA được là vậy.

Mục đích đố chỉ là vậy thôi.
cái này bac "siwtom" đã nói rõ ở bài trên rồi
đồng thời Ông Bill cũng đã định nghĩa rõ ràng hàm Join là làm nối các chuỗi trong mảng thành 1 chuỗi
vậy theo Anh ý nó là gì????
theo mình hiểu câu ấy là Join sẽ nối các chuỗi ký tự lại với nhau, nhưng các số vẫn có thể nối với nhau bởi vì Ông Bill hiểu các số ấy ko phải là các "con số "mà là "chữ số " (là chuỗi)
còn khi anh khai báo biến là biến số thì anh đang ép Ông Bill hiểu đây là những con số nên Ông Bill phản lại : đây ko phải công việc của tôi, tôi ko cố nghĩa vụ phải làm, nên việc này tao ko làm ------> dẫn đến báo lỗi thế thôi

đùa chút thôi theo mình nghĩ quan điểm của Ông Bill là các con số thì phải dùng trong tính toán chứ ko phải dùng để nối nên việc nối chỉ cho phép thực hiện ở chế độ chuỗi
 
Lần chỉnh sửa cuối:
Upvote 0
cái này bac "siwtom" đã nói rõ ở bài trên rồi
đồng thời Ông Bill cũng đã định nghĩa rõ ràng hàm Join là làm nối các chuỗi trong mảng thành 1 chuỗi
vậy theo Anh ý nó là gì????
theo mình hiểu câu ấy là Join sẽ nối các chuỗi ký tự lại với nhau, nhưng các số vẫn có thể nối với nhau bởi vì Ông Bill hiểu các số ấy ko phải là các "con số "mà là "chữ số " (là chuỗi)
còn khi anh khai báo biến là biến số thì anh đang ép Ông Bill hiểu đây là những con số nên Ông Bill phản lại : đây ko phải công việc của tôi, tôi ko cố nghĩa vụ phải làm, nên việc này tao ko làm ------> dẫn đến báo lỗi thế thôi

đùa chút thôi theo mình nghĩ quan điểm của Ông Bill là các con số thì phải dùng trong tính toán chứ ko phải dùng để nối nên việc nối chỉ cho phép thực hiện ở chế độ chuỗi


Gọi là tổng kết lại những thông tin căn bản.
Theo tôi hiểu thì:

1. JOIN đòi hỏi mảng vào là mảng các chuỗi.
2. Nếu ta truyền mảng các chuỗi thì JOIN nói: dạ vâng, em bắt tay vào việc đây. Nếu ta truyền mảng các số thì JOIN nói: Tôi không làm vì người ta không đếm xỉa tới yêu cầu của tôi.

Nhưng có ai đó nói: Thế tại sao với code

Mã:
Sub Test()
    Dim i As Byte
    Dim Arr(0 To 9)
    For i = 0 To 9
        Arr(i) = i
    Next
    MsgBox TypeName(Arr(1))
    MsgBox Join(Arr, ",")
End Sub

thì hàm JOIN vẫn "xơi" tuốt luốt, không bị "mắc xương"? MsgBox chả đã nói rõ là mảng đang chứa các giá trị BYTE là gì? BYTE đâu có là STRING?

Nguyên nhân thì tôi đã nói ở bài #935: Mà đã là VARIANT thì dù nhập vào SỐ thì nó luôn được "nhìn" là SỐ hoặc CHUỖI tùy theo "nhu cầu" hiện hành ***

Dùng Variant nó có cái khác ở chỗ đó. Tức "ta" cung cấp cho JOIN mảng chuỗi.

Về *** mà tôi viết là có cơ sở hẳn hoi

Variant Data Type

The Variant data type is the data type for all variables that are not explicitly declared as some other type (using statements such as Dim, Private, Public, or Static). The Variant data type has no type-declaration character.

A Variant is a special data type that can contain any kind of data except fixed-length String data. (Variant types now support user-defined types.) A Variant can also contain the special values Empty, Error, Nothing, and Null. You can determine how the data in a Variant is treated using the VarType function or TypeName function.

Numeric data can be any integer or real number value ranging from -1.797693134862315E308 to -4.94066E-324 for negative values and from 4.94066E-324 to 1.797693134862315E308 for positive values. Generally, numeric Variant data is maintained in its original data type within the Variant. For example, if you assign an Integer to a Variant, subsequent operations treat the Variant as an Integer. However, if an arithmetic operation is performed on a Variant containing a Byte, an Integer, a Long, or a Single, and the result exceeds the normal range for the original data type, the result is promoted within the Variant to the next larger data type. A Byte is promoted to an Integer, an Integer is promoted to a Long, and a Long and a Single are promoted to a Double. An error occurs when Variant variables containing Currency, Decimal, and Double values exceed their respective ranges.

You can use the Variant data type in place of any data type to work with data in a more flexible way. If the contents of a Variant variable are digits, they may be either the string representation of the digits or their actual value, depending on the context. For example:

Dim MyVar As Variant
MyVar = 98052


In the preceding example,

MyVar

contains a numeric representation — the actual value
98052

. Arithmetic operators work as expected on Variant variables that contain numeric values or string data that can be interpreted as numbers. If you use the + operator to add
MyVar

to another Variant containing a number or to a variable of a numeric type, the result is an arithmetic sum.

The value Empty denotes a Variant variable that hasn't been initialized (assigned an initial value). A Variant containing Empty is 0 if it is used in a numeric context and a zero-length string ("") if it is used in a string context.

Don't confuse Empty with Null.Null indicates that the Variant variable intentionally contains no valid data.

In a Variant, Error is a special value used to indicate that an error condition has occurred in a procedure. However, unlike for other kinds of errors, normal application-level error handling does not occur. This allows you, or the application itself, to take some alternative action based on the error value. Error values are created by converting real numbers to error values using the CVErr function.

Chỗ đỏ đỏ chính là cái tôi đã viết.

Vậy thì:

1. nếu đòi hỏi phải có mảng các SỐ mà ta truyền mảng Variant mà hiện thời đang chứa các SỐ thì dĩ nhiên là tốt rồi. Nhưng ta cũng có thể truyền mảng các CHUỖI mà mỗi chuỗi có thể convert được thành SỐ (vd. "12" convert được thành SỐ nhưng "hichic" thì không convert được thành SỐ). Cơ sở là cái dòng đỏ đỏ kia.

2. nếu đòi hỏi phải có mảng các CHUỖI mà ta truyền mảng Variant mà hiện thời đang chứa các CHUỖI thì dĩ nhiên là tốt rồi. Nhưng ta cũng có thể truyền mảng các SỐ. Cơ sở là cái dòng đỏ đỏ kia.

3. Dù là Variant "12" hay Variant 12 nếu dùng trong biểu thức có phép "+" thì nó có vai trò là SỐ 12, nếu dùng trong ghép chuỗi thì nó có vai trò là chuỗi "12".

Ta phải ý thức được:

1. Variant nó có gì khác biệt với các kiểu dữ liệu khác.

2. Cái ta nhìn thấy, có được, sờ nắn ngửi được là kết quả của bao thao tác mà ta không nhìn thấy, kể cả convert nếu cần thiết, là kết quả mà bao "vị" đã đổ mồ hôi âm thầm cần cù làm sau "cánh gà" để có được "sản phẩm" dâng cho ta. JOIN không phải tự convert SỐ thành chuỗi, mà nó dứt khoát không làm, mà nó được cung cấp mảng chuỗi là sản phẩm mà "trước đó" sau "cánh gà" "người ta" đã đổ mồ hôi để tạo ra để dâng cho nó.
----------------
Đó là những gì tôi hiểu. Tôi không dám nói là mình hiểu đúng. Nhưng những gì tôi muốn viết thì đã viết hết rồi. Vậy đây là bài cuối cùng của tôi về vấn đề này.
 
Upvote 0
Gọi là tổng kết lại những thông tin căn bản.
Theo tôi hiểu thì:

1. JOIN đòi hỏi mảng vào là mảng các chuỗi.
2. Nếu ta truyền mảng các chuỗi thì JOIN nói: dạ vâng, em bắt tay vào việc đây. Nếu ta truyền mảng các số thì JOIN nói: Tôi không làm vì người ta không đếm xỉa tới yêu cầu của tôi.

Nhưng có ai đó nói: Thế tại sao với code


[GPECODE=vb]Sub Test()
Dim i As Byte
Dim Arr(0 To 9)
For i = 0 To 9
Arr(i) = i
Next
MsgBox TypeName(Arr(1))
MsgBox Join(Arr, ",")
End Sub[/GPECODE]


thì hàm JOIN vẫn "xơi" tuốt luốt, không bị "mắc xương"? MsgBox chả đã nói rõ là mảng đang chứa các giá trị BYTE là gì? BYTE đâu có là STRING?
đương nhiên đoạn code trên chạy tốt rồi, vì như Bác đã nói "đỏ đỏ" đó đã được chấp thuận, nên em nó phải làm việc thôi, vì khi ko khai báo mảng Arr thuôc loại nào mặt nhiên nó là variant , tuy biến i đc khai báo nhưng mảng vẫn là variant
Nhưng có ai đó nói: Thế tại sao với code
vậy cảm phiềm test thêm 2 đoạn code này
[GPECODE=vb]Sub Test()
Dim i As Byte
Dim Arr(1 To 9) as Byte
For i = 1 To 9
Arr(i) = i
Next
MsgBox TypeName(Arr(1))
MsgBox Join(Arr, ",")
End Sub[/GPECODE]
ta thiết lập mạng là kiểu byte Dim Arr(1 To 9) as Byte
và đoạn này [GPECODE=vb]Sub Test()
Dim i As Byte
Dim Arr(1 To 9)
For i = 1 To 9
Arr(i) = i
Next
MsgBox TypeName(Arr)
MsgBox Join(Arr, ",")
End Sub[/GPECODE]

MsgBox TypeName(Arr)
Join đang làm việc với mảng nên mình cần xem mảng đó là mảng kiểu gì mà thôi
 
Lần chỉnh sửa cuối:
Upvote 0
- Vẽ cái Frame
- Click chuột phải vào đó, chọn Frame Object --> Edit
- Tự nhiên sẽ thấy và.. biết liền
Thầy ơi, khi em xài cái Frame này ở WinXP, Excel 2003 thì khi mở file nó hiện thông báo như thế này (xem hình), chọn Yes thì nó cho sử dụng, No thì như cái shape vậy đó. Cho em hỏi cách khắc phục đừng cho nó hiện thông báo này mỗi lần mở thì như thế nào ạ?

Nội dung:

This condition is related to how ActiveX controls are initialized within Office applications. ActiveX controls are programs and can store data in either the registry or within the control itself. ActiveX controls are similar to Visual Basic for Applications macros except they are compiled to a special file type and can be linked to a data file that can support them (for instance, Word documents and Excel workbooks). When you receive a file with an ActiveX control linked to it, the possibility that there may be "persistent" data (data stored with the control) is unknown; the data could be malicious - used to plant a virus or to modify your computer with the intent to do harm. Office applications provide, by default, the ability to block ActiveX controls from using persisted data. However, if you have specifically changed the default setting for ActiveX initialization during the installation process, or by using a policy, the system will perform the initialization of the ActiveX control based on your custom settings.If you choose to allow the application to run the control and to allow it to use persisted data, you do so at your own risk. It is highly recommended to not run ActiveX controls in documents submitted to you by people you do not know. However, if you trust the source of the document and the individual or company who sent it to you, then you can load the control and allow it to use persisted data. However, this is no guarantee that the data associated with the control is actually safe to use.
There are limitations to the ability of Office applications to migrate ActiveX control link references from one format of a document or file to another format. For instance, you can link an ActiveX control to a Word document and save that file. However, when you convert that Word document to another format the link reference to the ActiveX control might not convert into that file format. Therefore, conversion of files that have links to ActiveX controls may not be supported for all file types, partly because not all file types can support ActiveX control linking or activation. For files with links to ActiveX controls, it is necessary to accept and activate the ActiveX control prior to converting the file to another file type that supports ActiveX linking and activation. If the ActiveX control is not activated, the link reference is dropped from the file and will not appear in the converted file.
More information about this error message online.
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    142.2 KB · Đọc: 47
Lần chỉnh sửa cuối:
Upvote 0
Thầy ơi, khi em xài cái Frame này ở WinXP, Excel 2003 thì khi mở file nó hiện thông báo như thế này (xem hình), chọn Yes thì nó cho sử dụng, No thì như cái shape vậy đó. Cho em hỏi cách khắc phục đừng cho nó hiện thông báo này mỗi lần mở thì như thế nào ạ?

Lang thang trên Google, mãi mới tìm được cách "khống chế", cũng để cho nó hoạt động mà không thông báo, chứ cách này liên quan đến an toàn (http://support.microsoft.com)

Làm theo các bước sau:

1) Bấm start, bấm run, gõ regedit, và sau đó bấm OK.

2) Mở rộng khoá con registry sau:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Common

3) Bấm chuột phải vào Common, chọn New và sau đó bấm Key.

4) Gõ Security, rồi nhấn ENTER để đặt tên mới.

5) Bấm chuột phải vào Security, chọn New, và sau đó bấm Giá trị DWORD.

6) Gõ UFIControls, và sau đó nhấn ENTER để đặt tên giá trị.

7) Bấm đúp vào UFIControls.

8) Trong ô dữ liệu giá trị , nhập 1, và sau đó bấm OK.

Chú ý Cài đặt khả dụng cho UFIControls 1 đến 6. Thiết đặt an toàn nhất là 4. Thiết lập mặc định là 6 và thiết lập kém an toàn nhất là 1.

9) Thoát khỏi Registry Editor.
 
Upvote 0
Thiết lập như thế này thật tình là không được nếu ta dùng sự kiện Workbook_Open và trên file đó chứa ActiveX Controls (cái thông báo nó nhảy ra trước khi sự kiện hoạt động).

Mã:
Sub UFIControlsSetting(ByVal Input_from_1_to_6 As Byte)
    ''Chi nhap tu 1 den 6
    ''Kem an toan nhat: 1
    ''An toan nhat: 4
    Dim regKey As String
    regKey = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Common\Security\UFIControls"
    CreateObject("WScript.Shell").RegWrite regKey, Input_from_1_to_6, "REG_DWORD"
End Sub

Mã:
Private Sub Workbook_Open()
    UFIControlsSetting 1
End Sub

Vậy phải làm sao đây các Thầy ơi???
 
Upvote 0
Chắc máy của Nghĩa bị làm sao ấy... chứ có ai bị vụ này đâu mà test đây?
Máy em đâu, 5 cái máy xài WinXP và Excel 2003 đều bị dính hết, phải regedit hết mới không còn bị nữa! Còn máy em xài Win7 Excel 2010 nên không bị.
 
Upvote 0
Upvote 0
Hôm nay mình muốn đưa ra 1 câu đố vui, mong anh em cùng thử 1 chút:

Trên Form UserForms1 chỉ có 1 Button là CommandButton1. Không thêm bất kể 1 đối tượng nào trên Form và không dùng hình nền cho Form làm sao có thể khi nhấn Button sẽ xuất hiện dòng chữ WELLCOME lên trên Form khi RunTime
 
Upvote 0
Hôm nay mình muốn đưa ra 1 câu đố vui, mong anh em cùng thử 1 chút:

Trên Form UserForms1 chỉ có 1 Button là CommandButton1. Không thêm bất kể 1 đối tượng nào trên Form và không dùng hình nền cho Form làm sao có thể khi nhấn Button sẽ xuất hiện dòng chữ WELLCOME lên trên Form khi RunTime

Có phải giống như bên dưới ở VB6.0 không anh?

[video=youtube;aFnZVRXxEeo]http://www.youtube.com/watch?v=aFnZVRXxEeo&amp;feature=youtu.be[/video]
 
Upvote 0
Cái này chỉ hữu dụng đối với MDI form chứ VBA đâu có được, mình cũng đã Test lại cho chắc chắn rồi.

Nó như hình trong file sau
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Hôm nay mình muốn đưa ra 1 câu đố vui, mong anh em cùng thử 1 chút:

Trên Form UserForms1 chỉ có 1 Button là CommandButton1. Không thêm bất kể 1 đối tượng nào trên Form và không dùng hình nền cho Form làm sao có thể khi nhấn Button sẽ xuất hiện dòng chữ WELLCOME lên trên Form khi RunTime

Bài này nếu dùng API thì không có vấn đề gì cả (cho hiển thị Text lên bất cứ đâu cũng được)
Vấn đề là do đang ĐỐ VUI nên không biết anh sealand có mẹo gì không?
Nếu anh sealand khẳng định loại trừ cách dùng hàm API thì quả thật mình chưa nghĩ ra được cách gì khác
 
Upvote 0
Câu đố này xuất phát từ việc khai báo biến mà hiện thời mình vẫn đang thắc mắc chưa hiểu rõ. Anh em tham khảo 2 đoạn Code cho CommandButton1 sau nha:

1/Code này nhấn sẽ thay đổi Title của Form:

Mã:
Private Sub CommandButton1_Click()
Dim Frm As Object
Set Frm = CommandButton1.Parent
Frm.Caption = "WELLCOME"
End Sub

2/Code sau không đổi Title mà lại in xuống nền Form:

Mã:
Private Sub CommandButton1_Click()
Dim Frm As MSforms.UserForm
Set Frm = CommandButton1.Parent
Frm.Caption = "WELLCOME"
End Sub

Hì, vừa trả lời vừa hỏi kể cũng kỳ.
 
Upvote 0
Câu đố này xuất phát từ việc khai báo biến mà hiện thời mình vẫn đang thắc mắc chưa hiểu rõ. Anh em tham khảo 2 đoạn Code cho CommandButton1 sau nha:

1/Code này nhấn sẽ thay đổi Title của Form:

Mã:
Private Sub CommandButton1_Click()
Dim Frm As Object
Set Frm = CommandButton1.Parent
Frm.Caption = "WELLCOME"
End Sub

2/Code sau không đổi Title mà lại in xuống nền Form:

Mã:
Private Sub CommandButton1_Click()
Dim Frm As MSforms.UserForm
Set Frm = CommandButton1.Parent
Frm.Caption = "WELLCOME"
End Sub

Hì, vừa trả lời vừa hỏi kể cũng kỳ.

Hơi bị bất ngờ đấy. Đúng là nhiều khi không biết con ma nó đi đường mòn nào.

Nếu ta có trên Form các controls như sau
View attachment 113002
và code
Mã:
Private Sub CommandButton1_Click()
Dim Frm As [COLOR=#ff0000]MSforms.UserForm[/COLOR] ' MSforms.Frame   ' Object
    Set Frm = CommandButton1.Parent
    Frm.Caption = "WELLCOME"
End Sub

Private Sub CommandButton2_Click()
Dim Frm As [COLOR=#ff0000]MSforms.UserForm[/COLOR]
    Set Frm = CommandButton2.Parent
    Frm.Caption = "WELLCOME"
End Sub

thì nhấn CommandButton2 cho WELLCOME ở dưới thanh tiêu đề, nhưng nhấn CommandButton1 thì có WELLCOME ở Frame2 vì đối tượng Frame2 được trả về. Trong CommandButton1_Click thì Frm có thể khai báo là Object, MSforms.Frame, MSforms.UserForm đều được và kết quả trả về luôn là Frame2, tức container trực tiếp của CommandButton2.

Trong 2 trường hợp dưới đây thì số lượng controls, chủng loại và cấu trúc đều như nhau nhưng tùy khai báo trong CommandButton1_Click

Với khai báo Dim Frm As MSforms.UserForm thì ta có
View attachment 113003

Với khai báo Dim Frm As Object hoặc Dim Frm As MSforms.Page ta có
test3.JPG

Ai mà ngờ được những rắc rối nay? botay.toantap.com
 
Upvote 0
Giả sử tôi có 3 sheet
- Sheet thứ nhất có tên là "Nguyễn" và Sheet CodeName là "S1"
- Sheet thứ hai có tên là "Anh" và Sheet CodeName là "S2"
- Sheet thứ ba có tên là "Tuấn" và Sheet CodeName là "S3"
-----------
Giờ ta gõ:
- Cell A1 chữ S1
- Cell A2 chữ S2
- Cell A3 chữ S3
Xin hỏi: Dùng code thế nào để:
- Kết quả tại B1 là Nguyễn
- Kết quả tại B2 là Anh
- Kết quả tại B3 là Tuấn
-------------
Tức biến đầu vào là Sheet CodeName (dạng String) và kết quả đầu ra là Sheet Name (dạng String)

Câu hỏi ngược lại: Viết một hàm để tìm Sheet CodeName nếu biết Sheet Name. (Chỉ một dòng Code tương tự bài #521)
Mở rộng: Dùng vòng lặp duyệt qua các WorkSheets để đổi tên tất cả các Sheet CodeName.

Mời tất cả các bạn tham gia cho vui!
 
Lần chỉnh sửa cuối:
Upvote 0
Câu hỏi ngược lại: Viết một hàm để tìm Sheet CodeName nếu biết Sheet Name. (Chỉ một dòng Code tương tự bài #521)
Mở rộng: Dùng vòng lặp duyệt qua các WorkSheets để đổi tên tất cả các Sheet CodeName.

Mời tất cả các bạn tham gia cho vui!

Mã:
Sub RenameSheetCodeName(ByVal wb As Workbook, ByVal SheetName As String, ByVal newSheetCodeName As String)
Dim CodeName As String
    CodeName = wb.Sheets(SheetName).CodeName    ' đọc Sheet CodeName nếu biết Sheet Name
    wb.VBProject.VBComponents(CodeName).name = newSheetCodeName
End Sub
 
Upvote 0
Mã:
Sub RenameSheetCodeName(ByVal wb As Workbook, ByVal SheetName As String, ByVal newSheetCodeName As String)
Dim CodeName As String
    CodeName = wb.Sheets(SheetName).CodeName    ' đọc Sheet CodeName nếu biết Sheet Name
    wb.VBProject.VBComponents(CodeName).name = newSheetCodeName
End Sub
Chưa đạt yêu cầu anh siwtom ơi!
Làm khó sư phụ tí, hi hi ... lâu lâu mới có dịp múa rìu qua mắt thợ dại gi không múa, mình đúng sai tính sau.
 
Upvote 0
Chưa đạt yêu cầu anh siwtom ơi!
Làm khó sư phụ tí, hi hi ... lâu lâu mới có dịp múa rìu qua mắt thợ dại gi không múa, mình đúng sai tính sau.

PHP:
Sheets(SheetName).CodeName

Code này sao không đạt yêu cầu nhỉ? Mà cái này hình như có nói trên GPE rồi.
 
Upvote 0
PHP:
Sheets(SheetName).CodeName

Code này sao không đạt yêu cầu nhỉ? Mà cái này hình như có nói trên GPE rồi.

Cho danh mục các tên Sheet vào cột A, với dòng code đó, bạn làm sao để viết hàm để lấy CodeName các sheet đã liệt kê vào cột B đây?, yêu cầu là viết hàm mà, hàm đó cũng có thể dùng trong VBA.
Rồi thêm câu hỏi khuyến mãi nữa: Thủ tục đổi tên tất cả các Sheet CodeName trong các WorkSheets

PS: Bạn chỉ giùm đường dẫn chổ nào đã có "cái này" trên GPE!
 
Lần chỉnh sửa cuối:
Upvote 0
Cho danh mục các tên Sheet vào cột A, với dòng code đó, bạn làm sao để viết hàm để lấy CodeName các sheet đã liệt kê vào cột B đây?, yêu cầu là viết hàm mà, hàm đó cũng có thể dùng trong VBA.

Ủa! Anh nói sao em không hiểu nhỉ? Dòng code đó là đạt rồi còn gì? Có viết thành HÀM thì cũng là dòng code ấy thôi. Ví dụ:
Mã:
Function SheetCodeName(ByVal SheetName As String) As String
  SheetCodeName = Sheets(SheetName).CodeName
End Function
Hay anh còn ẩn ý gì trong "trái ổi" nữa?
--------------------------------
(Code này nếu viết rõ hơn phải có thêm biến Workbook nữa mới chính xác)
 
Upvote 0
Cho danh mục các tên Sheet vào cột A, với dòng code đó, bạn làm sao để viết hàm để lấy CodeName các sheet đã liệt kê vào cột B đây?, yêu cầu là viết hàm mà, hàm đó cũng có thể dùng trong VBA.
Rồi thêm câu hỏi khuyến mãi nữa: Thủ tục đổi tên tất cả các Sheet CodeName trong các WorkSheets

PS: Bạn chỉ giùm đường dẫn chổ nào đã có "cái này" trên GPE!
Hàm lấy CodeName
PHP:
 Function CodeShName(ByVal ShName As String) As String
CodeShName = Sheets(ShName).CodeName
End Function
Công thức cho B1
Mã:
=CodeShName(A1)
Sử dụng trong VBA
PHP:
Sub Test()
MsgBox CodeShName("Sheet1")
End Sub
Đổi tên tất cả các Sheet CodeName
PHP:
Sub ChangeAllCodeShName()
Dim Sh As Worksheet, i As Long
For Each Sh In Sheets
    If Sh.Type = xlWorksheet Then
        i = i + 1
        ActiveWorkbook.VBProject.VBComponents(Sh.CodeName).Name = "CodeShName" & i
    End If
Next
End Sub
Đây là một trong các Link nói về lấy và đổi CodeName của Sheet.
http://www.giaiphapexcel.com/forum/showthread.php?5048-Code-Name
 
Upvote 0
Hàm lấy CodeName
PHP:
 Function CodeShName(ByVal ShName As String) As String
CodeShName = Sheets(ShName).CodeName
End Function
Công thức cho B1
Mã:
=CodeShName(A1)
Sử dụng trong VBA
PHP:
Sub Test()
MsgBox CodeShName("Sheet1")
End Sub
Đổi tên tất cả các Sheet CodeName
PHP:
Sub ChangeAllCodeShName()
Dim Sh As Worksheet, i As Long
For Each Sh In Sheets
    If Sh.Type = xlWorksheet Then
        i = i + 1
        ActiveWorkbook.VBProject.VBComponents(Sh.CodeName).Name = "CodeShName" & i
    End If
Next
End Sub
Đây là một trong các Link nói về lấy và đổi CodeName của Sheet.
http://www.giaiphapexcel.com/forum/showthread.php?5048-Code-Name


Hì mình chịu bạn rồi, sory nha!, tại vì phương án của mình đưa ra hơi khác, không nghờ bạn lại có một cách khác
Mình dùng Properties tương tự như HLMT làm ở đây.
 
Upvote 0
Cho danh mục các tên Sheet vào cột A, với dòng code đó, bạn làm sao để viết hàm để lấy CodeName các sheet đã liệt kê vào cột B đây?, yêu cầu là viết hàm mà, hàm đó cũng có thể dùng trong VBA.
Rồi thêm câu hỏi khuyến mãi nữa: Thủ tục đổi tên tất cả các Sheet CodeName trong các WorkSheets

PS: Bạn chỉ giùm đường dẫn chổ nào đã có "cái này" trên GPE!

Bắt bẻ thế thì bó tay rồi. Vì tôi lười nên viết một sub thôi nhưng có chỉ cách lấy tên. Còn chuyện viết thành hàm thì khó gì.
 
Upvote 0
Cho danh mục các tên Sheet vào cột A, với dòng code đó, bạn làm sao để viết hàm để lấy CodeName các sheet đã liệt kê vào cột B đây?, yêu cầu là viết hàm mà, hàm đó cũng có thể dùng trong VBA.
Rồi thêm câu hỏi khuyến mãi nữa: Thủ tục đổi tên tất cả các Sheet CodeName trong các WorkSheets

...

Chẳng liên quan gì tới tôi nhưng xin phép cho tôi thắc mắc: tại sao lại phải dùng hàm? Nếu dùng hàm thì trả về cái gì? Công việc là lấy dữ liệu cột A, kết quả ghi vào cột B. Vậy thì mục đích của trị được hàm trả về là gì?
 
Upvote 0
Bạn cần Hàm thì ta vẫn sử dụng Hàm được chớ sao.
Mình ngại viết lại Code lấy danh sách từ sheet mà đổi luôn Sub của HuuThang thử xem

Mã:
Function ChangeAllCodeShName() As Boolean
Dim Sh As Worksheet, i As Long
For Each Sh In Sheets
    If Sh.Type = xlWorksheet Then
        i = i + 1
        ActiveWorkbook.VBProject.VBComponents(Sh.CodeName).Name = "CodeShName" & i
    End If
Next
ChangeAllCodeShName = True
End Function
'------------------------------------------------------------------------------------
Sub Test()
MsgBox ChangeAllCodeShName()

End Sub

Nhất định bạn không thể bảo đây chẳng phải là Hàm
 
Upvote 0
Sub chỉ chạy được bằng cách nhấn Button

- Giả định tôi có 1 Sub:
Mã:
Sub GiGiDo()
  .....
  .....
End Sub
- Tôi vẽ 1 Button và Assign Macro Button này với Sub GiGiDo
- Xin hỏi: Tôi phải viết gì trong Sub để chỉ cho phép chạy code khi nhấn vào Button mà thôi ---> Có nghĩa là không chạy được trực tiếp trong cửa sổ lập trình, cũng không chạy được bằng cách Alt + F8 để gọi Sub
-------------------
Nói thêm: Nội dung Sub GiGiDo các bạn muốn viết cái gì tùy ý, miễn đạt được mục đích như dòng màu xanh ở trên
Câu đố này rất dễ
 
Upvote 0
Thì bắt nó truyền tham số gì đó ví dụ

Mã:
Sub Test(Name As String)
MsgBox "OK"
End Sub

và nút lệnh cũng truyền vớ vẩn chi đó

Mã:
Private Sub CommandButton1_Click()
Test ""
End Sub

Tóm lại, Sub nhận tham số chỉ chạy từ 1 sub hay hàm khác có truyền cho nó tham số. Để tránh truyền ta có thể viết:

Mã:
Sub Test(Optional Name As String = "")
MsgBox "OK"
End Sub

Và Sub goi giờ có thể viết

Mã:
Private Sub CommandButton1_Click()
Test 
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Bắt bẻ thế thì bó tay rồi. Vì tôi lười nên viết một sub thôi nhưng có chỉ cách lấy tên. Còn chuyện viết thành hàm thì khó gì.

Không phải là bắt bẻ nhưng do khác với của em nên chưa biết cách sử dụng, cảm ơn anh

Chẳng liên quan gì tới tôi nhưng xin phép cho tôi thắc mắc: tại sao lại phải dùng hàm? Nếu dùng hàm thì trả về cái gì? Công việc là lấy dữ liệu cột A, kết quả ghi vào cột B. Vậy thì mục đích của trị được hàm trả về là gì?
Có lẽ bạn chưa biết Sheet CodeName, bạn xem hàm trong file bên dưới.

Bạn cần Hàm thì ta vẫn sử dụng Hàm được chớ sao.
Mình ngại viết lại Code lấy danh sách từ sheet mà đổi luôn Sub của HuuThang thử xem

Mã:
Function ChangeAllCodeShName() As Boolean
Dim Sh As Worksheet, i As Long
For Each Sh In Sheets
    If Sh.Type = xlWorksheet Then
        i = i + 1
        ActiveWorkbook.VBProject.VBComponents(Sh.CodeName).Name = "CodeShName" & i
    End If
Next
ChangeAllCodeShName = True
End Function
'------------------------------------------------------------------------------------
Sub Test()
MsgBox ChangeAllCodeShName()

End Sub

Nhất định bạn không thể bảo đây chẳng phải là Hàm

Em nhất định bảo đấy là hàm rồi nhưng không phải hàm em cần, hu hu ...

Còn đây là code của mình:
Mã:
Sub EditWorksheetCodenames()
    Dim Ws As Worksheet, i As Integer
    If TypeName(ActiveWorkbook) = "Nothing" Then Exit Sub
    For Each Ws In ActiveWorkbook.Worksheets
        i = i + 1
        On Error Resume Next
        'Cells(i, 1) = Ws.Name
        Ws.Parent.VBProject.vbcomponents(Ws.CodeName).Properties("_CodeName") = "GPE" & i
        'On Error GoTo 0
    Next Ws
End Sub


Function shCodeName(ByVal shName As String) As String
    On Error Resume Next    ' Neu khong tim thay Sheet shName
    shCodeName = ActiveWorkbook.VBProject.vbcomponents(Sheets(shName).CodeName).Properties("_CodeName")
End Function
 

File đính kèm

Upvote 0
Thì bắt nó truyền tham số gì đó ví dụ

Mã:
Sub Test(Name As String)
MsgBox "OK"
End Sub

và nút lệnh cũng truyền vớ vẩn chi đó

Mã:
Private Sub CommandButton1_Click()
Test ""
End Sub

Tóm lại, Sub nhận tham số chỉ chạy từ 1 sub hay hàm khác có truyền cho nó tham số. Để tránh truyền ta có thể viết:

Mã:
Sub Test(Optional Name As String = "")
MsgBox "OK"
End Sub

Và Sub goi giờ có thể viết

Mã:
Private Sub CommandButton1_Click()
Test 
End Sub
Hình như anh đang trả lời câu đố của em?
Em nói rõ là BUTTON cơ mà
- Tôi vẽ 1 ButtonAssign Macro Button này với Sub GiGiDo
BUTTON thì mới Assign Macro được chứ anh!
Còn anh thì lại sửa thành COMMANDBUTTON, 2 loại control khác nhau hoàn toàn
Thêm nữa, em ghi Sub GiGiDo() hoàn toàn không có cái vụ "tham số truyền" ở đây! Chỉ hỏi mọi người về NỘI DUNG của sub thôi
Tóm lại: Nội dung code của Sub này sẽ quyết định tất cả
 
Upvote 0
Còn đây là code của mình:
Mã:
Sub EditWorksheetCodenames()
    Dim Ws As Worksheet, i As Integer
    If TypeName(ActiveWorkbook) = "Nothing" Then Exit Sub
    For Each Ws In ActiveWorkbook.Worksheets
        i = i + 1
        On Error Resume Next
        'Cells(i, 1) = Ws.Name
        Ws.Parent.VBProject.vbcomponents(Ws.CodeName).Properties("_CodeName") = "GPE" & i
        'On Error GoTo 0
    Next Ws
End Sub


Function shCodeName(ByVal shName As String) As String
    On Error Resume Next    ' Neu khong tim thay Sheet shName
    shCodeName = ActiveWorkbook.VBProject.vbcomponents(Sheets(shName).CodeName).Properties("_CodeName")
End Function
Cái này là do người ta cứ suy nghĩ quá xa mà không cho rằng vấn đề đơn giản hơn nhiều đấy anh à!
Lấy Codename đó là chuyện bình thường thôi
 
Upvote 0
- Giả định tôi có 1 Sub:
Mã:
Sub GiGiDo()
  .....
  .....
End Sub
- Tôi vẽ 1 Button và Assign Macro Button này với Sub GiGiDo
- Xin hỏi: Tôi phải viết gì trong Sub để chỉ cho phép chạy code khi nhấn vào Button mà thôi ---> Có nghĩa là không chạy được trực tiếp trong cửa sổ lập trình, cũng không chạy được bằng cách Alt + F8 để gọi Sub
-------------------
Nói thêm: Nội dung Sub GiGiDo các bạn muốn viết cái gì tùy ý, miễn đạt được mục đích như dòng màu xanh ở trên
Câu đố này rất dễ

Cái này mà là trong Delphi thì quá dễ. Cái "khung" của ButtonClick là thế này
Mã:
procedure TForm1.Button1Click([COLOR=#ff0000]Sender[/COLOR]: TObject);
begin
    ' code A kiểm tra Sender
end;

Nếu ta nhấn Button1 và trong procedure/sub đọc ra thì Sender chính là đối tượng Button1.
Nhưng nếu ta gọi thế này:

Mã:
procedure TForm1.Button2Click(Sender: TObject);
begin
        Button1Click(Form1); '<-- tức CALL sub Button1Click
end;

thì code A sẽ trả về đối tượng Sender = Form1. THay cho Form1 có thể truyền bắt cứ con, cháu, chắt, chít nào của TObject (Object), tức class/object di truyền từ TObject (Object), hoặc truyền NIL (trong VBA tương ứng là NOTHING.
------------
Trong VBA thì chắc là Caller

Mã:
Sub GiGiDo()
    If TypeName(Application.Caller) = "String" Then
        If Application.Caller = "Button1" Then
            MsgBox "Xin moi xin moi"
        Else
            MsgBox "bye-bye"
        End If
    Else
        MsgBox "bye-bye"
    End If
End Sub

Sub test()
    GiGiDo
End Sub

Gọi test không được, nhấn Button2 (cùng macro) cũng không được
 
Upvote 0
Cái này là do người ta cứ suy nghĩ quá xa mà không cho rằng vấn đề đơn giản hơn nhiều đấy anh à!
Lấy Codename đó là chuyện bình thường thôi

Thì ndu cũng thường nhắc nhở rằng topic này là để vui, mới lạ, độc đáo mà.
Trước khi hỏi mình cũng tìm hiểu Properties của Sheet CodeName đâu có trên GPE đâu. Hỏi để tìm giải pháp mới, với mục đích làm phong phú cho Forum chớ chưa hẳn đã hay hoặc hay nhất.
Trước đây mình đã thấy một thấy một số cao thủ nói rằng Sheet CodeName là thuộc tính Read-only rất khó Edit bằng code sao gọi là chuyện bình thường được?
 
Upvote 0
Trong VBA thì chắc là Caller

Đó chính là vấn đề (cái Caller)
Còn việc viết gì trong Sub thì tùy ý mọi người, miễn sao có sự tồn tại của Caller để CHỈ DUY NHẤT BUTTON mới gọi được Sub
Thế thôi!
Như em, viết thế này cũng được
Mã:
Sub GiGiDo()
  MsgBox Application.Caller
End Sub
(Đúng ra sau 3 ngày nữa, nếu không ai trả lời thì anh siwtom mới có quyền trả lời, thế mới công bằng chứ nhỉ?)
Ẹc... Ẹc...
---------------
Trước đây mình đã thấy một thấy một số cao thủ nói rằng Sheet CodeName là thuộc tính Read-only rất khó Edit bằng code sao gọi là chuyện bình thường được?
Edit thì khó nhưng chỉ LẤY TÊN CÙA NÓ thì đúng là chuyện bình thường mà anh! Và em cũng chỉ đang nói về vụ lấy tên thôi
(trong khi chỉ cái chuyện lấy tên bình thường ấy anh lại đi đường vòng cho mất công.... Ẹc... Ẹc...)
 
Lần chỉnh sửa cuối:
Upvote 0
...
Có lẽ bạn chưa biết Sheet CodeName, bạn xem hàm trong file bên dưới.

...
Còn đây là code của mình:
Mã:
[COLOR=#ff0000][B]Sub EditWorksheetCodenames()[/B][/COLOR]
    Dim Ws As Worksheet, i As Integer
    If TypeName(ActiveWorkbook) = "Nothing" Then Exit Sub
    For Each Ws In ActiveWorkbook.Worksheets
        i = i + 1
        On Error Resume Next
        'Cells(i, 1) = Ws.Name
        Ws.Parent.VBProject.vbcomponents(Ws.CodeName).Properties("_CodeName") = "GPE" & i
        'On Error GoTo 0
    Next Ws
End Sub


Function shCodeName(ByVal shName As String) As String
    On Error Resume Next    ' Neu khong tim thay Sheet shName
    shCodeName = ActiveWorkbook.VBProject.vbcomponents(Sheets(shName).CodeName).Properties("_CodeName")
End Function

Việc biết hay không biết Sheet CodeName chả liên quan gì đến hàm cả.

EditWorksheetCodenames() trả về cái gì mới quan trọng. Theo code trên thì nó là Sub.

Thắc mắc của tôi thực ra là câu đố ngầm. Nên cho nó trả về cái gì?

Theo như code trước đây thì có vài bạn muốn trả về True/False. Nhưng nếu tôi viết hàm này thì tôi cho nó trả về số sheets mà nó đổi tên - dĩ nhiên là nếu nó chả đổi sheet nào thì nó trả về 0.
 
Upvote 0
Đó chính là vấn đề (cái Caller)
Còn việc viết gì trong Sub thì tùy ý mọi người, miễn sao có sự tồn tại của Caller để CHỈ DUY NHẤT BUTTON mới gọi được Sub
Thế thôi!
Như em, viết thế này cũng được
Mã:
Sub GiGiDo()
  MsgBox Application.Caller
End Sub
^^ bh em biết thêm được caller <--- cảm ơn diễn đàn GPE nói chung và anh Ndu, Switom nói riêng :D
Nếu em viết như vầy :
Mã:
Sub GPE()
    Dim button1 As Button
        Set button1 = Worksheets(1).Buttons(Application.Caller)
        MsgBox button1.Name
End Sub
Application.Caller --> như là một Name động của các button vậy , ta chỉ cần click bất kỳ button nào thì code đều chạy hết --> em hiểu vậy có đúng không các anh nhj ??
 
Lần chỉnh sửa cuối:
Upvote 0
^^ bh em biết thêm được caller <--- cảm ơn diễn đàn GPE nói chung và anh Ndu, Switom nói riêng :D
Nếu em viết như vầy :
Mã:
Sub GPE()
    Dim button1 As Button
        Set button1 = Worksheets(1).Buttons(Application.Caller)
        MsgBox button1.Name
End Sub
Application.Caller --> như là một Name động của các button vậy , ta chỉ cần click bất kỳ button nào thì code đều chạy hết --> em hiểu vậy có đúng không các anh nhj ??

Bất cứ button nào Assign Maco với Sub GPE chứ
Giải thích thế này sẽ dễ hiểu:
- TUI chính là Sub GPE
- Còn thằng nào "gọi điện thoại" đến TUI thì thằng đó là CALLER
 
Upvote 0
Đố về Freeze Panes.

Trong sheet chứa Freeze Panes, đố các bạn xác định được ô nào đầu tiên giao nhau mà không bị đóng băng.

(Trong File đính kèm, ô cần tìm là ô DP107).
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0

File đính kèm

  • FreezePanes.jpg
    FreezePanes.jpg
    39 KB · Đọc: 51
Upvote 0
Dùng send keys ctrl+home là sẽ lấy được địa chỉ của nó.
Cũng là một giải pháp rất hay, nhưng nếu không dùng SendKeys thì còn cách nào nữa không?

Giả sử cột cần tìm là cột hoặc hàng, hoặc cả hai bị HIDE thì cách send keys ctrl+home không phát huy được tác dụng nha!
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox ActiveWindow.VisibleRange(1, 1).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!
 
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox [B][COLOR=#ff0000]ActiveWindow.VisibleRange(1, 1)[/COLOR][/B].Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!

Sẳn đây đố luôn, nếu thay "cái vụ" màu đỏ thành một thủ tục khác, vậy theo các bạn sẽ thay vào đó cái gì để có kết quả như chưa thay? Nói chung là không dùng VisibleRange.
 
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox ActiveWindow.VisibleRange(1, 1).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!

Có thể dùng cách khác mà không cần phải dùng đến Scroll.
 
Upvote 0
Upvote 0
Thủ thuật này nó sẽ lấy địa chỉ ở cell chéo với DP107, đó là cell DO106 + thêm 1 dòng và 1 cột sẽ ra kết quả:
Chắc HLMT đang nói đến Panes(x) với x từ 1 đến 4 phải không? Nhưng trước khi làm phải Panes.Count trước đấy nhé, không thôi sẽ gặp lỗi đấy! (chỉ đóng băng dòng hoặc đóng băng cột).

Nhưng để tránh rắc rối, hay bẩy lỗi nhiều, mình không dùng VisibleRange luôn.
 
Lần chỉnh sửa cuối:
Upvote 0
Chắc HLMT đang nói đến Panes(x) với x từ 1 đến 4 phải không? Nhưng trước khi làm phải Panes.Count trước đấy nhé, không thôi sẽ gặp lỗi đấy! (chỉ đóng băng dòng hoặc đóng băng cột).

Nhưng để tránh rắc rối, hay bẩy lỗi nhiều, mình không dùng VisibleRange luôn.

Vầy chắc được:
Mã:
Sub GoHome()
  With ActiveWindow
    .ScrollRow = 1
    .ScrollColumn = 1
    Application.Goto Cells(.ScrollRow, .ScrollColumn), True
  End With
  MsgBox ActiveCell.Address
End Sub
 
Upvote 0
Vầy chắc được:
Mã:
Sub GoHome()
  With ActiveWindow
    .ScrollRow = 1
    .ScrollColumn = 1
    Application.Goto Cells(.ScrollRow, .ScrollColumn), True
  End With
  MsgBox ActiveCell.Address
End Sub
Đúng là em đã dùng cách này! Nhưng gọn hơn tí!

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox [COLOR=#ff0000]Cells(.ScrollRow, .ScrollColumn)[/COLOR].Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Tuy rằng ta đặt .ScrollRow = 1, .ScrollColumn = 1, nhưng nếu gặp FreezePanes nó sẽ dừng lại nơi mà ta thiết lập, vì thế, lợi dụng điểm này ta có thể lấy được hàng và cột của chúng.
 
Lần chỉnh sửa cuối:
Upvote 0
Đúng là em đã dùng cách này! Nhưng gọn hơn tí!

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
          [COLOR=#ff0000]  .ScrollRow = 1
            .ScrollColumn = 1[/COLOR]
            MsgBox Cells([COLOR=#ff0000].ScrollRow, .ScrollColumn[/COLOR]).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Tuy rằng ta đặt .ScrollRow = 1, .ScrollColumn = 1, nhưng nếu gặp FreezePanes nó sẽ dừng lại nơi mà ta thiết lập, vì thế, lợi dụng điểm này ta có thể lấy được hàng và cột của chúng.
Ở trên em có nói cái chổ màu đỏ không cần dùng Sroll.
 
Upvote 0

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

Back
Top Bottom