Các câu đố, bài tập nhằm ôn tập & bổ sung kiến thức căn bản VBA (1 người xem)

Liên hệ QC

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

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,662
Được thích
16,725
Giới tính
Nam
Với tinh thần chơi mà học, học mà chơi, nên tôi đã mở ra topic này, hy vọng các thành viên tham gia, nhất là các thành viên mới biết về VBA.

Sau đây là câu hỏi đầu tiên:

Câu hỏi 1: Bằng phương pháp nào nhanh nhất để tìm ra ô nào trong một cột chứa một điều kiện.

Tôi có 1 file Excel 2007, với cột A, từ A1 đến A1048576 đều có giá trị.

Bằng phương pháp nào nhanh nhất (dùng mảng, dùng For Each v.v...) để tìm ra ô nào trong cột A chứa chữ "Nghia", đồng thời với ô ở cột B tương ứng nhập giá trị "OK" vào đó?

Ví dụ tìm thấy trong ô A2 có giá trị là "Nghia" thì ô B2 nhập vào "OK".

Hiện tại, đáp án nhanh nhất mà tôi có được đã gửi mail riêng (nhằm ghi lại thời gian gửi, để tránh nói ăn gian).

Để tiện việc theo dõi các câu đố, các bài tập tôi đã tạo ra topic này các bạn click vào đây:

Các link của topic "Các câu đố, bài tập nhằm ôn tập & bổ sung kiến thức căn bản VBA"
 

File đính kèm

Lần chỉnh sửa cuối:
Em đề nghị các ace tiếp tục cho các đề bài cơ bản/ căn bản khác để những người mới như em rèn luyện/ trao đổi thêm...
tks
 
Upvote 0
Một câu trong bài test cuối khóa VBA căn bản:
(Người ra đề: ptm0412)
Đề trong file word, làm bài trong file excel.

Các bạn có thể tham khảo và làm thử. Chương trình căn bản gói gọn trong đó, không có biến mảng.
Em xin được trả lời bài tập, mong các anh chị đừng ném đá em tội nghiệp.

[GPECODE=vb]Sub BaiTap_XiTin()
Dim adoConn As Object, adoRS As Object
Dim strDK As Variant, Kho As String, i As Integer, strKQ As String
Kho = UCase(InputBox("Ban chon loai SP nao?" & vbLf & "(a,b,c,d)", "Chon loai"))
If Len(Kho) = 0 Then Exit Sub
strDK = Filter(Array("A", "B", "C", "D"), Kho)
If UBound(strDK) >= 0 Then
Set adoConn = CreateObject("ADODB.Connection")
Set adoRS = CreateObject("ADODB.Recordset")
With adoConn
.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & ThisWorkbook.FullName & _
";Extended Properties=""Excel 8.0;HDR=No;IMEX=1"";"
.Open
End With
With adoRS
.ActiveConnection = adoConn
.Open "SELECT F1,sum(F2),sum(F3),sum(F4),sum(F5) " & _
"FROM [Tinhtong$A3:E16] " & _
"GROUP BY F1 " & _
"HAVING UCASE(F1) like '" & Kho & "'"
For i = 1 To 4
strKQ = strKQ & vbNewLine & "- Store 0" & i & ": " & Format(.Fields(i).Value, "#,##0")
Next i
MsgBox "Tong doanh so mat hang " & .Fields(0).Value & ":" & strKQ, , "Ket qua"
End With
Else
MsgBox "Chon khong dung san pham"
Exit Sub
End If
Erase strDK
adoRS.Close: Set adoRS = Nothing
adoConn.Close: Set adoConn = Nothing


End Sub


[/GPECODE]
 
Upvote 0
[GPECODE=vb]
With adoRS
.ActiveConnection = adoConn
.Open "SELECT F1,sum(F2),sum(F3),sum(F4),sum(F5) " & _
"FROM [Tinhtong$A3:E16] " & _
"GROUP BY F1 " & _
"HAVING UCASE(F1) like '" & Kho & "'"
For i = 1 To 4
strKQ = strKQ & vbNewLine & "- Store 0" & i & ": " & Format(.Fields(i).Value, "#,##0")
Next i
MsgBox "Tong doanh so mat hang " & .Fields(0).Value & ":" & strKQ, , "Ket qua"
End With
[/GPECODE]
Hic, Lính mới như em nhìn code ADO là "hoa hết cả mắt". Nếu được, mong các Anh chị giải thích cặn kẽ hơn code trên từng dòng một; F1, 2, 3, 4, 5 lấy ở đâu, lấy ntn, nguyên tắc lấy? và xin cho biết những kinh nghiệm/ lưu ý khi sử dụng ADO
many tks
 
Lần chỉnh sửa cuối:
Upvote 0
Hic, Lính mới như em nhìn code ADO là "hoa hết cả mắt". Nếu được, mong các Anh chị giải thích cặn kẽ hơn code trên từng dòng một; F1, 2, 3, 4, 5 lấy ở đâu, lấy ntn, nguyên tắc lấy? và xin cho biết những kinh nghiệm/ lưu ý khi sử dụng ADO
many tks
F1 ->F5 là thứ tự cột trong vùng A3:E16 (A là F1, B là F2...) vì khai báo HDR=No nên mặc định như thế.
Bạn muốn học ado thì tải ebook sau về đọc nhé.

http://www.giaiphapexcel.com/forum/content.php?44-eBook-ADO-tòan-tập
 
Upvote 0
Nói về bài Ending-Test, đối với trình độ căn bản và tôi chấm điểm thì chỉ cần thế này là đạt:
(Code để trong sheet)
PHP:
Sub tinhtong()
Dim Loai As String, Tong1 As Double, Tong2 As Double, Tong3 As Double, Tong4 As Double
Dim EndR As Long

EndR = [A1000].End(xlUp).Row
Loai = InputBox("Ban chon loai SP nao?" & Chr(13) & "(a, b, c, d)", "Chon loai", "a")
If Loai = "" Then Exit Sub
For i = 3 To EndR
    If Cells(i, 1) = Loai Then
        Tong1 = Tong1 + Cells(i, 2)
        Tong2 = Tong2 + Cells(i, 3)
        Tong3 = Tong3 + Cells(i, 4)
        Tong4 = Tong4 + Cells(i, 5)
     End If
Next
MsgBox "Tong doanh so mat hang " & Loai & ":" & Chr(13) & _
    "- " & [B2] & ": " & Format(Tong1, "#,##0") & Chr(13) & _
    "- " & [C2] & ": " & Format(Tong2, "#,##0") & Chr(13) & _
    "- " & [D2] & ": " & Format(Tong3, "#,##0") & Chr(13) & _
    "- " & [E2] & ": " & Format(Tong4, "#,##0"), vbOKOnly, "Ket qua"
End Sub

1. Không cần Do loop để chọn đúng mặt hàng, bởi vì gõ sai tên mặt hàng thì tổng doanh số bằng 0, MsgBox cũng thể hiện kết quả bằng 0 cho cả 4 cửa hàng. Kết quả đúng.
2. InputBox có Default là 1 mặt hàng a, nếu ok ngay thì tính mặt hàng a, nếu nhấn Cancel thì thoát, không tính.
3. Định dạng #,##0 thì kết quả 0 cũng thể hiện 0

Ngoài ra, nếu viết code dùng vòng lặp ghi các dòng đúng mặt hàng chọn ra vùng tạm rồi tính tổng vùng tạm, cũng OK

Các bài giải trên đây đã sử dụng thêm code kiểm tra tên mặt hàng gõ vào, càng tốt. Tuy nhiên như bài 138 và 141 có viết:
- Không bắt buộc người dùng phải tính, họ có quyền cancel trên InputBox
- Khi chọn sai, MsgBox thông báo không dùng vbOKOnly (mặc định) để hành hạ người dùng phải nhập đúng mới cho thoát, mà người dùng cũng có quyền cancel trên MsgBox thông báo này.

Để thân thiện, nếu người dùng chọn sai, bạn hỏi người dùng có muốn chọn lại không, và dùng vbYesNo, để người dùng có thể chọn No

Vậy đoạn code đó như sau:

PHP:
Do
    Loai = InputBox("Ban chon loai SP nao?" & Chr(13) & "(a, b, c, d)", "Chon loai", "a")
    If Loai = "" Then Exit Sub
    If Loai = "a" Or Loai = "b" Or Loai = "c" Or Loai = "d" Then
        Exit Do
    Else
        Thongbao = MsgBox("Khong co mat hang nay, ban co chon lai khong?", _
        vbYesNo, "Thong bao")
        If Thongbao = vbNo Then Exit Sub
    End If
       
Loop
For i = 3 To EndR
...
 
Lần chỉnh sửa cuối:
Upvote 0
Nói thêm: Vì bài EndingTest là bài kiểm tra cuối khóa, nên ra đề buộc phải sử dụng những vấn đề đã giới thiệu trong khóa học:

- Khai báo biến, kiểu biến (chưa dùng biến mảng)
- Phương thức End
- Cấu trúc If Then Else End If
- Cấu trúc vòng lặp For Next và/hoặc Do loop
- Giao tiếp với người dùng: InputBox, MsgBox với đầy đủ trường hợp nhấn nút trên phương thức giao tiếp.
- Hàm Format

Còn áp dụng thuật toán nào, tạo ra bao nhiêu biến, sử dụng biến thế nào để ra kết quả, là việc của người làm bài.

Câu hỏi sau đây dễ hơn, nhưng cũng cần phải suy luận:

a. Dùng vòng lặp For - Next để thể hiện 56 màu của Bảng màu Excel 2003 lên cột A bắt đầu từ A1. Đồng thời trên cột B ghi chỉ số màu tương ứng
b. Cũng giống câu a, nhưng dùng step 2 để chỉ thể hiện các màu có chỉ số màu chẵn, liên tục từ A1 đến A28, chỉ số màu tương ứng trên cột B
 
Lần chỉnh sửa cuối:
Upvote 0
Nói thêm: Vì bài EndingTest là bài kiểm tra cuối khóa, nên ra đề buộc phải sử dụng những vấn đề đã giới thiệu trong khóa học:

- Khai báo biến, kiểu biến (chưa dùng biến mảng)
- Phương thức End
- Cấu trúc If Then Else End If
- Cấu trúc vòng lặp For Next và/hoặc Do loop
- Giao tiếp với người dùng: InputBox, MsgBox với đầy đủ trường hợp nhấn nút trên phương thức giao tiếp.
- Hàm Format

Còn áp dụng thuật toán nào, tạo ra bao nhiêu biến, sử dụng biến thế nào để ra kết quả, là việc của người làm bài.

Câu hỏi sau đây dễ hơn, nhưng cũng cần phải suy luận:

a. Dùng vòng lặp For - Next để thể hiện 56 màu của Bảng màu Excel 2003 lên cột A bắt đầu từ A1. Đồng thời trên cột B ghi chỉ số màu tương ứng
b. Cũng giống câu a, nhưng dùng step 2 để chỉ thể hiện các màu có chỉ số màu chẵn, liên tục từ A1 đến A28, chỉ số màu tương ứng trên cột B
2 câu hỏi làm tại 1 điểm , khi chấm bài phải dò code từng em rồi " chứ đâu thể chấm kết quả nữa

bài dễ thử lên bảng 1 bài xem có bị gõ đầu ko

thay đổi vị trí hiện thị câu B sang cột c và d
[GPECODE=vb]Sub tomau()Dim i As Integer
For i = 1 To 56
Cells(i, 1).Interior.ColorIndex = i
Cells(i, 2) = i
If i / 2 = Int(i / 2) Then
Cells(i / 2, 3).Interior.ColorIndex = i
Cells(i / 2, 4) = i
End If
Next i
End Sub[/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
2 câu hỏi làm tại 1 điểm , khi chấm bài phải dò code từng em rồi " chứ đâu thể chấm kết quả nữa
Thì xóa kết quả làm lại, hoặc làm sheet khác, hoặc làm file mới, hoặc làm cột C và D, ...
Trời ạ!

Chưa nói thậm chí ghi đè lên cũng có thể kiểm tra code đúng sai được.

Chàng Edit bài rồi, cuối cùng cũng đã dời kết quả sang C và D. Tuy nhiên, yêu cầu cầu b là For Next với step 2 (câu b riêng biệt với câu a).
 
Lần chỉnh sửa cuối:
Upvote 0
2 câu hỏi làm tại 1 điểm , khi chấm bài phải dò code từng em rồi " chứ đâu thể chấm kết quả nữa

Thế bạn không nghĩ là câu a "viết" ở sheet1, câu b viết ở sheet2?
Khi đi thi bạn ghi đáp án cho câu 1 từ dòng đầu trang 1, cho câu 2 từ dòng đầu trang 1, ..., cho câu n từ dòng đầu trang 1? Làm thế thì thầy cho 0 điểm với lý do: làm nhưng không biết suy nghĩ. Đâu phải cái gì cũng phải thầy giải thích, cầm tay dẫn đi? Có ông thầy nói: "nếu anh không biết suy nghĩ thì nghỉ học luôn cho khỏi tốn "đèn sách. Mà tôi e rằng quét đường cũng cần suy nghĩ". Chí lý quá. Cứ thử quét đường 1 ngày thì sẽ thấy: quét đường cũng cần suy nghĩ.

Tất nhiên thầy phải kiểm tra code chứ không thể chỉ nhìn kết quả. Nhìn code thấy "em này" có ý tưởng rất hay, cách giải quyết vượt trội các bạn khác thì cho thêm điểm, "em kia" hiểu sai thì trừ điểm.

Ví dụ code bài #156 (code các bài #128, #132, #147 tương tự)

Mã:
Kho = InputBox("Ban chon loai san pham nao?" & Chr(13) & "(a,b,c,d)", "Chon loai", , [COLOR=#ff0000]vbYesNoCancel[/COLOR])
Loop Until (Kho = "a" Or Kho = "b" Or Kho = "c" Or Kho = "d" [COLOR=#ff0000]Or Kho = vbCancel[/COLOR])

Ở bài này thì vbYesNoCancel và OR Kho = vbCancel không ảnh hưởng tới quá trình tính (luôn có Kho = vbCancel = FALSE) nhưng rõ ràng viết như thế là không hiểu đúng về hàm InputBox. Về Kho = vbCancel thì cái không hiểu là: Hàm Input trả về chuỗi có trong trường Textbox chứ không trả về giá trị được gán cho các nút. Về vbYesNoCancel thì cái không hiểu là: thông số thứ tư trong hàm Inputbox có ý nghĩa khác. Vả lại không có thông số nào xác định số và "loại" nút cần có trong Inputbox.

Tóm lại tuy code viết như trên trong trường hợp cụ thể này không ảnh hưởng tới quá trình tính nhưng code cho thấy người viết hiểu chưa đúng về Inputbox. Như thế tuy ra kết quả đúng cũng phải bị trừ điểm. Không nhiều nhưng phải bị trừ.

Gọi là mượn bài để viết chính về vấn đề khác (Inputbox) chứ tôi cũng biết là bạn đùa thôi. Tất nhiên với phần đùa thì tôi cũng đùa. Nhưng đùa là với bạn còn thật là ở chỗ nếu tôi là thầy mà ai viết kiểu "đè lên nhau" là tôi không nhận bài.
 
Upvote 0
Một vài nhận xét về cách đặt tên biến:

Trong các bài giải từ đầu topic đến giờ, tôi nhận xét 1 số điểm và tôi nghĩ nên sửa đổi như sau:

1. Tên biến nên đặt sao cho đọc tên có thể mường tượng biến đang hoặc sẽ gán giá trị gì. Thí dụ:

- Biến mảng có thể đặt Arr, sArr, sArray, ... nhưng nếu 2 biến mảng trở lên thì tốt hơn nên đặt SourceArr, ResultArr để phân biệt. chí ít cũng là sArr và rArr. Nếu đặt tiếng Việt thì có thể đặt MangNguon, MangDich, hoặc MgNguon, MgDich. Nếu đặt tên 2 biến là sArr sArray thì không phân biệt được Array nào dùng làm việc gì (bài #20)
- Nếu không phải biến mảng thì không đặt tên biến là Arr hoặc sArr
- Biến loại Range có thể viết tắt là Rng, nếu không phải biến loại Range thì không nên đặt tên biến là Rng
- Nếu For Each từng ô thì nên đặt biến là Cls, Cll, ..., nếu For Each từng vùng thì mới đặt tên biến là Rng (bài #23)
- Đặt tên biến chạy (trong vòng lặp For Next) có thể đặt i, j, k cho đơn giản, tuy nhiên đừng kẹo quá mà đặt tên biến lấy giá trị từ InputBox, MsgBox là i, j, k (Bài $142). Hãy đặt "tượng hình" chẳng hạn SP = InputBox(), Thongbao hoặc TB = MsgBox(). Tuy nhiên không nên đặt tên biến là l (L viết thường), vì trong cửa sổ VBA nó rất giống số 1 (một).
- Không đặt tên biến cho cái bàn mà tượng hình thành cái tủ, thí dụ đặt tên biến là Kho cho loại sản phẩm (bài #128, #158)
- Hãy đặt tên cụ thể là EndRw, NextRw, RwsCount chứ đừng đặt Rw chung chung, dễ lẫn lộn.

2. Đặt tên biến bao gồm chữ hoa và chữ thường:

Việc này nhằm mục đích kiểm tra chính tả về tên biến: khi chúng ta viết code ào ào, không cần nhấn Shift, thì tên biến (đã khai báo) tự động viết hoa lên. Nếu tên biến không tự động viết hoa nghĩa là ta gõ sai tên biến.

Theo tôi, đặt tên biến iI, jJ GpE, là hơi kỳ cục. Nhưng ta có thể đặt tên biến với chữ hoa đầu tên, hoặc chữ hoa đầu từ cho tên biến gồm 2 từ. Thí dụ: EndRow, NextRow, hoặc EndR, NextR, Rw, Col, SourceArr, ResultArr, RwsCount, SoDong, ...

3. Kiểu biến:

Với biến kiểu số cần tính toán thì chỉ đặt kiểu Long khi biết chắc toàn bộ các dữ liệu cần tính toán, cũng như kết quả là số nguyên. Nhất là khi dùng phép chia. Kể cả tính Sum 1 vùng không xác định thì cũng nên đặt Double.
 
Lần chỉnh sửa cuối:
Upvote 0
Một vài nhận xét về cách đặt tên biến:

Trong các bài giải từ đầu topic đến giờ, tôi nhận xét 1 số điểm và tôi nghĩ nên sửa đổi như sau:

1. Tên biến nên đặt sao cho đọc tên có thể mường tượng biến đang hoặc sẽ gán giá trị gì. Thí dụ:

.........................
2. Đặt tên biến bao gồm chữ hoa và chữ thường:

Việc này nhằm mục đích kiểm tra chính tả về tên biến: khi chúng ta viết code ào ào, không cần nhấn Shift, thì tên biến (đã khai báo) tự động viết hoa lên. Nếu tên biến không tự động viết hoa nghĩa là ta gõ sai tên biến.

Theo tôi, đặt tên biến iI, jJ là hơi kỳ cục. Nhưng ta có thể đặt tên biến với chữ hoa đầu tên, hoặc chữ hoa đầu từ cho tên biến gồm 2 từ. Thí dụ: EndRow, NextRow, hoặc EndR, NextR, Rw, Col, SourceArr, ResultArr, RwsCount, SoDong, ...
Riêng về việc đặt tên biến, em học được 1 kinh nghiệm của các lập trình viên thế này:
- Tên biến lúc nào cũng có 2 phần: Phần tiền tố là viết tắt của kiểu biến, hậu tố thường là phần mô tả mục đích sử dụng (không có cũng không sao)
- Phần tiền tố luôn viết thường, phần hậu tố viết HOA 1 ký tự đầu tiên
- Với hằng số, người ta thường viết HOA toàn bộ
Ví dụ:
Biến Long: sẽ có chữ l đứng đầu:
lR: Biến Long, nói về vị trí của Row
lC: Biến Long, nói về vị trí của Column
Biến String: sẽ có chữ s hoặc str hoặc sz đứng đầu
sPath: Biến String, mô tả đường dẫn
sFile: Biến String, mô tả tên file​
vân... vân...
- Với biến Object, người ta thường đặt tiền tố gồm 3 ký tự mô tả loại object
Ví dụ:
Range: tiền tố được đặt là rng
CheckBox: tiền tố được đặt là chk
ComboBox: tiền tố được đặt là cbo
CommandButton: tiền tố được đặt là cmd
vân... vân....
Riêng với việc đặt tên cho đối số của hàm hoặc sub, người ta thường không áp dụng cách này mà phải đặt sao càng dễ mường tượng ra đối số ấy làm công việc gì càng tốt
Ví dụ:
Mã:
Function JoinText(ByVal [COLOR=#ff0000]Delimiter[/COLOR] As String, ByVal [COLOR=#ff0000]IgnoreBlanks[/COLOR] As Boolean, ParamArray [COLOR=#ff0000]Arrays[/COLOR]()) As String
Nhìn vào 3 đối số màu đỏ sẽ đoán được ngay chúng làm công việc gì
---------------
Dưới đây là bảng mô tả cách đặt tên biến của 1 số object:
Object|Prefix|Example

Checkbox|chk|chkReadOnly

Combo box|cbo|cboEnglish

Command button|cmd|cmdCancel

Common dialog ctrl|dlg|dlgFileOpen

Control|ctl|ctrCurrent

Form|frm|frmFileOpen

Frame|fra|fraLanguage

Image|img|imgIcon

Label|lbl|lblHelpMessage

List box|lst|lstPolicyCodes

Menu|mnu|mnuFileOpen

Object|obj|objUserTable

Option button|opt|optFrench

Shape|shp|shpCircle

Spin control|spn|spnPages

Text box|txt|txtGetText

----------------------------------------
Các lập trình viên phải thống nhất với nhau về cách đặt tên biến như thế để khi làm việc nhóm với nhau họ mới có thể kiểm tra code qua lại 1 cách dễ dàng (mạnh ai nấy đặt tên theo ý mình thì sẽ rất khó cho công việc kiểm tra)
Thử tưởng tượng mai này GPE nỗi tiếng đến mức có nhiều người nước ngoài ghé thăm, họ đọc code và xem cách đặt tên biến của chúng ta chắc cũng nhức đầu
Nên ưu tiên cách đặt tên biến là tiếng Anh để dù là ai, nước nào cũng có thể hiểu được
 
Upvote 0
Riêng về việc đặt tên biến, em học được 1 kinh nghiệm của các lập trình viên thế này:
- Tên biến lúc nào cũng có 2 phần: Phần tiền tố là viết tắt của kiểu biến, hậu tố thường là phần mô tả mục đích sử dụng (không có cũng không sao)
- Phần tiền tố luôn viết thường, phần hậu tố viết HOA 1 ký tự đầu tiên
- Với hằng số, người ta thường viết HOA toàn bộ
Tôi đồng ý với ndu, và việc này (kể cả cái bảng này) đã được đưa lên GPE từ lâu. Riêng tôi thì nếu tên biến chỉ có mô tả không thôi, mà mô tả rõ, cũng đã đủ để biết biến loại nào. Về biến object thì tôi vẫn theo tiêu chuẩn tạo tiền tố để phân biệt các dạng object như textbox, combobox, ..., có điều tôi chưa muốn giới thiệu trong topic này.

Tất nhiên làm đúng chuẩn quốc tế như ndu viết vẫn hơn.

Nên ưu tiên cách đặt tên biến là tiếng Anh

Tôi vẫn thường ưu tiên đặt tên biến tiếng Anh. Tên tiếng Việt không dấu lại còn viết tắt thì có trường hợp đọc không hiểu nổi, thí dụ như biến đặt tên Mang hoặc Vung không nói làm gì, đặt bằng cách viết tắt Mg, Mng, Vg, ... thì chịu thua.
 
Lần chỉnh sửa cuối:
Upvote 0
@xì tin:
Tôi chỉ nói về câu SQL của bạn thôi. Những chỗ code còn lại không kể.
1. Câu hỏi chỉ đòi hỏi 1 sản phẩm. Cho nên câu truy vấn không cần phải GROUP BY, chỉ cần WHERE sanPham = Kho là được rồi. (Đã không có group thì không thể dùng having)
2. Cho biết lý do tại sao bạn lọc bằng từ khoá LIKE Kho?
LIKE dùng để so theo dạng 'wildcard'. Ở đây mã kho chỉ có 1 ký tự cho nên đâu có cần wildcard!

@ptm:
Tại sao khoá học của bạn không khuyến khích viết code có chú thích (comments) nhỉ.
Hồi tôi còn đi học, viết một hàm/thủ tục mà không có dòng giải thích hàm làm cái gì (nhiệm vụ hàm) thì Thầy/Cô sổ toẹt. Có lẽ tôi già quá rồi.
 
Upvote 0
@ptm:
Tại sao khoá học của bạn không khuyến khích viết code có chú thích (comments) nhỉ.
Hồi tôi còn đi học, viết một hàm/thủ tục mà không có dòng giải thích hàm làm cái gì (nhiệm vụ hàm) thì Thầy/Cô sổ toẹt. Có lẽ tôi già quá rồi.
Trong khóa học tôi cũng có hướng dẫn comment. Tuy nhiên với những bài tập ngắn năm ba dòng code với chỉ 1 mục đích nhỏ thì tùy theo người làm, họ thấy không cần chú thích cũng hiểu thì họ không chú thích.

Hơn nữa, đó cũng chỉ là bài test đánh giá thu hoạch là chính, không nhằm mục đích lấy điểm đậu hay rớt, nên không trừ điểm vụ comment mà sẽ chỉ nhắc nhở.
 
Upvote 0
1) Em chỉ định đố những câu đố ngắn (căn bản) nhưng thật sự không định hướng được thế nào là căn bản.
2) Đố dễ quá thì nhàm chán, đố khó quá thì cho là không căn bản, là nâng cao hoặc quá cao.
3) Nhiều cao thủ góp ý quá, kể cả Nghĩa cũng lùm xùm quá, tạo ra sự "ô hợp", mỗi người mỗi kiểu, mỗi kiến thức, mỗi kinh nghiệm.
4) Em đã có ý định đổi tên topic, nhưng hiện giờ em cũng không xác định được tên nó là gì nữa rồi, vã lại, em không quản lý Box này nên không đổi tên được.
Kính nhờ các Thầy, Sư phụ xem mà đổi giúp để cho các thành viên mới học VBA được nhờ ạ.
Anh Nghĩa có thể INDEX các câu đố, bài giải ở bài #1 được không?
Nếu được thì anh cập nhật các bài theo từng chuyên đề vào bài #1 để mọi người theo dõi và học hỏi, cái nào chưa nắm được thì dễ tìm.
1. Các chuyên đề cơ bản có thể là Vòng lặp, Input, Msgbox, các phương thức, ... (nhờ các Thầy khái niệm phần cơ bản dùm, ở đây em chỉ lấy ví dụ). Trong đó là các bài, câu đố liên quan, ...
2. Dù là dễ, nhưng người chưa nắm cơ bản thì lại rất cần. Câu đố khó (vượt mức cơ bản) thì ghi chú tham khảo và đề nghị không tranh luận trong topic.
Việc dời bài của các Thầy, em nghĩ là khó, nhưng nếu anh nói trước thì các Thầy cũng thông cảm thôi.
 
Upvote 0
Quay trở lại trình độ căn bản. Bài tập sau đây cần 1 chút xíu tư duy (2 câu độc lập):

a. Dùng vòng lặp For - Next để thể hiện 56 màu của Bảng màu Excel 2003 lên cột A bắt đầu từ A1. Đồng thời trên cột B ghi chỉ số màu tương ứng
b. Cũng giống câu a, nhưng dùng step 2 để chỉ thể hiện các màu có chỉ số màu chẵn, liên tục từ C1 đến C28, chỉ số màu tương ứng trên cột D

For Next thì ai cũng biết
Step 2 ai cũng biết
Vấn đề là step 2 nhưng ghi lên sheet liên tục không cách dòng.

Làm được bài này, các bạn sẽ ứng dụng rất nhiều trong xử lý dữ liệu, cả trên sheet lẫn trong mảng.
 
Upvote 0
Quay trở lại trình độ căn bản. Bài tập sau đây cần 1 chút xíu tư duy (2 câu độc lập):
a. Dùng vòng lặp For - Next để thể hiện 56 màu của Bảng màu Excel 2003 lên cột A bắt đầu từ A1. Đồng thời trên cột B ghi chỉ số màu tương ứng
b. Cũng giống câu a, nhưng dùng step 2 để chỉ thể hiện các màu có chỉ số màu chẵn, liên tục từ C1 đến C28, chỉ số màu tương ứng trên cột D
For Next thì ai cũng biết
Step 2 ai cũng biết
Vấn đề là step 2 nhưng ghi lên sheet liên tục không cách dòng.
Làm được bài này, các bạn sẽ ứng dụng rất nhiều trong xử lý dữ liệu, cả trên sheet lẫn trong mảng.
Em xin thử trước, (nếu có tag HIDE thì hay quá, nhiều bạn sẽ đưa ra nhiều đáp án hơn.)
Câu a:
Mã:
Private Sub CommandButton1_Click()
Dim I As Long
Columns("A:B").Clear
    For I = 1 To 56
        Cells(I, 1).Interior.ColorIndex = I
        Cells(I, 2) = I
    Next I
End Sub
Câu b:
Mã:
Private Sub CommandButton2_Click()
Dim I As Long, J As Long
Columns("A:B").Clear
    For I = 2 To 56 Step 2
        If I Mod 2 = 0 Then
            J = J + 1
            Cells(J, 1).Interior.ColorIndex = I
            Cells(J, 2) = I
        End If
    Next I
End Sub
 

File đính kèm

Upvote 0
Em xin thử trước, (nếu có tag HIDE thì hay quá, nhiều bạn sẽ đưa ra nhiều đáp án hơn.)
Câu a:
...
Câu b:
Mã:
Private Sub CommandButton2_Click()
Dim I As Long, J As Long
Columns("A:B").Clear
    For I = 2 To 56 Step 2
        If I Mod 2 = 0 Then
            J = J + 1
            Cells(J, 1).Interior.ColorIndex = I
            Cells(J, 2) = I
        End If
    Next I
End Sub

mod 2 : như ptm đã nêu, không cần phải thử

Mẹo toán: nếu bạn để ý sẽ thấy J luôn luôn = I/2. Suy ra biến J không cần.
Ngược lại, nếu đề không bắt buộc dùng step 2 thì ta có thể cho I chạy từ 1 đến 28 và dùng giá trị I*2
 
Upvote 0
mod 2 : như ptm đã nêu, không cần phải thử

Mẹo toán: nếu bạn để ý sẽ thấy J luôn luôn = I/2. Suy ra biến J không cần.
Ngược lại, nếu đề không bắt buộc dùng step 2 thì ta có thể cho I chạy từ 1 đến 28 và dùng giá trị I*2

Đề ra step 2 nhằm mục đích phải dùng biến phụ j tăng có điều kiện. Từ đó có thể áp dụng vào việc khác sau này.

Thí dụ như lọc vùng dữ liệu, dòng nào thỏa điều kiện thì chép sang sheet khác kế tiếp nhau, hoặc nếu dùng mảng, thì gán vào mảng ở dòng j. (Điều kiện thỏa trong bài tập nhỏ này là chẵn hoặc mod 2 = 0).

Một áp dụng mở rộng khác là tính toán cái biến j đó (không chỉ là cộng 1), thí dụ như tính tổng store1, store2, ... với điều kiện mặt hàng a, trong bài Ending-Test.

Vấn đề của học viên lập trình không phải ở học thuộc cú pháp, cấu trúc, ... mà còn ở tư duy tìm phương pháp giải. Những bài tập con con này chỉ nhằm rèn luyện tư duy. Gặp 1 vấn đề cần giải quyết, nhớ lại các bài tập nhỏ đã làm này, lấy ra 1 cái để áp dụng.
 
Lần chỉnh sửa cuối:
Upvote 0
Em sửa lại code câu b như vậy, cũng không khác so với code trước, nhưng tạm thời là chưa nghĩ ra cách khác:
Mã:
Private Sub CommandButton3_Click()
Dim I As Long, J As Long
Columns("E:F").Clear
    For I = 1 To 56 Step 2
        J = (I + 1) / 2
        Cells(J, 5).Interior.ColorIndex = I + 1
        Cells(J, 6) = I + 1
    Next I
End Sub
 

File đính kèm

Upvote 0
Em sửa lại code câu b như vậy, cũng không khác so với code trước, nhưng tạm thời là chưa nghĩ ra cách khác:
Mã:
Private Sub CommandButton3_Click()
Dim I As Long, J As Long
Columns("E:F").Clear
    For I = 1 To 56 Step 2
        J = (I + 1) / 2
        Cells(J, 5).Interior.ColorIndex = I + 1
        Cells(J, 6) = I + 1
    Next I
End Sub

Sửa xong thấy phức tạp hơn code cũ:
1. Tại sao sửa For i = 2 thành For i = 1 rồi sau đó ColorIndex phải + 1?
2. j = j + 1 thì có vấn đề gì mà phải sửa? Và sửa xong nó phức tạp hơn?

Để y nguyên code cũ, bỏ if i Mod 2 = 0 đi là đã xong rồi:

Mã:
    For I = 2 To 56 Step 2
        J = J + 1
        Cells(J, 5).Interior.ColorIndex = I
        Cells(J, 6) = I
    Next I

Bạn thấy đấy, For Next nhuần nhuyễn là thế, chỉ vì tư duy không đúng mà code bị phức tạp lên.
 
Lần chỉnh sửa cuối:
Upvote 0
Mẹo toán: nếu bạn để ý sẽ thấy J luôn luôn = I/2. Suy ra biến J không cần.
Ngược lại, nếu đề không bắt buộc dùng step 2 thì ta có thể cho I chạy từ 1 đến 28 và dùng giá trị I*2

1. Không cần biến j:

Mã:
 For i = 2 to 56 Step 2
    Cells(i / 2, 1).Interior.ColorIndex = i
    Cells(i / 2, 2) = i
Next

2. Không cần cả Step 2:

Mã:
 For i = 1 to 28  
    Cells(i, 1).Interior.ColorIndex = i * 2
    Cells(i, 2) = i * 2
Next

Ghi chú: Đề ra Step 2 là có mục đích. Thí dụ ghi xuống sheet bắt đầu từ dòng 3 (áp dụng để ghi cái gì đó bất kỳ, chứ không phải ghi chỉ số màu theo quy luật tăng dần):

Mã:
    [COLOR=#ff0000]j = 2[/COLOR]
    For i = 2 To 56 Step 2
        j = j + 1
        Cells(j, 5).Interior.ColorIndex = i
        Cells(j, 6) = i
    Next i
 
Lần chỉnh sửa cuối:
Upvote 0
1. Không cần biến j:
2. Không cần cả Step 2:

Mã:
 For i = 1 to 28  
    Cells(i, 1).Interior.ColorIndex = i * 2
    Cells(i, 2) = i * 2
Next

Ghi chú: Đề ra Step 2 là có mục đích. Thí dụ ghi xuống sheet bắt đầu từ dòng 3 (áp dụng để ghi cái gì đó bất kỳ, chứ không phải ghi chỉ số màu theo quy luật tăng dần):

Cám ơn ThầY Mỹ nhiều, lâu lâu xem lại để đầu óc hết mụ. E thấy code này là OK nhất nếu chỉ cần như thế. Các bạn thử xem nếu thực tập gán sang 1 range thì thế nào. Từ đó sẽ có tư duy để chuyển sang Array.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập mở rộng của For Next bài vừa rồi, Dùng biến j tăng 1 theo điều kiện để ghi dữ liệu thỏa điều kiện sang sheet khác.

Cho dữ liệu về các đơn hàng trong sheet Data:

Chọn số Đơn hàng trong validation ô C2 sheet Report.

- Xóa nội dung đơn hàng cũ
- Bằng vòng lặp For next: Chọn các dòng dữ liệu sheet Data có số đơn hàng giống ô C2 sheet Report, ghi vào sheet Report từ dòng số 5, bao gồm cả số thứ tự, Tên mặt hàng, số lượng, đơn giá
- Dùng property FormulaR1C1 gán công thức cột thành tiền = số lượng x đơn giá
- Gán chuỗi Total vào dòng kế tiếp ở cột B
- Dùng property FormulaR1C1 gán công thức tính tổng cột thành tiền tại dòng Total

Ghi chú:
Không dùng mảng cũng được, vì dữ liệu không nhiều.
Cố hạn chế vòng lặp thừa bằng cách xác định dòng cuối sheet Data bằng phương thức End
Có Kết quả mẫu cho đơn hàng số 11-03.
 

File đính kèm

Upvote 0
Không cho Thu Nghi tham gia nhé, làm bộ quên phải học lại để tham gia sao?
 
Upvote 0
Bài này là khá phù hợp với thực tập nhưng phần kẻ khung sợ là hơi khó với các thành viện đang thực tập. Phải xóa khung và kẻ khung lại.
E đâu có tham gia, rảnh nên nên lên tham gia chém gió thôi. Mà chém với ý đồ tốt mà.
 
Upvote 0
Bài tập mở rộng của For Next bài vừa rồi, Dùng biến j tăng 1 theo điều kiện để ghi dữ liệu thỏa điều kiện sang sheet khác.
Cho dữ liệu về các đơn hàng trong sheet Data:
Chọn số Đơn hàng trong validation ô C2 sheet Report.
- Xóa nội dung đơn hàng cũ
- Bằng vòng lặp For next: Chọn các dòng dữ liệu sheet Data có số đơn hàng giống ô C2 sheet Report, ghi vào sheet Report từ dòng số 5, bao gồm cả số thứ tự, Tên mặt hàng, số lượng, đơn giá
- Dùng property FormulaR1C1 gán công thức cột thành tiền = số lượng x đơn giá
- Gán chuỗi Total vào dòng kế tiếp ở cột B
- Dùng property FormulaR1C1 gán công thức tính tổng cột thành tiền tại dòng Total
Ghi chú:
Không dùng mảng cũng được, vì dữ liệu không nhiều.
Cố hạn chế vòng lặp thừa bằng cách xác định dòng cuối sheet Data bằng phương thức End
Có Kết quả mẫu cho đơn hàng số 11-03.
Bài này em gửi đáp án vào email Thầy Mỹ nhé, Thầy check mail dùm.
Sở dĩ em gửi mail vì muốn học hỏi cách làm của các bạn khác.
 
Upvote 0
Phần border em bổ sung phần kẻ nét đứt như sau:
Mã:
            Range("A5:E" & J + 5).Borders.LineStyle = 1
            With Range("A5:E" & J + 4).Borders(xlInsideHorizontal)
                .LineStyle = xlContinuous
                .ColorIndex = xlAutomatic
                .TintAndShade = 0
                .Weight = xlHairline
            End With
 
Upvote 0
Oái! Bỗng nhiên mình bị biến thành người chấm điểm nè trời?
 
Upvote 0
Cho dữ liệu về các đơn hàng trong sheet Data:

Chọn số Đơn hàng trong validation ô C2 sheet Report.

- Xóa nội dung đơn hàng cũ
- Bằng vòng lặp For next: Chọn các dòng dữ liệu sheet Data có số đơn hàng giống ô C2 sheet Report, ghi vào sheet Report từ dòng số 5, bao gồm cả số thứ tự, Tên mặt hàng, số lượng, đơn giá
- Dùng property FormulaR1C1 gán công thức cột thành tiền = số lượng x đơn giá
- Gán chuỗi Total vào dòng kế tiếp ở cột B
- Dùng property FormulaR1C1 gán công thức tính tổng cột thành tiền tại dòng Total
Em cũng thử sức Code chạy trong Sheet2 (Code dùng Font màu trắng, các bạn bôi đen sẽ thấy - một cách Hide tạm thời; nhưng mà là "sáng kiến" nhé :))
Mã:
Sub Button1_Click()
Dim startR As Long, endR As Long, lastR As Long
D[COLOR=#000000]im i As Long, j As Long
[/COLOR][COLOR=#fff0f5]
Rows("5:20").Delete     'Du lieu khong nhieu xoa tu dong 5 den dong 20
startR = 4              'Dong bat dau lay du lieu Sheet1 (cho biến vào bài này hơi thừa nhưng sẽ có ích với những bài khác)
endR = 64               'Dong ket thuc lay du lieu Sheet1 hay la Sheets("Data").Range("B1000").End(xlUp).Row

j = 5   'Dong bat dau ghi du lieu o Sheet2
For i = startR To endR
  With Sheets("Data")   'hoac la With Sheet1
    If .Cells(i, 2) = [C2] Then
      Cells(j, 2).Offset(, -1) = j - 4
      Cells(j, 2) = .Cells(i, 4)
      Cells(j, 2).Offset(, 1) = .Cells(i, 4).Offset(, 1)
      Cells(j, 2).Offset(, 2) = .Cells(i, 4).Offset(, 2)
      Cells(j, 2).Offset(, 3).FormulaR1C1 = "=RC[-2]*RC[-1]"
      j = j + 1
    End If
  End With
Next
    'Them cong thuc
lastR = Range("B50").End(xlUp).Row + 1 'Xac dinh dong duoi dong du lieu cuoi cung tim duoc tai Sheet2
Range("B" & lastR) = "Total"
Range("E" & lastR).FormulaR1C1 = "=SUM(R[-" & j - 5 & "]C:R[-1]C)"
Range("D5:E" & lastR).NumberFormat = "#,##0"
    'Ke khung vien
Range("A5:E" & lastR).Borders.LineStyle = 1
Range("A5:E" & lastR - 1).Borders(xlInsideHorizontal).Weight = xlHairline[/COLOR][COLOR=#000000]
[/COLOR]
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em cũng thử sức Code chạy trong Sheet2 (Code dùng Font màu trắng, các bạn bôi đen sẽ thấy - một cách Hide tạm thời; nhưng mà là "sáng kiến" nhé :))
Mình góp ý, nếu theo bạn hay hơn thì hướng dẫn lại dùm nha:
- Không dùng Delete dòng, mà dùng Clear từ A5:E65535. Vì dùng Delete dòng ảnh hưởng đến giá trị ngoài bảng nếu có.
- Dư lastR, vì J đã là lastrow.
- Cells(j, 2).Offset(, 1) Hình như là dư Offset, có thể dùng Cells(j, 3).
- Border nét đứt, mình Record Marco nó ra 4 dòng, mà quên lựa chọn, mình học được bạn cái này.
 
Upvote 0
sinh sau đẻ muộn cũng xin làm bài này gởi thầy để học hỏi thêm các kỹ năng về property trong VBA
 

File đính kèm

Upvote 0
Mọi người gửi lên thì em cũng gửi luôn, nhờ các Thầy chỉ bảo, có sửa lại một chút so với bài gửi trong mail Thầy Mỹ.
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
    Dim Rng As Range
    Dim I As Long, J As Long
    Set Rng = Sheet1.Range("B4:B" & Sheet1.Range("B65535").End(xlUp).Row)
        If Target.Address <> "$C$2" Then
        Exit Sub
        Else
            Range("A5:E65535").Clear
            For I = 1 To Rng.Rows.Count
                If Rng(I) = Target Then
                    J = J + 1
                    Cells(J + 4, 1) = J
                    Cells(J + 4, 2) = Rng(I).Offset(, 2)
                    Cells(J + 4, 3) = Rng(I).Offset(, 3)
                    Cells(J + 4, 4) = Format(Rng(I).Offset(, 4), "#,##0")
                    Cells(J + 4, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
                End If
            Next I
            Cells(J + 5, 2) = "Total"
            Cells(J + 5, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"
            Range("E5:E" & J + 5).NumberFormat = "#,##0"
            Range("A5:E" & J + 5).Borders.LineStyle = 1
            Range("A5:E" & J + 4).Borders(xlInsideHorizontal).Weight = xlHairline
        End If
Application.ScreenUpdating = True
End Sub
 

File đính kèm

Upvote 0
Mình góp ý, nếu theo bạn hay hơn thì hướng dẫn lại dùm nha:
- Không dùng Delete dòng, mà dùng Clear từ A5:E65535. Vì dùng Delete dòng ảnh hưởng đến giá trị ngoài bảng nếu có.
- Dư lastR, vì J đã là lastrow.
- Cells(j, 2).Offset(, 1) Hình như là dư Offset, có thể dùng Cells(j, 3).
- Border nét đứt, mình Record Marco nó ra 4 dòng, mà quên lựa chọn, mình học được bạn cái này.
- Bài này dữ liệu ít nên mình xóa dòng làm biếng thế mà (trong code đã nói rùi), xóa/ phá dữ liệu thì thiếu gì cách
- Công nhận dư lastR. Cứ viết là viết thui quên không check, Cho nên mình nghĩ khi viết code các bạn mới như mình cũng nên cho thêm phần kiểm tra biến vào Msgbox j hoặc Debug.Print j để quản lý biến tốt nhất có thể
- Dùng Offset() để tham chiếu đến 1 ô nguồn nhiều khi có lợi hơn (quan điểm cá nhân)
- Mình cũng Record Macro và thử mọi trường hợp để đạt kết quả và dễ nhìn, dễ sửa chữa sau này
 
Upvote 0
Mọi người gửi lên thì em cũng gửi luôn, nhờ các Thầy chỉ bảo, có sửa lại một chút so với bài gửi trong mail Thầy Mỹ.

Em cũng tham gia chút, Thầy Mỹ tiện thể chấm điểm luôn dùm em.

PHP:
Sub TrichLoc()
Dim i&, dong&, eR&
Dim DonHang As String
Dim myRng As Range
With Sheets("Data")
  eR = .Cells(65000, 2).End(xlUp).Row
  Set myRng = .Range("A4:F" & eR)
End With
dong = 4
With Sheets("Report")
  .Range("A5:E100").Borders.LineStyle = 0
  DonHang = CStr(.Cells(2, 3))
  For i = 1 To myRng.Rows.Count
    If CStr(myRng(i, 2)) = DonHang Then
      dong = dong + 1
      .Cells(dong, 1) = dong - 4
      .Cells(dong, 2) = myRng(i, 4)
      .Cells(dong, 3) = myRng(i, 5)
      .Cells(dong, 4) = myRng(i, 6)
      .Cells(dong, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
    End If
  Next i
  .Cells(dong + 1, 2) = "Total"
  .Cells(dong + 1, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"
  With .Range("A5:E" & dong + 1)
    With .Borders(xlEdgeTop)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeBottom)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeRight)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideVertical)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideHorizontal)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
    End With
End With
Set myRng = Nothing
End Sub
 
Upvote 0
Các cụm (block) range trong bài này đều là cụm đặc, không có chỗ đứt đoạn. Nếu không dùng For Each thì không cần phải dùng OFFSET. Chỉ cần đặt Ranges vào ô đầu tiên của nơi đi và ô đầu tiên của ô đến là cái Cells(n,m) property nó cho truy cập hết.

Ranges:
Set rgFr = Sheets("Dữ liệu").Range("Ô đầu tiên của nhóm dữ liệu")
Set rgTo = Sheets("Đơn hàng").Range("Ô đầu tiên cần ghi chi tiết đơn hàng")

Vòng lặp:
J bắt đầu là 0
FOR i = 1 to dongCuoi - dongDau + 1
nếu so rgFr(i,1) = Đúng điều kiện
j = j + 1
rgTo.Cells(j, 1) = j
rgTo.Cells(j, 2) = rgFr.Cells(i, ...)
...
NEXT i
rgTo.Cells(j+1, 5) = công thức tổng

làm xong thì set mấy cái ranges về nothing
 
Upvote 0
Em cũng tham gia chút, Thầy Mỹ tiện thể chấm điểm luôn dùm em.

Mã:
Sub TrichLoc()
Dim i&, dong&, eR&
Dim DonHang As String
Dim myRng As Range
With Sheets("Data")
  eR = .Cells(65000, 2).End(xlUp).Row
  Set myRng = .Range("A4:F" & eR)
End With
dong = 4
With Sheets("Report")
  .Range("A5:E100").Borders.LineStyle = 0
  DonHang = CStr(.Cells(2, 3))
  For i = 1 To myRng.Rows.Count
    If CStr(myRng(i, 2)) = DonHang Then
      dong = dong + 1
      .Cells(dong, 1) = dong - 4
      .Cells(dong, 2) = myRng(i, 4)
      .Cells(dong, 3) = myRng(i, 5)
      .Cells(dong, 4) = myRng(i, 6)
      .Cells(dong, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
    End If
  Next i
  .Cells(dong + 1, 2) = "Total"
  .Cells(dong + 1, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"
  [COLOR=#ff0000]With .Range("A5:E" & dong + 1)
    With .Borders(xlEdgeTop)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeBottom)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeRight)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideVertical)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideHorizontal)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
    End With[/COLOR]
End With
Set myRng = Nothing
End Sub
Đoạn mảu đỏ ấy thừa cả thúng luôn
 
Upvote 0
Thà dziết làm còn hơn bỏ sót, hehe... em nói vui thôi, phiền mấy anh chị chỉ dẫn.
Chẳng phải bài của phanminhphuong & leonguyenz đã có đoạn code kẻ khung rồi sao
Range("A5:E" & lastR).Borders.LineStyle = 1 => Kẻ đường viền toàn bộ vùng dữ liệu từ ô A5:E(dòng cuối cùng)
Range("A5:E" & lastR - 1).Borders(xlInsideHorizontal).Weight = xlHairline => Kẻ nét đứt ở giữa (chừa dòng cuối cùng ra)

Về code đánh số thứ tự thực sự thấy đưa vào vòng lặp như bài này cũng được vì dữ liệu ít nhưng mà mình thấy chiêu này của bác PTM0412 còn hay hơn
Range("A5:A" & lastR - 1) = Evaluate("=Row(R:R)")
 
Lần chỉnh sửa cuối:
Upvote 0
Mọi người gửi lên thì em cũng gửi luôn, nhờ các Thầy chỉ bảo, có sửa lại một chút so với bài gửi trong mail Thầy Mỹ.
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
    Dim Rng As Range
    Dim I As Long, J As Long
    Set Rng = Sheet1.Range("B4:B" & Sheet1.Range("B65535").End(xlUp).Row)
        If Target.Address <> "$C$2" Then
        Exit Sub
        Else
            Range("A5:E65535").Clear
            For I = 1 To Rng.Rows.Count
                If Rng(I) = Target Then
                    J = J + 1
                    Cells(J + 4, 1) = J
                    Cells(J + 4, 2) = Rng(I).Offset(, 2)
                    Cells(J + 4, 3) = Rng(I).Offset(, 3)
                    [COLOR=#ff0000]Cells(J + 4, 4) = Format(Rng(I).Offset(, 4), "#,##0")[/COLOR]
                    Cells(J + 4, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
                End If
            Next I
            Cells(J + 5, 2) = "Total"
            Cells(J + 5, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"
            [COLOR=#ff0000]Range("E5:E" & J + 5).NumberFormat = "#,##0"[/COLOR]
            Range("A5:E" & J + 5).Borders.LineStyle = 1
            Range("A5:E" & J + 4).Borders(xlInsideHorizontal).Weight = xlHairline
        End If
Application.ScreenUpdating = True
End Sub

Chào bạn leonguyenz,

Trong đoạn code của bạn mình tô đỏ ý, theo mình thì:

Dòng này :
Cells(J + 4, 4) = Format(Rng(I).Offset(, 4), "#,##0")
đổi thành:
Cells(J + 4, 4) = Rng(I).Offset(, 4)

và dòng này:
Range("E5:E" & J + 5).NumberFormat = "#,##0"
đổi thành:
Range("D5:E" & J + 5).NumberFormat = "#,##0"

sẽ nhanh hơn chứ nhỉ vì:

Thay vì format từng Cell một thì mình fomat cả vùng luôn 1 thể cho 2 cột.
 
Upvote 0
Theo tôi thây, đây là topic căn bản VBA mà, các bạn biết rồi nên tranh luận về kẻ khung, thậm chí còn nét này nét nọ..., và format.
Cứ học VBA từ đầu làm sao ra đúng đáp số đã, cùng lắm trang trí lại sau.
Phần trang trí nếu nói sâu cũng phức tạp lắm. Tôi thì kg rành pần này nên thường format nhiều dòng và hide lại cho khỏe. Đỡ mất công tư duy mà đáp số lại sai.
Hy vọng các bạn kg phiền, vì lúc tôi học VBA nếu ra đáp số là nhảy tưng rồi.
Cám ơn các bạn.
 
Upvote 0
Chưa thấy ai dùng Resize nhỉ?
 
Upvote 0
...
Về code đánh số thứ tự thực sự thấy đưa vào vòng lặp như bài này cũng được vì dữ liệu ít nhưng mà mình thấy chiêu này của bác PTM0412 còn hay hơn
Range("A5:A" & lastR - 1) = Evaluate("=Row(R:R)")

Hay thì hay rồi, nhưng không theo sát yêu cầu đề bài

Bài tập mở rộng của For Next bài vừa rồi, Dùng biến j tăng 1 theo điều kiện để ghi dữ liệu thỏa điều kiện sang sheet khác.
...

Theo điều kiện, J là chỉ số thứ tự của dòng chi tiết chứ không phải là thứ tự của dòng ghi - tuy kết quả giống nhau nhưng không cùng ý nghĩa.

Nếu công việc triển khai ra khiến một dòng chi tiết có thể ghi ra nhiều hàng thì người ta chỉ việc đặt thêm 1 biến K để phân biệt dòng ghi và dòng chi tiết.

Mã:
1    Chi tiết 1
2    Chi tiết 2
     Chi tiết phụ của 2
3    Chi tiết 3
4 ...
 
Upvote 0
Em cũng tham gia chút, Thầy Mỹ tiện thể chấm điểm luôn dùm em.

PHP:
Sub TrichLoc()

  With .Range("A5:E" & dong + 1)
    With .Borders(xlEdgeTop)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeBottom)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlEdgeRight)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideVertical)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
      With .Borders(xlInsideHorizontal)
          .LineStyle = xlContinuous
          .ColorIndex = 0
          .TintAndShade = 0
          .Weight = xlThin
      End With
    End With
End With
Set myRng = Nothing
End Sub

Đoạn code border sao anh không viết như vậy cho gọn:
Mã:
For Each Item In Array(7, 8, 9, 10, 11, 12)
      set rng = Range("A5:E" & dong + 1) 
       rng.Borders(Item).LineStyle = 1
Next
 
Upvote 0
Làm theo gợi ý của bác VetMini (dữ liệu là khối liền mạch). Code chạy tại Sheet2
[GPECODE=vb]Sub Bai1()

Dim i As Long, j As Long
Dim SourceRange As Range, DesRange As Range

Set SourceRange = Sheet1.Range("B4:F" & Sheet1.Range("F1000").End(xlUp).Row)
Set DesRange = Sheet2.Range("A5")

Range("A5:E65000").Clear

For i = 1 To SourceRange.Rows.Count
With DesRange
If SourceRange.Cells(i, 1) = [C2] Then
j = j + 1
.Cells(j, 1) = j
.Cells(j, 2) = SourceRange.Cells(i, 3)
.Cells(j, 3) = SourceRange.Cells(i, 4)
.Cells(j, 4) = SourceRange.Cells(i, 5)
.Cells(j, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
End If
End With
Next i
Cells(j + 5, 2) = "Total"
Cells(j + 5, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"

Range("D5:E" & j + 5).NumberFormat = "#,##0"
Range("A5:E" & j + 5).Borders.LineStyle = 1
Range("A5:E" & j + 4).Borders(xlInsideHorizontal).Weight = xlHairline

Set SourceRange = Nothing
Set DesRange = Nothing

End Sub[/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
Re: Ressize
Phạm vi của thớt này là gì?
"So sánh tất cả các kỹ thuật viết code từ cơ bản đến nâng cao" hay "Giới hạn trong các kỹ thuật đơn giản để giải quyết vấn đề"
 
Upvote 0
Đoạn code border sao anh không viết như vậy cho gọn:
Mã:
For Each Item In Array(7, 8, 9, 10, 11, 12)
      set rng = Range("A5:E" & dong + 1) 
       rng.Borders(Item).LineStyle = 1
Next

Vậy vẫn dài. Dùng cái này: Range("Gì gì đó").Borders.LineStyle = 1
--------------------
Re: Ressize
Phạm vi của thớt này là gì?
"So sánh tất cả các kỹ thuật viết code từ cơ bản đến nâng cao" hay "Giới hạn trong các kỹ thuật đơn giản để giải quyết vấn đề"

Resize và Offset cũng rất đơn giản mà
 
Upvote 0
Re: Ressize
Phạm vi của thớt này là gì?
"So sánh tất cả các kỹ thuật viết code từ cơ bản đến nâng cao" hay "Giới hạn trong các kỹ thuật đơn giản để giải quyết vấn đề"

Dùng Resize đúng chỗ ấy chứ Vetmini.

Thay
Mã:
      .Cells(j, 2) = SourceRange.Cells(i, 3)

      .Cells(j, 3) = SourceRange.Cells(i, 4)
      .Cells(j, 4) = SourceRange.Cells(i, 5)


bằng
Mã:
      .Cells(j, 2).Resize(1,3) = SourceRange.Cells(i, 3).Resize(1, 3)

3 dòng lệnh gom thành 1 không phải là quá hay, nhưng nếu 5, 7 dòng thì gom thành 1 thì cũng khá hữu ích.

Còn những chỗ khác thì tôi ưu tiên làm theo cách:

Range(Cells(i, j), Cells(m, n))
hoặc
Range("A3:A" & EndRow)

Tùy theo tình huống cái gì có sẵn.
 
Upvote 0
Vậy em làm bài theo hướng này có được ko vậy các anh chị ? (Do bài này dữ liệu liền mạch, ko liền mạch thì Sort cái là ra rồi Resize cả cụm khỏi phải lặp, nhưng lại phải thêm 1 biến k không thì chưa tìm ra cách nào xác định dòng đầu tiên của SourceRange có giá trị = [C2])
[GPECODE=vb]Sub Bai1_Resize()

Dim i As Long, j As Long, k As Long
Dim SourceRange As Range, DesRange As Range

Set SourceRange = Sheet1.Range("B4:F" & Sheet1.Range("F1000").End(xlUp).Row)
Set DesRange = Sheet2.Range("A5")

Range("A5:E65535").Clear

For i = 1 To SourceRange.Rows.Count
If SourceRange.Cells(i, 1) = [C2] Then
k = i
j = j + 1
DesRange.Cells(j, 1) = j
DesRange.Cells(j, 5).FormulaR1C1 = "=RC[-2]*RC[-1]"
End If
Next i
DesRange.Cells(1, 2).Resize(j, 3).Value = SourceRange.Cells(k, 1).Offset(-j + 1, 2).Resize(j, 3).Value

Cells(j + 5, 2) = "Total"
Cells(j + 5, 5).FormulaR1C1 = "=SUM(R5C:R[-1]C)"

Range("D5:E" & j + 5).NumberFormat = "#,##0"
Range("A5:E" & j + 5).Borders.LineStyle = 1
Range("A5:E" & j + 4).Borders(xlInsideHorizontal).Weight = xlHairline

Set SourceRange = Nothing
Set DesRange = Nothing

End Sub

[/GPECODE]
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Tôi chỉ nói là phải đến một trình độ nào đó người ta mới có thể nhìn được hình dạng và vị trí của một range. Khi ấy dùng Offset và Resize mới có ý nghĩa.

Trong bài này, thực ra có 3 chỗ để sử dụng Resize:
1. Vì trong quá trình sao chép có giai đoạn cần copy 3 ô liên tiếp từ bên src qua 3 ô liên tiếp bên des cho nên có thể dùng Offset (hoặc Cells) để đến ô đầu tiên của nhóm và áp dụng Resize để phép sao chép hàng loạt.
2. Sau vòng lặp, trị của J chính là số dòng của nhóm dữ liệu vừa chép xong. Vì vậy ta có thể dùng Resize để chép công thức "=RC[-2]*RC[-1]" vào cột thứ 5 của nhóm dữ liệu, thay vì chép từng dòng trong vòng lặp.
3. Tương tự, Resize cũng có thể được dùng để chọn nhóm và kẻ khung.

Để làm được như vậy. Các bạn nói là căn bản sao?
 
Upvote 0
Để làm được như vậy. Các bạn nói là căn bản sao?
Ở mức độ căn bản, người mới học chỉ cần biết resize là thay đổi kích thước 1 range thành 1 range mới, có cùng ô góc trên bên trái. Range mới này có đầy đủ tính chất của 1 range nên có thể sử dụng mọi property và method của range. Tuy property và method thì bao la, nhưng họ biết method nào xài method đó, vậy thôi.
Trong câu tôi thí dụ thì chỉ là resize 1 ô thành 1 dòng 3 cột (3 ô), có gì khó hiểu đâu? Những chỗ khác khó hơn, tôi không làm mẫu và cũng không bắt làm.

ì vậy ta có thể dùng Resize để chép công thức "=RC[-2]*RC[-1]" vào cột thứ 5 của nhóm dữ liệu, thay vì chép từng dòng trong vòng lặp.

Chỗ này tôi cũng sẽ không dùng resize, mà dùng Range("E5:E" & j)

Kẻ khung tôi cũng dùng Range("A5:E" & j) hoặc Range("A5:E" & j + 1)
 
Lần chỉnh sửa cuối:
Upvote 0
Một số nhận xét và gợi ý qua bài tập liệt kê chi tiết của 1 đơn hàng:

1. Code của phanminhphuong:

a. Cells(j, 2).Offset(, 1) = .Cells(i, 4).Offset(, 1)

Tại sao không là Cells(j, 3) = .Cells(i, 5)? Offset trong trường hợp này làm tăng sự phức tạp của code và khiến cho VBA phải tính toán thêm 1 động tác thừa.

b. j có giá trị ban đầu là 5 là dòng bắt đầu, sau khi tăng dần, j chính là dòng cuối. Vậy sao phải mất công tính lastR = Range("B50").End(xlUp).Row làm gì, xài luôn j cho khỏe?

c. Code kẻ khung của bạn rất gọn: 1 dòng kẻ khung toàn bộ cho cả dòng total, 1 dòng kẻ đường ngang giữa = hairline cho vùng không kể dòng tổng.

2. Code của leonguyen:

Bạn cũng dùng offset, ngoài ra bạn dùng hàm format, kết quả sinh ra chuỗi chứ không phải số, mặc dù khi gán xuống Excel vẫn hiểu.
Hơn nữa, nếu định dạng, thì định dạng cả vùng sau khi lặp, chứ không nên định dạng từng ô trong vòng lặp.

3. Code của phihn:


a. Yêu cầu gán công thức cho cột E chứ không phải gán giá trị. Mặc dù gán giá trị thì nhanh hơn, làm cho file nhẹ hơn, nhưng yêu cầu là ôn lại FormulaR1C1

b. Công thức Sum của bạn rối rắm quá:
Mã:
      Sheet2.Select
      Range("E" & j).Select
      ActiveCell.FormulaR1C1 = "=SUM(R5C5:R" & j - 1 & "C5)"

- Bạn đang đứng ở Sheet2 nhấn nút cho chạy code, thì cần gì Sheet2.Select?
- Gán công thức trực tiếp cũng được, cần gì Range("E" & j).Select?
- Chỉ cần "=SUM(R5C:R[-1]C)

c. Code kẻ khung của bạn record macro làm sao để nguyên như vậy, nên dài thậm thượt.

d. Bạn không định dạng số có phân cách hàng ngàn.

4. Code của TungNguyen:

Chỉ mỗi tội code kẻ khung "dư cả thúng"

5. Code của
hoi_joker84:
Làm theo gợi ý của VetMini, dùng DesRange.Cells(m, n). Cách này là tham chiếu tương đối, nên hơi trừu tượng hơn là địa chỉ dòng cột của Excel.

5. Gơi ý chung:

a. Dùng Resize để gán giá trị 1 lần 3 ô 1 dòng cho mỗi vòng lặp:Cells(j, 2).Resize(1,3) = SourceRange.Cells(i, 3).Resize(1, 3)

b. Dùng trực tiếp Range trên sheet Data, khỏi Set SourceRange, vì cũng chẳng nhanh hơn bao nhiêu. Lại còn phải set Nothing



c. Định dạng số nên đưa ra ngoài vòng lặp, và định dạng số 1 lần cho cả khối

d. Công thức cột thành tiền cũng có thể gán 1 lần cho cả cột, nên hãy đưa ra ngoài vòng lặp:
Range("E5:E" & j).FormulaR1C1 = "=RC[-2]*RC[-1]"

e. Code kẻ khung nên làm theo code của phanminhphuong. Tuy nhiên dự phòng trường hợp đơn hàng chỉ có 1 mặt hàng, nên chỉ có 1 dòng, không có đường kẻ ngang bên trong và sinh ra lỗi.

f. Xóa dữ liệu cũ:

- Nên Clear, không nên Delete dòng
- Clear 1 số dòng vừa phải, không Clear cả 65 ngàn dòng. Ta nên suy nghĩ 1 chút, trước hết nó không thể nhiều hơn EndRow sheet Data được. Kế đến ta có thể ước tính số dòng tối đa cho 1 đơn hàng, vậy Clear 50 dòng hay tối đa 100 dòng là được.
 
Lần chỉnh sửa cuối:
Upvote 0
Không sao cả. Chấp nhận Resize không khó hiểu. Và cũng chấp nhận Offset không khó hiểu luôn.

Phép toán thường dùng cho sao chép dữ liệu khối (nhiều ô liên tiếp cùng hàng) sang khối khác nó hơi đặc biệt một chút.
Ngưởi ta đặt cái source range là 3 ô đầu, destination range cũng vậy (thường là các ô headings). Và như vậy thì code chép là: datDes.Offset(J).Value = datSrc.Offset(I).Value
Phép này rất thông dụng cho loại bài toán chép dữ liệu có số cột liên tiếp giống nhau nhưng có số dòng so le nhau. Điển hình là đề bài này.

Đăt range nhiều quá tuy hơi rườm rà nhưng bù lại người ta có thể đặt tất cả các thông số về nơi đi nơi đến, số ô cần chép, vv... trước khi tiến vào vòng lặp. Đây là kỹ thuật viết code tách rời phần sửa soạn (đặt thông số) với phần làm việc (vòng lặp duyệt dữ liệu và chép dữ liệu). Code bên trong vòng lặp không cần biết dãy data đang chép có bao nhiêu ô.
 
Lần chỉnh sửa cuối:
Upvote 0
Không biết anh Nghĩa và các Thầy còn quan tâm đến topic này không nhỉ?
Có thể ít người biết đến, nhưng nếu để topic chìm, rồi cũng chắc chẳng ai biết luôn. Rất mong anh Nghĩa và các Thầy cho tiếp câu đố, bài tập, bổ sung kiến thức căn bản VBA với ạ.
 
Upvote 0
Không biết anh Nghĩa và các Thầy còn quan tâm đến topic này không nhỉ?
Có thể ít người biết đến, nhưng nếu để topic chìm, rồi cũng chắc chẳng ai biết luôn. Rất mong anh Nghĩa và các Thầy cho tiếp câu đố, bài tập, bổ sung kiến thức căn bản VBA với ạ.

Nhớ lại ngày xưa tôi học hơi khác: Tôi chẳng bao giờ đợi các thầy ra đề mà luôn tự mình nghĩ đề tài và tự giải
Nếu Thảo quan tâm cũng nên học theo cách này ---> Lấy công việc hằng ngày làm để tài chẳng han
Excel nó vô vàn và đề tài cũng không bao giờ thiếu
 
Upvote 0
Không biết anh Nghĩa và các Thầy còn quan tâm đến topic này không nhỉ?
Có thể ít người biết đến, nhưng nếu để topic chìm, rồi cũng chắc chẳng ai biết luôn. Rất mong anh Nghĩa và các Thầy cho tiếp câu đố, bài tập, bổ sung kiến thức căn bản VBA với ạ.
Thảo đã cày hết cái file bài tập anh gởi cho Thảo chưa mà ham hố quá vậy? Hỏng lẻ học nhanh vậy sao ta?
Học hành gì mà mới 10g đã out rồi.
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Câu hỏi 7: Làm sao để biết bao nhiêu sự kiện trong sheet?

Khi thao tác trên sheet, ta thường có những sự kiện đại loại như thế này:


[GPECODE=vb]Private Sub Worksheet_Change(ByVal Target As Range)


End Sub


Private Sub Worksheet_SelectionChange(ByVal Target As Range)


End Sub

v.v...


[/GPECODE]


Câu hỏi đặt ra là: Có bao nhiêu sự kiện có sẳn của một Worksheet? Và nếu là bạn, bạn sẽ làm gì để có được chúng?
 
Upvote 0
khi thao tác trên sheet, ta thường có những sự kiện đại loại như thế này:


[gpecode=vb]private sub worksheet_change(byval target as range)



end sub


private sub worksheet_selectionchange(byval target as range)


end sub

v.v...


[/gpecode]


câu hỏi đặt ra là: Có bao nhiêu sự kiện có sẳn của một worksheet? Và nếu là bạn, bạn sẽ làm gì để có được chúng?
hỏng biết diễn đạt như thế nào . Nhưng sự kiện của sheet không biết có cái nào khác nữa không
 

File đính kèm

  • WS.jpg
    WS.jpg
    50.3 KB · Đọc: 59
Upvote 0
hỏng biết diễn đạt như thế nào . Nhưng sự kiện của sheet không biết có cái nào khác nữa không
Cách này anh Nghĩa có chỉ cho em rồi, em tưởng là liệt kê những sự kiện đã viết.
Đề nghị anh Thương tham gia ra câu đố, không tham gia trả bài câu đố ở topic này.
 
Upvote 0
hỏng biết diễn đạt như thế nào . Nhưng sự kiện của sheet không biết có cái nào khác nữa không
Đúng vậy đó bạn hiền, để có sự kiện của sheet ta phải làm như sau:

Đầu tiên ta chọn một Object cần có tại ComboBox Object, tại đây bạn chọn Worksheet:

attachment.php



Sau khi chọn vào nó, mặc định chúng sẽ hiện lên những dòng code đầu tiên cho sự kiện của Worksheet như sau:

Mã:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)


End Sub

Lúc này, để có nhiều sự kiện khác, ta đặt con trỏ vào bất kỳ chỗ nào trong thủ tục này để bấm vào ComboBox thứ hai đó là ComboBox Procedure, tại đây có rất nhiều sự kiện có sẳn của Worksheet, ta chỉ cần chọn những sự kiện cần thiết của nó.

attachment.php


Như thế, ta không phải mất công gõ từng chữ (mà gõ thì chắc gì nhớ cú pháp phải không?). Việc này cũng có thể áp dụng cho UserForm hoặc các Object khác.
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    31.3 KB · Đọc: 58
  • Picture2.jpg
    Picture2.jpg
    43.9 KB · Đọc: 57
Upvote 0
Cách này anh Nghĩa có chỉ cho em rồi, em tưởng là liệt kê những sự kiện đã viết.
Đề nghị anh Thương tham gia ra câu đố, không tham gia trả bài câu đố ở topic này.

Nó vừa liệt kê những thủ tục mình viết, đồng thời nó cũng tạo ra sự kiện nếu đối tượng đó có sự kiện. Ta cũng có thể di chuyển nhanh chóng đến thủ tục đã viết sẳn trong đó nhanh chóng bằng cách chọn vào chúng tại Procedure.

Đồng chí bạn hiền Lê Duy Thương của mình cũng bằng bằng cỡ Thảo mà thôi, tại hên là trả lời trúng đó chứ! kakakkaka
 
Upvote 0
Câu hỏi liên quan, nếu các sự kiện dưới đây:

PHP:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub

Ta đều thấy cái này: ByVal Target As Range

Vậy Target là cái gì thế?
 
Lần chỉnh sửa cuối:
Upvote 0
Target hình như là 1 cái biến kiểu range dùng để lưu 1 vùng địa chỉ nào đó được truyền vào hàm
Worksheet_BeforeRightClick ...., trong các ví dụ trên thì nó chỉ truyền vào hàm là tham trị thôi
không biết hiểu như vậy có đúng? hic hic

 
Upvote 0
Target hình như là 1 cái biến kiểu range dùng để lưu 1 vùng địa chỉ nào đó được truyền vào hàm
Worksheet_BeforeRightClick ...., trong các ví dụ trên thì nó chỉ truyền vào hàm là tham trị thôi
không biết hiểu như vậy có đúng? hic hic


Đúng thế, Target chẳng là cái gì hết, nhưng khi được khai báo thì nó chính là một biến kiểu Range, vì thế nếu đối tượng Range có tất cả những thuộc tính gì, phương thức nào thì Target sẽ có đầy đủ những thuộc tính và phương thức đó.

Tôi nghĩ, tới bài này, các Sư phụ, các Thầy đã có những bài tập căn bản về sự kiện của Worksheet rồi nhỉ? Các Thầy ra bài tập đi ạ!
 
Upvote 0
Giải thích Target như vậy là chưa đầy đủ đối với các sự kiện.
Lát tối rảnh tôi sẽ viết thêm
 
Upvote 0
Giải thích Target như vậy là chưa đầy đủ đối với các sự kiện.
Lát tối rảnh tôi sẽ viết thêm

Em nghĩ nói Target là gì, thì câu trả lời đó là tên của một biến có kiểu là Range đã là rất hợp lý và đầy đủ lắm rồi.

Nếu Sư phụ đổi tên biến Target thành một tên biến bất kỳ nào khác thì nó vẫn hoạt động, chẳng hạn:

Mã:
Option Explicit


Private Sub Worksheet_SelectionChange(ByVal [COLOR=#0000cd]NghiaDepTrai [/COLOR]As Range)
    MsgBox [COLOR=#0000cd]NghiaDepTrai[/COLOR].Address
End Sub


Nếu Sư phụ có giải thích thì nên giải thích cho mọi người hiểu các sự kiện được thực hiện như thế nào, cách vận hành ra sao, khi nào mới xảy ra sự kiện thì em nghĩ sẽ hợp lý hơn.
 
Upvote 0
Nếu Sư phụ có giải thích thì nên giải thích cho mọi người hiểu các sự kiện được thực hiện như thế nào, cách vận hành ra sao, khi nào mới xảy ra sự kiện thì em nghĩ sẽ hợp lý hơn.

Bình tĩnh một chút. Tôi nói là không đầy đủ đối với sự kiện chứ không nói là sai.
 
Upvote 0
Nó vừa liệt kê những thủ tục mình viết, đồng thời nó cũng tạo ra sự kiện nếu đối tượng đó có sự kiện. Ta cũng có thể di chuyển nhanh chóng đến thủ tục đã viết sẳn trong đó nhanh chóng bằng cách chọn vào chúng tại Procedure.

Đồng chí bạn hiền Lê Duy Thương của mình cũng bằng bằng cỡ Thảo mà thôi, tại hên là trả lời trúng đó chứ! kakakkaka
hoàn toàn đúng. tôi chỉ học vba nếu có thể đáp ứng cho công việc của tôi . thì tôi mới biết code. còn không code nó biết tôi chứ tôi hỏng biết nó.
nhân tiện nhờ các bạn viết cho đoạn code ngắn để dược kết quả như trong hình 2 trong file đính kèm.
 

File đính kèm

Upvote 0
hoàn toàn đúng. tôi chỉ học vba nếu có thể đáp ứng cho công việc của tôi . thì tôi mới biết code. còn không code nó biết tôi chứ tôi hỏng biết nó.
nhân tiện nhờ các bạn viết cho đoạn code ngắn để dược kết quả như trong hình 2 trong file đính kèm.
Sao giống Thương đang giỡn quá vậy trời
PHP:
Sub Noi_Chuoi()
Dim i As Long, Sarr()
Sarr = Range([A2], [A65536].End(3)).Resize(, 3).Value
For i = 1 To UBound(Sarr)
   Sarr(i, 3) = Sarr(i, 1) & Space(1) & Sarr(i, 2)
Next
[A2].Resize(i - 1, 3) = Sarr
End Sub
 
Upvote 0
Sao giống Thương đang giỡn quá vậy trời
PHP:
Sub Noi_Chuoi()
Dim i As Long, Sarr()
Sarr = Range([A2], [A65536].End(3)).Resize(, 3).Value
For i = 1 To UBound(Sarr)
   Sarr(i, 3) = Sarr(i, 1) & Space(1) & Sarr(i, 2)
Next
[A2].Resize(i - 1, 3) = Sarr
End Sub
không dùng vòng lặp được không ?. code này vơi quang hai thì muỗi rồi
--=0
 
Upvote 0
Nói về sự kiện và thủ tục cho sự kiện:

Trước hết, phải xác định rõ thế nào là sự kiện và thế nào là thủ tục cho sự kiện.
Ngoài ra các thủ tục sự kiện của sheet là các thủ tục có thể có tham số, chứ không phải hàm như phihn nói. Thủ tục sự kiện Sheet_Activate có tham số đối số gì đâu, sao gọi là hàm được?

1. Sự kiện là gì và thủ tục sự kiện là gì:

Bất kỳ 1 thao tác nào chúng ta tác động lên sheet là xảy ra 1 sự kiện. Thủ tục thực thi ngay sau khi sự kiện diễn ra và do xảy ra sự kiện mà chạy, đó là thủ tục sự kiện. Tuy nhiên không phải sự kiện nào cũng có sẵn 1 thủ tục sự kiện.

2. Phân loại:
Phân loại 1: Thủ tục sự kiện có tham số Cancel (As Boolean) và thủ tục sự kiện không có Cancel. Thí dụ thủ tục sự kiện Change không có tham số Cancel

Phân loại 2: Thủ tục sự kiện có tham số và Thủ tục sự kiện không có tham số. Thí dụ thủ tục Worksheet_Activate không có tham số.

Phân loại 3: Nếu phân loại các thủ tục sự kiện theo tham số thì các thủ tục sự kiện của sheet có 2 loại:
- Tham số truyền là Target As Range
- Tham số truyền không phải Target As Range.

3. Target là gì:

a. Trước tiên Target trong các thủ tục sự kiện là 1 tham số truyền, và có kiểu Range. (Gọi là biến nghe không ổn lắm). Sự kiện có tham số Target là sự kiện đánh vào 1 Range trên sheet. Tên tham số có thể đặt là gì cũng được, (dĩ nhiên), nhưng không phải ngẫu nhiên người ta đặt tên tham số là Target (mục tiêu): Target chính là range mục tiêu của sự kiện vừa diễn ra: Click chọn, tô chọn, thay đổi giá trị, nhấn chuột phải, nhấn đúp (double click), nhấn vào hyperlink trong range.

- Range nào không phải mục tiêu của sự kiện vừa diễn ra thì không phải Target

- Khi đặt kiểu cho tham số truyền là Range thì chỉ khi nào mục tiêu của sự kiện là range thì thủ tục sự kiện mới chạy, thí dụ thủ tục sự kiện Selection_Change không chạy khi click chọn biểu đồ, click chọn AutoShape, mà chỉ chạy khi click chọn (tô chọn) 1 Range.

Như vậy Target là 1 Range vừa mới chịu sự tác động, là mục tiêu của sự kiện vừa mới diễn ra.

b. Target là 1 Range, nên Target có thể là 1 Range 1 ô hay nhiều ô, và có thể là các ô (dãy ô) không liên tục. Thí dụ viết thủ tục cho sự kiện click chọn ô, tô chọn vùng:

PHP:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MsgBox Target.Address
End Sub

Và thử click chọn 1 ô, tô chọn 1 vùng, nhấn Ctrl hoặc Shift chọn nhiều vùng không liên tục hoặc liên tục.

c. Target là 1 Range nên có đầy đủ tính chất của 1 range (Properties), và có thể dùng các phương thức khác nhau (methods) để đánh vào Target như Copy, định dạng, Find, ... Xin nhấn mạnh rằng target là 1 range với đầy đủ các thuộc tính, chứ không chỉ là thuộc tính giá trị như phihn nói. Chẳng qua giá trị (value) là property mặc định của range mà thôi. Nên nếu dùng câu lệnh MsgBox Target ta sẽ có giá trị của Target (nếu Target là ô đơn lẻ).
 
Lần chỉnh sửa cuối:
Upvote 0
không dùng vòng lặp được không ?. code này vơi quang hai thì muỗi rồi
--=0
Không dùng vòng lặp chắc phải xử lý trên sheet mới được

PHP:
Sub noichuoi2()
Range([A2], [A65536].End(3)).Offset(, 2).FormulaR1C1 = "=RC[-2]& "" ""&RC[-1]"
End Sub
Hoặc xóa luôn công thức
PHP:
Sub noichuoi2()
With Range([A2], [A65536].End(3)).Offset(, 2)
   .FormulaR1C1 = "=RC[-2]& "" ""&RC[-1]"
   .Value = .Value
End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Thủ tục sự kiện có tham số Cancel.

Gồm có 2 thủ tục cho 2 sự kiện là DoubleClick và RightClick.

Đó là Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean) và
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

Tham số Cancel có kiểu boolean, và mặc định có giá trị False. Nếu ta gán giá trị True cho nó, sự kiện tiếp theo lẽ ra phải diễn ra, sẽ không diễn ra nữa.

Khi nhấn chuột phải vào 1 ô, bình thường sẽ xuất hiện menu ngữ cảnh (còn gọi là menu chuột phải). Nếu ta viết thủ tục sau:

PHP:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
End Sub

Thì menu chuột phải sẽ không xuất hiện.

Đối với sự kiện DoubleClick, bình thường sẽ có 1 trong 2 sự kiện tiếp theo xảy ra:
- Ô được double click, chuyển sang dạng Edit Mode để chỉnh sửa nội dung
- Nếu Option đã được thay đổi là Not allow edit directly in cells, và nếu ô có chứa công thức tham chiếu đến ô khác, ô hiện hành sẽ nhảy sang ô tham chiếu đó.

Nếu ta viết thủ tục sự kiện Worksheet_BeforeDoubleClick và gán Cancel = True, thì chẳng sự kiện nào trong 2 sự kiện trên xảy ra.
 
Lần chỉnh sửa cuối:
Upvote 0
Có một số bạn thường nói "Sự kiện WorkSheet_Change", một cách nói vắn tắt và có thể hiểu là thủ tục cho sự kiện Change. Tạm chấp nhận.

Tuy nhiên nếu có bạn nào nói "định dạng ô không phải sự kiện nên code worksheet_change không chạy" thì là phát biểu sai.

Bất cứ hành vi nào tác động lên sheet đều là sự kiện. Tuy nhiên không phải sự kiện nào làm thay đổi range đều được thủ tục sự kiện WorkSheet_Change "bắt". Sự kiện tô màu kẻ khung ô vẫn diễn ra, chỉ có điều sự kiện đó không được đưa vào danh sách sự kiện của thủ tục sự kiện, hoặc nói khác đi, sự kiện đó không dẫn đến việc thực thi thủ tục sự kiện mà thôi.
 
Upvote 0
Không dùng vòng lặp chắc phải xử lý trên sheet mới được

PHP:
Sub noichuoi2()
Range([A2], [A65536].End(3)).Offset(, 2).FormulaR1C1 = "=RC[-2]& "" ""&RC[-1]"
End Sub
Hoặc xóa luôn công thức
PHP:
Sub noichuoi2()
With Range([A2], [A65536].End(3)).Offset(, 2)
   .FormulaR1C1 = "=RC[-2]& "" ""&RC[-1]"
   .Value = .Value
End With
End Sub
Đối với các anh em mới tập Vba thì nên dùng cách xử lý trên cell. Còn có thể viết cách khác. Như Do loop... cũng được.
 
Upvote 0
Upvote 0
đoạn này có ý nghĩa gì hén các pro. em chưa học nên không biết

Sarr = Range([A2], [A65536].End(3)).Resize(, 3).Value
 
Upvote 0
đoạn này có ý nghĩa gì hén các pro. em chưa học nên không biết

Sarr = Range([A2], [A65536].End(3)).Resize(, 3).Value

Lấy dữ liệu từ A2 đến dòng cuối cùng cột A --> mở rộng ra đến cột C và nạp vào mảng Sarr.
Giống như cho dữ liệu (A2:C dòng cuối cùng cột A) vào mảng Sarr.
 
Upvote 0
đoạn này có ý nghĩa gì hén các pro. em chưa học nên không biết

Sarr = Range([A2], [A65536].End(3)).Resize(, 3).Value

chắc là vậy
vùng từ A2 đến A có dòng data cuối cùng, mở rộng thêm 3 cột
thành A2:C100 (thí dụ A100 là cell cuối cùng cột A có số liệu)
hỏng bít đúng hong nữa thử vậy xem

Range([A2], [A65536].End(3)).Resize(, 3).select
 
Upvote 0
a. Trước tiên Target trong các thủ tục sự kiện là 1 tham số truyền, và có kiểu Range. (Gọi là biến nghe không ổn lắm)

Những gì Sư phụ nó về SỰ KIỆN của Worksheet thì đã đầy đủ và chính xác rồi, em không thảo luận thêm gì nữa, nhưng em nói rộng một chút về cái phần em tô đậm:

Sự kiện được thực hiện bởi một thủ tục (Sub) chứ không phải một hàm (Function) - cái này cũng đã được Sư phụ nói đến rất rõ.


Cấu trúc của một Sub:

Syntax:

[Private | Public | Friend] [Static] Sub name [(arglist)]

[statements]

[Exit Sub]

[statements]

End Sub


Vậy cái arglist là gì?

Đó chính là 'argument list' gọi nôm na là 'danh sách đối số'.

Thế một argument là gì?

Đó chính là: 'A constant, variable, or expression passed to a procedure' tạm dịch là 'Một hằng số, biến, hoặc biểu hiện thông qua một thủ tục'.

Vậy trong cú pháp của một Sub thì arglist được sử dụng như thế nào?

arglist: Optional. List of variables representing arguments that are passed to the Sub procedure when it is called. Multiple variables are separated by commas.

(tạm dịch là: Tùy chọn. Danh sách các biến đại diện cho đối số được truyền cho thủ tục Sub khi nó được gọi. Nhiều biến số thì được phân cách bằng dấu phẩy (,).)


Từ những việc nói trên, ta có thể khẳng định rằng Target chính là một biến, biến đó là đối số được truyền trong thủ tục, mà nói ngắn gọn như Sư phụ là một tham số truyền, còn việc "Gọi biến là không ổn" là chưa chính xác vì nó rất "ổn" và rất chính xác.
 
Upvote 0
Vậy cái arglist là gì?

Đó chính là 'argument list' gọi nôm na là 'danh sách đối số'.

Thế một argument là gì?

Đó chính là: 'A constant, variable, or expression passed to a procedure' tạm dịch là 'Một hằng số, biến, hoặc biểu hiện thông qua một thủ tục'.

Từ những việc nói trên, ta có thể khẳng định rằng Target chính là một biến, biến đó là đối số được truyền trong thủ tục, mà nói ngắn gọn như Sư phụ là một tham số truyền, còn việc "Gọi biến là không ổn" là chưa chính xác vì nó rất "ổn" và rất chính xác.

Nghĩa luôn luôn nhầm lẫn giữa chung và riêng. Lần trước trong cú pháp hàm InputBox cũng nhầm lẫn tham số của hàm với hằng. Lần này lại lấy cái riêng gán cho cái chung.

Chính trong câu trích của Nghĩa, bên trong thủ tục là Argument List, và nó không phải chỉ là biến, nó còn là hằng, là expression, ...

Vậy thì trong bài viết mang tính tổng quát, phải nói đến cái chung là arguments các loại (tham số), chứ không nói đến cái riêng là biến, dù Target có thể là biến.

Tôi nói rất rõ trong bài trên (lúc chưa viết lại) là Nghĩa không sai, chỉ là không đầy đủ. Khi viết chính thức, tôi cũng không bảo là sai, mà chỉ bảo là không ổn.

Nếu tôi không ghi chữ "không ổn" và Nghĩa không phản ứng, thì người mới học đâu có được Nghĩa giới thiệu nào là argument, nào là const, nào là expression?

Viết tổng quát thì phải viết bằng danh từ chỉ cái chung, nếu nói chi tiết đến cái riêng thì phải liệt kê hết những cái riêng ngay từ đầu chứ?
 
Upvote 0
Những gì Sư phụ nó về SỰ KIỆN của Worksheet thì đã đầy đủ và chính xác rồi, em không thảo luận thêm gì nữa, nhưng em nói rộng một chút về cái phần em tô đậm:

Sự kiện được thực hiện bởi một thủ tục (Sub) chứ không phải một hàm (Function) - cái này cũng đã được Sư phụ nói đến rất rõ.


Cấu trúc của một Sub:

Syntax:

[Private | Public | Friend] [Static] Sub name [(arglist)]

[statements]

[Exit Sub]

[statements]

End Sub


Vậy cái arglist là gì?

Đó chính là 'argument list' gọi nôm na là 'danh sách đối số'.

Thế một argument là gì?

Đó chính là: 'A constant, variable, or expression passed to a procedure' tạm dịch là 'Một hằng số, biến, hoặc biểu hiện thông qua một thủ tục'.

Vậy trong cú pháp của một Sub thì arglist được sử dụng như thế nào?

arglist: Optional. List of variables representing arguments that are passed to the Sub procedure when it is called. Multiple variables are separated by commas.

(tạm dịch là: Tùy chọn. Danh sách các biến đại diện cho đối số được truyền cho thủ tục Sub khi nó được gọi. Nhiều biến số thì được phân cách bằng dấu phẩy (,).)


Từ những việc nói trên, ta có thể khẳng định rằng Target chính là một biến, biến đó là đối số được truyền trong thủ tục, mà nói ngắn gọn như Sư phụ là một tham số truyền, còn việc "Gọi biến là không ổn" là chưa chính xác vì nó rất "ổn" và rất chính xác.
Thấy A viết khá hay, phiềm A nêu rõ thêm định nghĩa: thế nào là biến , và thế nào là tham số đc ko?
 
Upvote 0
Nghĩa luôn luôn nhầm lẫn giữa chung và riêng. Lần trước trong cú pháp hàm InputBox cũng nhầm lẫn tham số của hàm với hằng. Lần này lại lấy cái riêng gán cho cái chung.

Chính trong câu trích của Nghĩa, bên trong thủ tục là Argument List, và nó không phải chỉ là biến, nó còn là hằng, là expression, ...

Vậy thì trong bài viết mang tính tổng quát, phải nói đến cái chung là arguments các loại (tham số), chứ không nói đến cái riêng là biến, dù Target có thể là biến.

Tôi nói rất rõ trong bài trên (lúc chưa viết lại) là Nghĩa không sai, chỉ là không đầy đủ. Khi viết chính thức, tôi cũng không bảo là sai, mà chỉ bảo là không ổn.

Nếu tôi không ghi chữ "không ổn" và Nghĩa không phản ứng, thì người mới học đâu có được Nghĩa giới thiệu nào là argument, nào là const, nào là expression?

Viết tổng quát thì phải viết bằng danh từ chỉ cái chung, nếu nói chi tiết đến cái riêng thì phải liệt kê hết những cái riêng ngay từ đầu chứ?

Em định nghĩa cái arguments là cái tổng thể, còn trường hợp riêng của Sub nó chỉ là List của các biến mà thôi, không hề có một hằng hay một thứ gì khác!

arglist: Optional. List of variables representing arguments that are passed to the Sub procedure when it is called. Multiple variables are separated by commas.

(tạm dịch là: Tùy chọn. Danh sách các biến đại diện cho đối số được truyền cho thủ tục Sub khi nó được gọi. Nhiều biến số thì được phân cách bằng dấu phẩy (,).)

Cho nên nó chỉ là BIẾN chứ không là những thứ khác được! Còn cách gọi trong trường hợp này gọi chúng là gì thì ta gọi nó là "tham số truyền" hay "đối số truyền", còn câu hỏi của em là "Target là gì?".
 
Upvote 0
Thấy A viết khá hay, phiềm A nêu rõ thêm định nghĩa: thế nào là biến , và thế nào là tham số đc ko?
Không biết Good-Luck hỏi học hay hỏi đố nữa, tuy nhiên hỏi kiểu nào cũng được vì câu hỏi đó khá đơn giản!

Theo Toán Học:


Tham số là gì?

Một tham số là một đối số của một hàm toán học

Trong toán học, sự khác nhau giữa một "tham số" (parameter) và một "đối số" (argument) của một hàm là: tham số là các kí hiệu thuộc phần định nghĩa của hàm, trong khi các đối số là các kí hiệu được cung cấp cho hàm khi nó được dùng.


Biến là gì?

Biến số là một số có giá trị bất kỳ, không bắt buộc phải duy nhất có một giá trị (không có giá trị nhất định), biến số là số có thể thay đổi giá trị trong một tình huống có thể thay đổi. Ngược lại với khái niệm biến số là một khái niệm hằng số. Hằng số là một số không thể thay đổi trong bất kỳ các tình huống nào đó.

VBA cũng định nghĩa chúng theo phương pháp toán học mà thôi.
 
Upvote 0
theo tôi được biết trong ngôn ngữ lập trình C++
biến là một vùng nhớtên dùng để lưu trữ các giá trị khi tính toán, các giá trị của biến có thể thay đổi trong suốt thời gian chương trình thực thi.
vùng nhớ này có độ lớn nhỏ tùy theo kiểu dữ liệu
 
Upvote 0
Câu hỏi 8: Làm sao để có được dòng Option Explicit tự động khi bạn tạo Module mới ?

Liên quan đến bài này:

Câu hỏi 5: Bằng câu lệnh nào khi chạy code sẽ thông báo lỗi khi không khai báo biến?

Và một bạn đã trả lời:

À cái này mình biết, đó là

Option Explicit
ngay dòng đầu tiên luôn

Câu hỏi đặt ra là làm sao bạn có thể đặt Option Explicit một cách tự động khi bạn tạo một Module mới mà không cần phải gõ thủ công?
 
Upvote 0
Liên quan đến bài này:
Câu hỏi 5: Bằng câu lệnh nào khi chạy code sẽ thông báo lỗi khi không khai báo biến?
Và một bạn đã trả lời:
Câu hỏi đặt ra là làm sao bạn có thể đặt Option Explicit một cách tự động khi bạn tạo một Module mới mà không cần phải gõ thủ công?
Vào Tools > Options > Tab Editor > Check Require Variable Declaration > OK.
1.jpg
 
Upvote 0
Câu hỏi 9: Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách

Nhân tiện đây xin đố luôn, không mới nhưng sẽ có người không biết (Chỉ dành cho người mới tập viết VBA):

Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách để ẩn?
 
Lần chỉnh sửa cuối:
Upvote 0
Nhân tiện đây xin đố luôn, không mới nhưng sẽ có người không biết (Chỉ dành cho người mới tập viết VBA):
Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách để ẩn?
Thay Sub thành Private Sub.
Còn cách khác thì em chưa biết, chờ các bạn khác giải đáp.
 
Upvote 0
Nhân tiện đây xin đố luôn, không mới nhưng sẽ có người không biết (Chỉ dành cho người mới tập viết VBA):

Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách để ẩn?
Cho mình xin cái tiêu đề nhé, nhằm mục đích cập nhật link bài viết, chẳng hạn như:

Câu hỏi 9: Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách để ẩn?

Với câu này, khi đang "đau khổ" mình đã có lần hỏi trên diễn đàn và được giúp đỡ.
 
Upvote 0
Cho mình xin cái tiêu đề nhé, nhằm mục đích cập nhật link bài viết, chẳng hạn như:

Câu hỏi 9: Làm sao để ẩn Tên Macro ở cửa sổ Macro (Alt+F8), có bao nhiêu cách để ẩn?

Với câu này, khi đang "đau khổ" mình đã có lần hỏi trên diễn đàn và được giúp đỡ.
Đang ngồi hóng để học ké mấy cái cơ bản. Mình toàn mò mẩm edit nên chẳng có cơ bản gì ráo trọi. Câu hỏi này mình cũng không biết trả lời luôn.
 
Upvote 0
Em định nghĩa cái arguments là cái tổng thể, còn trường hợp riêng của Sub nó chỉ là List của các biến mà thôi, không hề có một hằng hay một thứ gì khác!



Cho nên nó chỉ là BIẾN chứ không là những thứ khác được! Còn cách gọi trong trường hợp này gọi chúng là gì thì ta gọi nó là "tham số truyền" hay "đối số truyền", còn câu hỏi của em là "Target là gì?".

Nghĩa chẳng bao giờ hiểu được tôi (hoặc người mà Nghĩa muốn phản bác) muốn nói gì.

Tôi nói đơn giản 1 câu: Nghĩa không bao giờ giới thiệu cái chung, chưa bao giờ viết 1 bài tổng quát ra hồn. Nghĩa toàn hỏi, hoặc đố, hoặc thí dụ, hoặc giải thích 1 cái riêng, cái nhỏ trong tổng thể.

Tôi nhắc lại, viết trong topic này là viết cho người mới học, từng câu từng chữ phải cân nhắc. Giới thiệu phải giới thiệu tổng quát, giới thiệu chi tiết thì phải giới thiệu hết chi tiết. Chứ không phải nay xì ra 1 dạng variable, mai xì ra 1 const, 1 expression, ... trong khi chỉ cần nói chung là Argument.

Nghĩa có thể biết hết đấy, nhưng viết ra hồn thì không viết. Nếu có ai nói Nghĩa không tổng quát thì Nghĩa phản bác tới cùng. Vụ việc InputBox, vụ việc For next hay Do Loop, vụ việc GoTo, và bên topic khác là vụ việc hàm Joint, Nghĩa luôn luôn đúng, và người khác luôn luôn sai.

Nói 1 câu Nghĩa có thể buồn hoặc giận, chứ Nghĩa chưa có khả năng viết bài giới thiệu kiến thức.

Nói thêm 1 câu, có thể Nghĩa sẽ chửi tôi, chứ tôi thấy nói với đầu gối sướng hơn.
 
Upvote 0

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

Back
Top Bottom