Nhờ Giúp - giải thuật cách viết macro sử dụng left(tên sheet;2) (1 người xem)

Liên hệ QC

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

hoangtrong_vbnd

Thành viên hoạt động
Tham gia
14/1/11
Bài viết
156
Được thích
7
Giới tính
Nam
Chào các bác,
Các bác có thể chỉ giúp e cách viết sao cho các sheet trùng tên ở 2 ký tự đầu sẽ hiện và các sheet còn lại sẽ ẩn đi,
Cụ thể D110, D120 sẽ trùng D1 --> hiện còn lại ẩn, E muốn viết " Nếu Left(sheetname, 2) = D1 thì hiện, còn lại thì ẩn"
E110, E120 sẽ trùng E1 --> hiện còn lại ẩn, E muốn viết " Nếu Left(sheetname, 2) = E1 thì hiện, còn lại thì ẩn"
....
---> Nhờ mọi người chỉ giúp
E có một đoạn tham khảo mà chưa biết nên sửa thế nào cho hợp lý
Sub RibbonLoad(ribbon As IRibbonUI)
Dim sh As Worksheet, sheetName As String
Set rb = ribbon
For Each sh In Sheets
If sh.Visible = -1 Then
currSheetName = Left(sheetName, 2)
Exit For
End If
Next sh
End Sub
Sub ButtonClick(control As IRibbonControl)
If currSheetName <> control.ID Then
Sheets(control.ID).Visible = -1
Sheets(currSheetName).Visible = 0
currSheetName = control.ID
End If
End Sub
Cảm ơn mọi người!
 

File đính kèm

Nếu không có sheet nào trùng thì sao? Đâu thể ẩn tất cả!
 
Upvote 0
Giải thuật:

Lập một ArrayList: aList = CreateObject("System.Collections.ArrayList")
Dùng chỉ số i đọc collection Sheets, ghi tên sheet vào aList
Sort aList
Đọc aList, nếu phần tử nào không trùng (2 ký tự) với trước nó hoặc sau nó thì ẩn đi.
Hết

Các thủ thuật giúp tránh lỗi:
- So sánh chuỗi: Khi ghi tên sheet, nên UCase để dễ so sánh
- Tránh lỗi ẩn tất cả các sheets: khi ẩn sheet, đếm số sheet bị ẩn. Khi số này bằng sheets.Count - 1 thì ngưng không ẩn nữa
- Tránh lối (i-1) ở đầu và i+1) ở cuối: sau khi sort, Insert một chuỗi "///" vào đầu list và Add một chuỗi "\\\" vào cuỗi list
 
Upvote 0
Macro sau nhập vào 2 ký tự đầu tiên của sheet. Nếu không có sheet nào phù hợp thì không làm gì cả, ngược lại sẽ hiện các sheet đó và ẩn các sheet còn khác. Trường hợp dùng lệnh On Error... để bẫy lỗi tránh ẩn hết các sheet cũng được nhưng nếu không có sheet nào phù hợp thì kết quả chỉ còn 1 sheet hiện.
Sub Main()
Dim sh As Worksheet
Dim n As String
Dim a As Boolean
n = InputBox("Enter 2 left character of sheet name:")
For Each sh In Sheets
If Left(sh.Name, 2) = n Then
a = True
'Them lenh sau de tranh loi an het cac sheet
sh.Visible = xlSheetVisible
Exit For
End If
Next
If Not (a) Then
MsgBox "No valid sheets"
Exit Sub
End If
For Each sh In Sheets
If Left(sh.Name, 2) = n Then sh.Visible = xlSheetVisible Else sh.Visible = xlSheetHidden
Next
End Sub
 
Upvote 0
Mình có cách củ chuối này, bạn xem thử:
Khai 1 biến kiểu chuỗi (như Txt)
Duyệt qua lần lượt các trang;
Qua mỗi trang, nếu 2 ký tự tên của nó chưa có trong Txt thì ghi nối 2 ký tự đó vô & ngăn cách với nhau bỡi kí tự không chấp nhận trong tên trang tính

Duyệt các trang lại lần nữa; Nhưng lần này cho ẩn các trang trùng 2 kí tự đầu với Txt (Xài hàm Intr() trong VBA)

Chúc thành công!
 
Upvote 0
Mình có cách củ chuối này, bạn xem thử:
Khai 1 biến kiểu chuỗi (như Txt)
Duyệt qua lần lượt các trang;
Qua mỗi trang, nếu 2 ký tự tên của nó chưa có trong Txt thì ghi nối 2 ký tự đó vô & ngăn cách với nhau bỡi kí tự không chấp nhận trong tên trang tính { KQ 1}

Duyệt các trang lại lần nữa; Nhưng lần này cho ẩn các trang trùng 2 kí tự đầu với Txt (Xài hàm Intr() trong VBA) { KQ 2 }

Chúc thành công!

Các sheets: sheet1, sheet2, sheet3, N1, N2, N3, N33
{ KQ 1} chuỗi ghi được: ";sh;N1;N2;N3"
{ KQ 2} đọc lại:
sheet1 : ";sh;N1;N2;N3" --> ẩn
sheet2 : ";sh;N1;N2;N3" --> ẩn
sheet3 : ";sh;N1;N2;N3" --> ẩn
N1 : ";sh;N1;N2;N3" --> ẩn
N2 : ";sh;N1;N2;N3" --> ẩn
N3 : ";sh;N1;N2;N3" --> ẩn
N33 : ";sh;N1;N2;N3" --> ẩn
--> tất cả đều ẩn !!!

Mấu chốt của vấn đề là đếm xem có bao nhiêu trang có cùng 2 ký tự đầu. Cách mà tôi thấy quý vị ở diễn đần này thích dùng nhất là dùng Dictionary để đếm. Sau đó duyệt lại, cái nào đếm hơn 1 là có trùng lặp.

Nếu muốn dùng chuỗi thì lúc ghi, lần đầu tiên ghi cùng với một ký tự "0", nếu thấy đã ghi rồi thì sửa lại thành "1"

Các sheets: sheet1, sheet2, sheet3, N1, N2, N3, N33
{ KQ đọc sheet đầu tiên } chuỗi ghi được: ";sh0"
{ KQ đọc sheet thứ nhì } chuỗi ghi được: ";sh1"
{ KQ 1 sau khi đọc hết các sheets } chuỗi ghi được: ";sh1;N10;N20;N31"
{ KQ 2} đọc lại:
sheet1 : ";sh1;N10;N20;N31" --> có "sh" nhưng sau nó là "1", không ẩn
sheet2 : ";sh1;N10;N20;N31" --> có "sh" nhưng sau nó là "1", không ẩn
sheet3 : ";sh1;N10;N20;N31" --> có "sh" nhưng sau nó là "1", không ẩn
N1 : ";sh1;N10;N20;N31" --> có "N1", và sau nó là "0", ẩn
N2 : ";sh1;N10;N20;N31" --> có "N2", và sau nó là "0", ẩn
N3 : ";sh1;N10;N20;N31" --> có "N3", và sau nó là "1", không ẩn
N33 : ";sh1;N10;N20;N31" --> có "N3", và sau nó là "1", không ẩn

chú thích: số 0/1 không ngại trùng với tên sheet bởi vì khi xét, bạn kèm xét với dấu ";"
 
Upvote 0
Mình ủng hộ cách giải quyết của bác HYen17, nó đơn giản và có thể đáp ứng được yêu cầu.
Nhưng theo mình thì bỏ đi 1 vòng duyệt cũng được. Ví dụ:

Mã:
Sub AttrSh()
Dim Sh As Worksheet, SaveName As String
For Each Sh In ThisWorkbook.Worksheets
If InStr(1, SaveName, Left(Sh.Name, 2)) > 0 Then
Sh.Visible = xlSheetVeryHidden
Else
Sh.Visible = xlSheetVisible
SaveName = SaveName & "~" & Left(Sh.Name, 2)
End If
Next
End Sub
 
Upvote 0
[thongbao]Nhưng theo mình thì bỏ đi 1 vòng duyệt cũng được. Ví dụ: . . . . [/thongbao]

Như vậy có thể bỏ lọt tôi fạm đầu đó chàng "Đất cảng" mến!
 
Upvote 0
[thongbao]Nhưng theo mình thì bỏ đi 1 vòng duyệt cũng được. Ví dụ: . . . . [/thongbao]

Như vậy có thể bỏ lọt tôi fạm đầu đó chàng "Đất cảng" mến!

Em chưa hiểu ý Bác, vì em lập luận như sau:

-Khi start Code thì SaveName = chuỗi rỗng ("").
-Khi start Code với vòng lặp for each thì chắc chắn nó cũng gán Sh với Worksheet đầu tiên theo thứ tự.
Vậy thì Hàm Instr(1,"","xx")=0 là chắc chắn. Vậy thì nó sẽ được trông thấy.

Có 1 chút phân vân: Em chưa rõ yêu cầu thực sự của chủ Topic trong 2 cách hành xử sau:
1/Nếu cứ gặp thằng cha nào có 2 chữ đầu của tên chưa giống ai thì trông thấy nó. Đây là cách hiển thị theo Index của Worksheet (Thứ tự của nó từ trái sang phải trên Tab Sheet. Code đang xử theo cách này.)
2/Chỉ hiển thị đối với thằng nào có tên nhỏ nhất. Vis dụ trật tự là : AH002--AH003--001 thì hiển thị AH001
 
Upvote 0
Em chưa hiểu ý Bác, vì em lập luận như sau:

-Khi start Code thì SaveName = chuỗi rỗng ("").
-Khi start Code với vòng lặp for each thì chắc chắn nó cũng gán Sh với Worksheet đầu tiên theo thứ tự.
Vậy thì Hàm Instr(1,"","xx")=0 là chắc chắn. Vậy thì nó sẽ được trông thấy.

Có 1 chút phân vân: Em chưa rõ yêu cầu thực sự của chủ Topic trong 2 cách hành xử sau:
1/Nếu cứ gặp thằng cha nào có 2 chữ đầu của tên chưa giống ai thì trông thấy nó. Đây là cách hiển thị theo Index của Worksheet (Thứ tự của nó từ trái sang phải trên Tab Sheet. Code đang xử theo cách này.)
2/Chỉ hiển thị đối với thằng nào có tên nhỏ nhất. Vis dụ trật tự là : AH002--AH003--001 thì hiển thị AH001

Với ví dụ của tôi: sheet1, sheet2, sheet3, N1, N2, N3, N33

Theo tôi hiểu thì điều kiện là chỉ ẩn N1, N2 và hiện sheet1, sheet2, sheet3, N3, N33

Code của bạn chỉ hiện sheet2, sheet3, N33 (tức là đúng như bạn ChanhQ@ đã nêu ra: mấy thằng đi đầu bị tóm cổ luôn)

Giải sử chủ thớt chấp nhận điều kiện:

2/Chỉ hiển thị đối với thằng nào có tên nhỏ nhất. Vis dụ trật tự là : AH002--AH003--001 thì hiển thị AH001
Thì code bạn cũng chạy không đúng điều kiện này. Vì bạn không hề sắp xếp thứ tự tên. Nếu có nhiều tên trùng thì cái đầu tiên được hiện, không phải cái nhỏ nhất.
 
Upvote 0
Mọi người thì tranh luận sôi nổi còn chủ topic thì lặn đâu mất tăm. Nếu như tôi đoán đúng thì trừ bạn Hau151978 ra, tất cả những người trả lời ở topic này đều hiểu sai ý của chủ topic.

Theo tôi hiểu thì:

File mà chủ topic muốn tạo là file làm việc của kiểm toán viên. Trong đó có nhiều sheet, các sheet có cùng 2 ký tự đầu là một nhóm để trình bày giấy tờ làm việc của một phần hành.

Chủ topic muốn tạo trên thanh Ribbon các nút lệnh tương ứng với từng phần hành: D1, D2,... , E1, E2,... Khi click vào nút lệnh của phần hành nào thì các sheet của phần hành đó hiện, còn lại thì ẩn (Tôi đoán thế vì trong code ban đầu của chủ topic có Ribbon, Control.ID...). Tuy nhiên, để đơn giản, chủ topic đã thay thế các nút lệnh thành các Shape ở sheet MENU.

Và việc cần làm không phải là so sánh 2 ký tự đầu của các sheet với nhau xem có trùng hay không mà là so sánh 2 ký tự đầu của mỗi sheet với 2 ký tự cho trước, nếu trùng thì hiện, không trùng thì ẩn.

Trước khi làm tiếp nên chờ ý kiến của chủ topic.
 
Upvote 0
Có lẽ vấn đề chỉ giản dị như vậy. Tưởng thuật toán thách đố 1 chút thì còn có hứng chứ code thì lười quá. Xin lỗi chủ thớt vậy.
 
Upvote 0
Có lẽ vấn đề chỉ giản dị như vậy. Tưởng thuật toán thách đố 1 chút thì còn có hứng chứ code thì lười quá. Xin lỗi chủ thớt vậy.
E cũng ko nhờ các bác viết code vì e muốn tự làm điều này ... có điều chưa biết cách sắp xếp một cách khoa học các thứ tự của code để chạy theo yêu cầu.
bác huuthang_bd nói đúng ý e ạ. E muốn các sheet có trùng 2 ký tự đầu theo tên Ví dụ 1 dãy sheet D110, D120, D210, D220, E110, E120 thì
có đoạn lệnh tìm tất cả các sheet trùng D1 --> còn lại các sheet khác ẩn
tiếp đến trùng D2 --> còn lại tất cả các sheet khác ẩn
tương tự...
E chưa biết nên bắt đâu với vòng lặp hay cách gì để đạt được ý muốn của mình.
Giống như chủ đề là giải thuật nên e mong các bác cho ý kiến để e nghiên cứu về đoạn code của mình. Hỏi code các bác nhiều cũng ngại nên e muốn học viết dần dần để đỡ bị lệ thuộc.
Chân thành cảm ơn mọi người!
 
Upvote 0
E cũng ko nhờ các bác viết code vì e muốn tự làm điều này ... có điều chưa biết cách sắp xếp một cách khoa học các thứ tự của code để chạy theo yêu cầu.
bác huuthang_bd nói đúng ý e ạ. E muốn các sheet có trùng 2 ký tự đầu theo tên Ví dụ 1 dãy sheet D110, D120, D210, D220, E110, E120 thì
có đoạn lệnh tìm tất cả các sheet trùng D1 --> còn lại các sheet khác ẩn
tiếp đến trùng D2 --> còn lại tất cả các sheet khác ẩn
tương tự...
E chưa biết nên bắt đâu với vòng lặp hay cách gì để đạt được ý muốn của mình.
Giống như chủ đề là giải thuật nên e mong các bác cho ý kiến để e nghiên cứu về đoạn code của mình. Hỏi code các bác nhiều cũng ngại nên e muốn học viết dần dần để đỡ bị lệ thuộc.
Chân thành cảm ơn mọi người!
Thử thế này xem sao. Tạo thêm 1 sheet tên là Main
Cho code vào 1 module chạy thử
PHP:
Sub An_Hien()
Dim dk As String, sh As Worksheet
dk = InputBox("Nhap nhóm sheet can hien")
For Each sh In Worksheets
    If sh.Name <> "Main" Then
        If sh.Name Like UCase(dk) & "*" Then
            sh.Visible = True
        Else
            sh.Visible = False
        End If
    End If
Next
End Sub
 
Upvote 0
Thử thế này xem sao. Tạo thêm 1 sheet tên là Main
Cho code vào 1 module chạy thử
Cám ơn bác Quanghai1969!
Cách này rất hay nhưng có thể để giá trị mặc định của nó luôn không ạ, vì cứ mỗi lần chạy mình lại nhập 2 ký tự đầu của sheet
Để cho mình click một cái là hiện hết các sheet theo yêu cầu lên
Ví dụ cháu đặt mặc định là D1 thì đặt như thế này được không nhỉ
If sh.Name Like UCase(dk) & "D1" Then
Để cháu thử xem
Cảm ơn bác quan tâm!
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn bác Quanghai1969!
Cách này rất hay nhưng có thể để giá trị mặc định của nó luôn không ạ, vì cứ mỗi lần chạy mình lại nhập 2 ký tự đầu của sheet
Để cho mình click một cái là hiện hết các sheet theo yêu cầu lên
Ví dụ cháu đặt mặc định là D1 thì đặt như thế này được không nhỉ
If sh.Name Like UCase(dk) & "D1" Then
Để cháu thử xem
Cảm ơn bác quan tâm!
Thì mình chỉ đưa ra hướng giải quyết, còn phần bạn muốn chế biến thế nào thì tùy theo yêu cầu của bài toán thôi
Thử vầy xem:
If UCase(sh.Name) Like UCase([D1]) & "*" Then
 
Upvote 0
Cám ơn bác Quanghai1969!
Ví dụ cháu đặt mặc định là D1 thì đặt như thế này được không nhỉ
If sh.Name Like UCase(dk) & "D1" Then
Để cháu thử xem
Cảm ơn bác quan tâm!
Tất nhiên là không được rồi.
Bạn có thể sửa:
dk = InputBox("Nhap nhóm sheet can hien", , "D1")
 
Upvote 0
PHP:
Sub an()
Application.ScreenUpdating = False
Dim sh As Worksheet, SheetName As String
SheetName = Sheets("Menu").Shapes(Application.Caller).AlternativeText
SheetName = Left(SheetName, 2)
For Each sh In Worksheets
            If sh.Name <> "Menu" Then
            If sh.Name Like SheetName & "*" Then
                sh.Visible = True
            Else
                sh.Visible = False
            End If
           End If
Next
Application.ScreenUpdating = True
End Sub
Bác Quanghai1969 ơi, Làm phiền bác chút nữa ạ
Theo như code lần trước bác giúp thì giờ cháu muốn sửa để mặc định 2 ký tự đầu của sheet như thế nào ạ
Left(sheetName, 2) = D1
Cảm ơn bác và mọi người giúp đỡ ạ.
 
Upvote 0
PHP:
Sub an()
Bác Quanghai1969 ơi, Làm phiền bác chút nữa ạ
Theo như code lần trước bác giúp thì giờ cháu muốn sửa để mặc định 2 ký tự đầu của sheet như thế nào ạ
[B]Left(sheetName, 2) = D1
[/B]Cảm ơn bác và mọi người giúp đỡ ạ.[/QUOTE]
Bạn thử code này xem
[code]
Sub ABC()
Dim sh As Worksheet
Dim a As Boolean
For Each sh In Sheets
If Left(sh.Name, 2) = "D1" Then
a = True
sh.Visible = xlSheetVisible
Exit For
End If
Next
If a Then
For Each sh In Sheets
If Left(sh.Name, 2) = "D1" Then sh.Visible = xlSheetVisible Else sh.Visible = xlSheetHidden
Next
End If
End Sub
[/code]
 
Upvote 0

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

Back
Top Bottom