Xoá thằng nào trên listview thì dùng lệnh sau ví dụ dòng 2
Me.ListView1.ListItems.Remove (2)
Xoá trên sheet thì dùng find hay index để tìm dòng cần xoá như bình thường
tiếp tục For next!Dạ, em biết là vậy với điều kiện là xóa từng "thằng" một, nhưng vấn đề là khi mình check nhiều "thằng" và xóa hàng loạt những "thằng" đã check thì làm sao đó mà! Hỏng lẻ không thể làm được hả Anh? Chắc phải có chứ, vì nó đã tạo ra cái checkbox trên listview mà ta?!
Thì như sư phụ Mỹ đã nói: For... Next, xét em nào Checked = True thì RemoveDạ, em biết là vậy với điều kiện là xóa từng "thằng" một, nhưng vấn đề là khi mình check nhiều "thằng" và xóa hàng loạt những "thằng" đã check thì làm sao đó mà! Hỏng lẻ không thể làm được hả Anh? Chắc phải có chứ, vì nó đã tạo ra cái checkbox trên listview mà ta?!
Dim i As Long
With ListView1
For i = .ListItems.Count To 1 Step -1
If .ListItems(i).Checked Then .ListItems.Remove i
Next
End With
Private Sub UserForm_Initialize()
Dim It As ListItem
Dim i
[U]Me.ListView1.View = lvwReport
Me.ListView1.ColumnHeaders.Add 1, , "Danh Sach", 110[/U]
For i = 1 To 50
Me.ListView1.ListItems.Add , , Sheet1.Cells(i, 1)
Next
For i = 1 To 12
Me.ListView1.ListItems.Add , , ""
Next
End Sub
Bạn thay đoạn code sau rồi test nghiên cứu lý do nha
Mã:Private Sub UserForm_Initialize() Dim It As ListItem Dim i [U]Me.ListView1.View = lvwReport[/U] [U]Me.ListView1.ColumnHeaders.Add 1, , "Danh Sach", 110[/U] For i = 1 To 50 Me.ListView1.ListItems.Add , , Sheet1.Cells(i, 1) Next For i = 1 To 12 Me.ListView1.ListItems.Add , , "" Next End Sub
Sub DeleteListItemsChecked()
Dim i As Long, j As Long, Rng As Range
With ListView1
For i = 1 To .ListItems.Count
If .ListItems(i).Checked = True Then
With Sheet1.[A1:A50]
Set Rng = .Find(ListView1.ListItems(i), LookIn:=xlValues, LookAt:=xlWhole)
''If Not Rng Is Nothing Then Sheet1.Rows(Rng.Row).Delete
If Not Rng Is Nothing Then Sheet1.Cells(Rng.Row, 1).Delete 2
End With
End If
Next
For j = .ListItems.Count To 1 Step -1
If .ListItems(j).Checked Then .ListItems.Remove j
Next
End With
End Sub
Xóa Item trong Listview và xóa dữ liệu trên sheet sao không làm 1 lần luôn mà phải chia ra 2 vòng lập For thế nhỉ?Theo code của Anh Sealand thì em nghiệm ra rằng, thứ nhất là phải chọn thuộc tính View là lvwReport, thứ hai là phải thêm header cho cột.
Vấn đề xóa nhiều check thì em làm như sau:
PHP:Sub DeleteListItemsChecked() Dim i As Long, j As Long, Rng As Range With ListView1 For i = 1 To .ListItems.Count If .ListItems(i).Checked = True Then With Sheet1.[A1:A50] Set Rng = .Find(ListView1.ListItems(i), LookIn:=xlValues, LookAt:=xlWhole) ''If Not Rng Is Nothing Then Sheet1.Rows(Rng.Row).Delete If Not Rng Is Nothing Then Sheet1.Cells(Rng.Row, 1).Delete 2 End With End If Next For j = .ListItems.Count To 1 Step -1 If .ListItems(j).Checked Then .ListItems.Remove j Next End With End Sub
Lưu ý, với ListItems phải là không có dấu tiếng Việt (unicode) và ListItems không bị trùng; còn nếu nguồn trong sheet là font Unicode và đã convert từ Unicode sang VNI trong Listview thì phải chuyển sang VNI sang Unicode trong Find thì mới xóa chính xác.
Cám ơn Anh NDU và Anh Seland đã tận tình giúp đỡ em.
Đúng rồi, tại em lúc đầu thử 2 cái riêng biệt rồi ghép lại, thêm nữa lúc đầu ListItems có dấu tiếng Việt, em chạy hoài nó không xóa, sau khi thử nhiều cách rồi mới biết nguyên nhân là vậy, rồi không kiểm tra lại vòng lặp.Xóa Item trong Listview và xóa dữ liệu trên sheet sao không làm 1 lần luôn mà phải chia ra 2 vòng lập For thế nhỉ?
Private Sub CommandButton2_Click()
Dim i As Long, Rng As Range
With ListView1
For i = .ListItems.Count To 1 Step -1
If .ListItems(i).Checked Then
With Sheet1.[A1:A50]
Set Rng = .Find(ListView1.ListItems(i), LookIn:=xlValues, LookAt:=xlWhole)
If Not Rng Is Nothing Then Sheet1.Range("A" & Rng.Row, "B" & Rng.Row).Delete 2
End With
.ListItems.Remove i
End If
Next
End With
End Sub
Em nghĩ đâu cần thiết phải thêm cột hả anh!2/Mình cũng đã sử dụng Listview để tìm xoá thì chắc ăn nhất là thêm cột số dòng và cho độ rộng dòng này bằng không (Nó không hiện ra). Khi xoá thằng nào thì cứ xem số tại cột đó bằng bao nhiêu rồi xoá dòng đó là chắc như đinh.
Em nghĩ đâu cần thiết phải thêm cột hả anh!
Ví dụ: SrcRng là vùng dữ liệu mà ta Add vào ListView, vậy thì trên ListView, khi ta check tại mục số 5, cũng hoàn toàn tương đương với SrcRng(5,1) trên sheet ---> Cứ thế mà xóa thôi
(Đang nói SrcRng là dữ liệu 1 cột nhiều dòng)
Option Explicit
Dim lsvItem As ListItem, i As Long, j As Long
Private Sub UserForm_Initialize()
With ListView1
.ColumnHeaders.Clear: .ListItems.Clear
For i = 1 To 2
.ColumnHeaders.Add , , Sheet1.Cells(1, i)
.ColumnHeaders(i).Width = 130
Next
For j = 1 To Sheet1.[A5000].End(xlUp).Row - 1
Set lsvItem = .ListItems.Add(, , Sheet1.Cells(j + 1, "A"))
lsvItem.SubItems(1) = Sheet1.Cells(j + 1, 2)
Next
End With
End Sub
Private Sub CommandButton1_Click()
If CommandButton1.Caption = "Check ALL" Then
For Each lsvItem In Me.ListView1.ListItems
lsvItem.Checked = True
Next
CommandButton1.Caption = "UnCheck ALL"
Else
For Each lsvItem In Me.ListView1.ListItems
lsvItem.Checked = False
Next
CommandButton1.Caption = "Check ALL"
End If
End Sub
Private Sub CommandButton2_Click()
With ListView1
For i = .ListItems.Count To 1 Step -1
If .ListItems(i).Checked Then
j = .ListItems(i).Index + 1
Sheet1.Range("A" & j, "B" & j).Delete 2
.ListItems.Remove i
End If
Next
End With
End Sub
Em nghĩ đâu cần thiết phải thêm cột hả anh!
Ví dụ: SrcRng là vùng dữ liệu mà ta Add vào ListView, vậy thì trên ListView, khi ta check tại mục số 5, cũng hoàn toàn tương đương với SrcRng(5,1) trên sheet ---> Cứ thế mà xóa thôi
(Đang nói SrcRng là dữ liệu 1 cột nhiều dòng)
Ai lại làm thế!PHP:Private Sub CommandButton1_Click() Dim lsvItem As ListItem If CommandButton1.Caption = "Check ALL" Then For Each lsvItem In Me.ListView1.ListItems lsvItem.Checked = True Next CommandButton1.Caption = "UnCheck ALL" Else For Each lsvItem In Me.ListView1.ListItems lsvItem.Checked = False Next CommandButton1.Caption = "Check ALL" End If End Sub
Private Sub CommandButton1_Click()
Dim lsvItem As ListItem
With CommandButton1
For Each lsvItem In Me.ListView1.ListItems
lsvItem.Checked = .Caption = "Check ALL"
Next
.Caption = IIf(.Caption = "Check ALL", "UnCheck ALL", "Check ALL")
End With
End Sub
listview nó có phương thức sort, vậy mà dựa vào index thì dễ oan gia lắm.
Private Sub ListViewSort(mLView As ListView, ByVal ColumnHeader As MSComctlLib.ColumnHeader)
With mLView
.Sorted = True
.SortKey = ColumnHeader.SubItemIndex
If .SortOrder = lvwDescending Then
.SortOrder = lvwAscending
Else
.SortOrder = lvwDescending
End If
.Sorted = False
End With
End Sub
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
Call ListViewSort(ListView1, ColumnHeader)
End Sub
Thật ra cũng chẳng hề gì nếu bạn... khéoĐã kiểm tra, nếu mà SORT thì oan gia thiệt, thử với nó là biết liền! Hic, Hic
PHP:Private Sub ListViewSort(mLView As ListView, ByVal ColumnHeader As MSComctlLib.ColumnHeader) With mLView .Sorted = True .SortKey = ColumnHeader.SubItemIndex If .SortOrder = lvwDescending Then .SortOrder = lvwAscending Else .SortOrder = lvwDescending End If .Sorted = False End With End Sub
Như vậy, muốn dùm hàm FIND hay INDEX để xóa trong sheet, thì người thiết kế phải nắm chắc cơ sở dữ liệu của mình như thế nào để không bị mất dữ liệu "oan". VD, nếu dùng INDEX thì không cho thuộc tính SORT, nếu dùng FIND thì dữ liệu phải không trùng... Có như vậy mới chắc chắn rằng mình xóa "đúng người đúng tội".PHP:Private Sub ListView1_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader) Call ListViewSort(ListView1, ColumnHeader) End Sub
Thật ra cũng chẳng hề gì nếu bạn... khéo
Cứ cho rằng chúng ta sẽ sort trên Listview đi, vậy thì ngay lúc AddItem cho Listview, ta cho list ấy vào 1 Dictionary Object với Dic.Key là các phần tử của Listview còn Dic.Item là STT ---> Mai này tìm kiếm thì cứ tra vào Dictionary mà tìm ra STT tương ứng
Có vấn đề gì không?
Bảo đảm với bạn rằng Find Method không sao bằng tốc độ so với dùng Array đâu
Ôi... vô vàn cách để nghiên cứu, nhưng cách dùng cột phụ như anh sealand thì em cho là... không được "đẹp" lắm
Ẹc... Ẹc...
Private Sub UserForm_Initialize()
With ListView1
.ColumnHeaders.Clear: .ListItems.Clear
For i = 1 To 2
.ColumnHeaders.Add , , Sheet1.Cells(1, i)
.ColumnHeaders(i).Width = 130
Next
.ColumnHeaders.Add , , "LINE"
.ColumnHeaders(3).Width = 0
For j = 1 To Sheet1.[A5000].End(xlUp).Row - 1
Set lsvItem = .ListItems.Add(, , Sheet1.Cells(j + 1, "A"))
For k = 1 To 2
Select Case k
Case 2: lsvItem.SubItems(k) = Format(Cells(j + 1, k + 1).Row, "00000") '<-- dung de sort moi dinh dang
Case Else: lsvItem.SubItems(k) = Sheet1.Cells(j + 1, k + 1)
End Select
Next k, j
End With
End Sub
Private Sub CommandButton2_Click()
With ListView1
For i = .ListItems.Count To 1 Step -1
If .ListItems(i).Checked Then
j = .ListItems(i).ListSubItems(2)
Sheet1.Range("A" & j, "B" & j).Delete 2
.ListItems.Remove i
End If
Next
End With
End Sub
Bảo đảm với bạn rằng Find Method không sao bằng tốc độ so với dùng Array đâu
Ôi... vô vàn cách để nghiên cứu, nhưng cách dùng cột phụ như anh sealand thì em cho là... không được "đẹp" lắm
Ẹc... Ẹc...
Tra Dictionary và lấy Index là y chang nhau mà anh..Mình lại nghĩ khác, khi sử lý các vấn đề phức tạp khác nó sẽ nảy sinh vấn đề xung đột. Luôn có 1 cái dictionnary tồn tại trong suốt quá trình tồn tại form. Động tác tra chưa chắc nhanh gọn hơn lấy subitem.
Mình lưu ý là để ở sublistem chứ không ở listitem.
Private Sub UserForm_Terminate()
Call XoaDongTrong
End Sub
'----------------------------------------------
Private Sub XoaDongTrong()
On Error Resume Next
With Sheet1.UsedRange
.SpecialCells(2).EntireRow.Hidden = True
.SpecialCells(12).EntireRow.Delete
.EntireRow.Hidden = False
End With
End Sub
Private Sub CommandButton2_Click()
With ListView1
For i = .ListItems.Count To 1 Step -1
If .ListItems(i).Checked Then
j = .ListItems(i).ListSubItems(2)
Sheet1.Range("A" & j, "B" & j).Clear '<--- thay cho Delete
.ListItems.Remove i
End If
Next
End With
End Sub