Compare and remove unmatched items from list1 and treeview - vb6

I have list1, treeview, list2
list1 has items
treeview1 has items
list2 empty or has items populating over time
Now I want to loop through list1 compare it with list2 and if items do not match then remove the items from treeview1,list1.
The small problem I am having now is list1 ends up keeping 1 unwanted item.
list1 treeview1 and list2 over time has same items populated but list2 sometimes may not contain the same value as list1 this is why I need to loop and match strings. If not found then remove the strings from list1 and treeview1 the same items only.
This code below you can paste it into fresh vb6 project just add 1 treeview1 list1 and list2 and 2 command button
Private Sub Command1_Click()
List1.AddItem "dezzzzz"
TreeView1.Nodes.Add , , , "dezzzzz" & "/" & "General"
List1.AddItem "tammy8123"
TreeView1.Nodes.Add , , , "tammy8123" & "/" & "General"
List1.AddItem "sarah7232"
TreeView1.Nodes.Add , , , "sarah7232" & "/" & "General"
List2.AddItem "tammy8123"
End Sub
Private Sub Command2_Click()
Dim i As Integer, ii As Integer
Dim iii As Integer, demopacket() As String
For ii = List1.ListCount - 1 To 0 Step -1
Dim lstUserspacket() As String
lstUserspacket() = Split(List1.List(ii), "/")
For iii = 1 To TreeView1.Nodes.Count
demopacket() = Split(TreeView1.Nodes(iii).Text, "/")
For i = List2.ListCount - 1 To 0 Step -1
Dim listpacket() As String
listpacket() = Split(List2.List(i), "/")
If listpacket(0) = demopacket(0) Then
Exit For
End If
Next
If i = -1 Then
On Error Resume Next
List1.RemoveItem ii
TreeView1.Nodes.Remove iii
End If
Next
Next
End Sub
Private Sub Form_Load()
Call Command1_Click
End Sub

My first thought was to simply find the issue with the code you provided. My next thought was realizing the code was too complex for a rather simple task. The code could be as simple as:
Private Sub Command2_Click()
Dim i As Integer
For i = List1.ListCount - 1 To 0 Step -1
If Not ExistsInList(List2, List1.List(i)) Then
TreeView1.Nodes.Remove FindInTree(TreeView1, List1.List(i))
List1.RemoveItem FindInList(List1, List1.List(i))
End If
Next
End Sub
Of course, the controls in question do not provide an Exists or Find method. But it is not a hard task to create you own. If you place the following functions in a Utility module then you can use them in other projects, too:
Public Function ExistsInList(ByVal ListBox As ListBox, ByVal Item As String) As Boolean
Dim i As Integer
For i = 0 To ListBox.ListCount - 1
If ListBox.List(i) = Item Then
ExistsInList = True
Exit Function
End If
Next
End Function
Public Function FindInList(ByVal ListBox As ListBox, ByVal Item As String) As Integer
Dim i As Integer
For i = 0 To ListBox.ListCount - 1
If ListBox.List(i) = Item Then
FindInList = i
Exit Function
End If
Next
End Function
Public Function FindInTree(ByVal TreeView As TreeView, ByVal Item As String) As Integer
Dim i As Integer
For i = 1 To TreeView.Nodes.Count
If InStr(1, TreeView.Nodes(i).Text, Item) > 0 Then
FindInTree = i
Exit Function
End If
Next
End Function

Related

How can run the following code on multiple Excel sheets?

I have a code which I would like to use on multiple sheets, except one sheet. But applying the code to alle sheets is also fine.
Here is the code that I would like to adjust. I am have currently applied it to Excel 2011 in OS X , but I would like to use it for Excel 2010 in Windows.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then
Dim the_selection As String
Dim month_in_review As String
the_selection = Sheet1.Range("A1")
Dim Rep As Integer
For Rep = 2 To 379
the_column = GetColumnLetter_ByInteger(Rep)
month_in_review = Sheet1.Range(the_column & "1")
If the_selection = month_in_review Then
Sheet1.Range(the_column & ":" & the_column).EntireColumn.Hidden = False
Else
Sheet1.Range(the_column & ":" & the_column).EntireColumn.Hidden = True
End If
Next Rep
End If
End Sub
In the module I have the following code:
Public Function GetColumnLetter_ByInteger(what_number As Integer) As String
GetColumnLetter_ByInteger = ""
MyColumn_Integer = what_number
If MyColumn_Ineger <= 26 Then
column_letter = ChrW(64 + MyColumn_Integer)
End If
If MyColumn_Integer > 26 Then
column_letter = ChrW(Int((MyColumn_Integer - 1) / 26) + 64) & ChrW(((MyColumn_Integer - 1) Mod 26) + 65)
End If
GetColumnLetter_ByInteger = column_letter
End Function
If you're asking for one sheet to detect the change in cell "A1" and then to hide/unhide columns on multiple sheets then the prior answers to your question will serve you nicely.
If, on the other hand, you're asking to detect a change in cell "A1" on any sheet and then to hide/unhide columns on just the changed sheet, then the code below will work for you. It accesses the Workbook_SheetChanged event at Workbook level.
A few points about your code:
You can reference cells using their integer or address values with the .Cell property, so Sheet1.Cells(1, 1) is the same as Sheet1.Cells(1, "A"). The same applies to the .Columns property. So there's no real need to convert your integer values to a string. See #Florent B's answer for a good example of this.
Wherever possible, minimise looping sheet interactions as these are very time-consuming. So rather than loop through the columns and hide/unhide each one individually, you could assign them to ranges within your loop and then hide/unhide the ranges all in one go at the end of your loop. If you must interact with the sheet on each iteration of your loop, then set the Application.ScreenUpdating property to false before the start of your loop. There's an example of this property in the sample code below.
Put this in your Workbook module:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Const TARGET_ADDRESS As String = "A1"
Dim cell As Range
Dim hiddenCols As Range
Dim unhiddenCols As Range
Dim selectedMonth As String
Dim monthInReview As String
Dim c As Integer
'Ignore event if not a target worksheet
If Sh.Name = "Not Wanted" Then Exit Sub
'Ignore event if not in target range
Set cell = Target.Cells(1)
If cell.Address(False, False) <> TARGET_ADDRESS Then Exit Sub
'Criteria met, so handle event
selectedMonth = CStr(cell.Value)
For c = 2 To 379
Set cell = Sh.Cells(1, c)
monthInReview = CStr(cell.Value)
'Add cell to hidden or unhidden ranges
If monthInReview = selectedMonth Then
If unhiddenCols Is Nothing Then
Set unhiddenCols = cell
Else
Set unhiddenCols = Union(unhiddenCols, cell)
End If
Else
If hiddenCols Is Nothing Then
Set hiddenCols = cell
Else
Set hiddenCols = Union(hiddenCols, cell)
End If
End If
Next
'Hide and unhide the cells
Application.ScreenUpdating = False 'not really needed here but given as example
If Not unhiddenCols Is Nothing Then
unhiddenCols.EntireColumn.Hidden = False
End If
If Not hiddenCols Is Nothing Then
hiddenCols.EntireColumn.Hidden = True
End If
Application.ScreenUpdating = True
End Sub
You can use a for each loop to loop through all the Worksheets, and check the worksheet name if it should be skipped. Then apply your code onto the sheet selected.
Something like:
Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
If ws.Name <> "Skip Sheet" Then
Dim the_selection As String
Dim month_in_review As String
the_selection = ws.Range("A1")
Dim Rep As Integer
For Rep = 2 To 379
the_column = GetColumnLetter_ByInteger(Rep)
month_in_review = ws.Range(the_column & "1")
If the_selection = month_in_review Then
ws.Range(the_column & ":" & the_column).EntireColumn.Hidden = False
Else
ws.Range(the_column & ":" & the_column).EntireColumn.Hidden = True
End If
Next Rep
End If
Next ws
End If
End Sub
I wasn't entirely sure what you wished to achieve, so i put ws in the place of Sheet1.
This example will show/hide the columns in all the other sheets if the first cell of the column match/differ with the cell A1 of the sheet where this code is placed:
Private Sub Worksheet_Change(ByVal Target As Range)
' exit if not cell A1
If Target.row <> 1 Or Target.column <> 1 Then Exit Sub
Dim sheet As Worksheet
Dim the_selection As String
Dim month_in_review As String
Dim column As Integer
the_selection = Target.Value
' iterate all the sheets
For Each sheet In ThisWorkbook.Worksheets
' skip this sheet
If Not sheet Is Me Then
' iterate the columns
For column = 2 To 379
' get the first cell of the column
month_in_review = sheet.Cells(1, column).Value
' hide or show the column if it's a match or not
sheet.Columns(column).Hidden = month_in_review <> the_selection
Next
End If
Next
End Sub

Iterate through a treeview in VB6

I have a treeview control on the form which looks like:
I want to iterate the treeview and write the contents of the treeview to ini file. So the ini file for the given tree would look like:
[EnvironmentSystem]
UpdateRate=50.0
InclinationAngle=20.7
Latitude=34.0
[Reflection]
NumReflectionLevel=5
NumSunLightLevel=5
NumWeatherLevel=3
TextureNameFormat=Reflection%01d%01d%02d.tga
[CloudsClear]
MaxClouds=48
MaxCloudParticles=51
3DCloudMaterial=CloudMaterial
3DCloudHorizontalSize=1400.0
3DCloudVerticalSize=600.0
3DCloudSizeDeviation=0.6
3DCloudParticleDensity=2.4
ParticleSize=300.0
ParticleSizeDeviation=0.3
MinBaseAltitude=400.0
MaxBaseAltitude=2450.0
UseBottomRow=TRUE
Here is the code that I have written:
Private Sub TvSaveToIniBtn_Click()
Dim nodx As Node
Dim i As Long
Dim sectionCount As Integer
sectionCount = TreeView1.Nodes(1).Children
Set nodx = TreeView1.Nodes(1).Child.FirstSibling
For i = 1 To sectionCount
SaveNodesToIni (nodx.Text)
Set nodx = nodx.Next
Next
End Sub
Sub SaveNodesToIni(sName As Variant)
Dim tvn As Node
Set tvn = TreeView1.Nodes(sName)
Dim chil As Integer
Dim a As Integer
Dim ret As Integer
Dim keyValuePair() As String
Dim nElements As Integer
chil = tvn.Children: If chil = 0 Then Exit Sub ' if no children the exit
Set tvn = tvn.Child.FirstSibling
For a = 1 To chil
keyValuePair = Split(tvn.Text, "=")
nElements = UBound(keyValuePair) - LBound(keyValuePair) + 1
If nElements > 0 Then
ret = WritePrivateProfileString(sName, keyValuePair(0), keyValuePair(1), "C:\\MyPrograms\\config.ini")
End If
Set tvn = tvn.Next
Next
End Sub
It is not giving the correct output, it gets stuck at the second section of reflection and is not able to read the third one. Something wrong with the code.

Excel copy/sort data while counting/removing duplicates

Ok so I've searched and searched and can't quite find what I'm looking for.
I have a workbook and what I'm basically trying to do is take the entries from certain ranges (Sheet1 - E4:E12, E14:E20, I4:I7, I9:I12, I14:I17, & I19:I21) and put them in a separate list on Sheet2. I then want the new list on Sheet2 to be sorted by how many times an entry appeared on Sheet1 as well as display the amount.
example http://demonik.doomdns.com/images/excel.png
Obviously as can be seen by the ranges I listed above, this sample is much smaller lol, was just having trouble trying to figure out how to describe everything and figured an image would help.
Basically I am trying to use VBA (the update would be initialized by hitting a button) to copy data from Sheet1 and put all the ranges into one list in Sheet2 that is sorted by how many times it appeared on Sheet1, and then alphabetically.
If a better discription is needed just comment and let me know, I've always been horrible at trying to describe stuff like this lol.
Thanks in advance!
Another detail: I cant have it search for specific things as the data in the ranges on Sheet1 may change. Everything must be dynamic.
I started out with this data
and used the following code to read it into an array, sort the array, and count the duplicate values, then output the result to sheet2
Sub Example()
Dim vCell As Range
Dim vRng() As Variant
Dim i As Integer
ReDim vRng(0 To 0) As Variant
Sheets("Sheet2").Cells.Delete
Sheets("Sheet1").Select
For Each vCell In ActiveSheet.UsedRange
If vCell.Value <> "" Then
ReDim Preserve vRng(0 To i) As Variant
vRng(i) = vCell.Value
i = i + 1
End If
Next
vRng = CountDuplicates(vRng)
Sheets("Sheet2").Select
Range(Cells(1, 1), Cells(UBound(vRng), UBound(vRng, 2))) = vRng
Rows(1).Insert
Range("A1:B1") = Array("Entry", "Times Entered")
ActiveSheet.UsedRange.Sort Range("B1"), xlDescending
End Sub
Function CountDuplicates(List() As Variant) As Variant()
Dim CurVal As String
Dim NxtVal As String
Dim DupCnt As Integer
Dim Result() As Variant
Dim i As Integer
Dim x As Integer
ReDim Result(1 To 2, 0 To 0) As Variant
List = SortAZ(List)
For i = 0 To UBound(List)
CurVal = List(i)
If i = UBound(List) Then
NxtVal = ""
Else
NxtVal = List(i + 1)
End If
If CurVal = NxtVal Then
DupCnt = DupCnt + 1
Else
DupCnt = DupCnt + 1
ReDim Preserve Result(1 To 2, 0 To x) As Variant
Result(1, x) = CurVal
Result(2, x) = DupCnt
x = x + 1
DupCnt = 0
End If
Next
Result = WorksheetFunction.Transpose(Result)
CountDuplicates = Result
End Function
Function SortAZ(MyArray() As Variant) As Variant()
Dim First As Integer
Dim Last As Integer
Dim i As Integer
Dim x As Integer
Dim Temp As String
First = LBound(MyArray)
Last = UBound(MyArray)
For i = First To Last - 1
For x = i + 1 To Last
If MyArray(i) > MyArray(x) Then
Temp = MyArray(x)
MyArray(x) = MyArray(i)
MyArray(i) = Temp
End If
Next
Next
SortAZ = MyArray
End Function
End Result:
Here is a possible solution that I have started for you. What you are asking to be done gets rather complicated. Here is what I have so far:
Option Explicit
Sub test()
Dim items() As String
Dim itemCount() As String
Dim currCell As Range
Dim currString As String
Dim inArr As Boolean
Dim arrLength As Integer
Dim iterator As Integer
Dim x As Integer
Dim fullRange As Range
Set fullRange = Range("E1:E15")
iterator = 0
For Each cell In fullRange 'cycle through the range that has the values
inArr = False
For Each currString In items 'cycle through all values in array, if
'values is found in array, then inArr is set to true
If currCell.Value = currString Then 'if the value in the cell we
'are currently checking is in the array, then set inArr to true
inArr = True
End If
Next
If inArr = False Then 'if we did not find the value in the array
arrLength = arrLength + 1
ReDim Preserve items(arrLength) 'resize the array to fit the new values
items(iterator) = currCell.Value 'add the value to the array
iterator = iterator + 1
End If
Next
'This where it gets tricky. Now that you have all unique values in the array,
'you will need to count how many times each value is in the range.
'You can either make another array to hold those values or you can
'put those counts on the sheet somewhere to store them and access them later.
'This is tough stuff! It is not easy what you need to be done.
For x = 1 To UBound(items)
Next
End Sub
All that this does so far is get unique values into the array so that you can count how many times each one is in the range.

Errror when trying to set the text of a ComboBox control

This is my code that tries to set the text of a ComboBox when I click an item in a ListView.
Private Sub ListView1_Click()
If ListView1.ListItems.Count > 0 Then
Text1.Text = ListView1.ListItems(ListView1.SelectedItem.Index).Text
Text2.Text = ListView1.ListItems(ListView1.SelectedItem.Index).ListSubItems(1).Text
Sql = "SELECT A.AID,B.LOC_NAME,C.SNAME FROM ASSET A,LOCATION B,SUPPLIER C WHERE "
Sql = Sql + "A.LOC_ID=B.LOC_ID AND A.SUP_ID=C.SUP_ID AND AID=" & Text1.Text
RS.Open Sql, CON, 1, 2
COM1
Combo1.Text = RS!LOC_NAME //combo with style - 2
COM5
Combo5.Text = RS!SNAME //combo with style - 2
End If
End Sub
Private Sub COM5()
If Combo5.ListIndex = -1 Then
For I = 0 To Combo5.ListCount - 1
Combo5.ListIndex = I
Next
End If
End Sub
Private Sub COM1()
If Combo1.ListIndex = -1 Then
For I = 0 To Combo1.ListCount - 1
Combo1.ListIndex = I
Next
End If
End Sub
However, when I click on the ListView1, I get this error:
'text' property is read only
Can anyone explain why?
For a combobox with the dropdown list style you can only select an item with .text if that item already exists, so combo1.text = "xxx" errors if "xxx" is not present in the list.
To select or add based on existence you can;
Private Sub SelectOrAddToCombo(combo As ComboBox, value As String)
Dim i As Long
With combo
For i = 0 To combo.ListCount - 1
If StrComp(.List(i), value, vbTextCompare) = 0 Then
combo.ListIndex = i
Exit Sub
End If
Next
.AddItem value
.ListIndex = .NewIndex
End With
End Sub
...
SelectOrAddToCombo Combo1, RS!LOC_NAME
SelectOrAddToCombo Combo5, RS!SNAME
It's not clear what the point of your COM5()/COM1() routines are.
For the listview, rather than click look at the
ListView1_ItemClick(ByVal Item As MSComctlLib.ListItem)
event which passes you the clicked item negating the need for ListView1.SelectedItem (which can cause errors if its Nothing).
yes, you must populate the combobox with the array(using additem value) before set the .text propierty, if the text that you want to set on the combobox does not exits in the array you get this error

How to give a name to each list item in Visual Basic 6

I am making a music player using the list control. I want to let the user change the name of the song on the list, but i want some property of THAT list item to contain its path.
Please help me in this. Any kind of help will be appreciated. Thanks in advance.
EDIT
Private Sub AddToList(ByVal txtFileName As String)
Dim I As Integer
Dim blnFileAlreadyexists As Boolean
txtFileName = Trim(txtFileName)
If txtFileName <> "" Then
blnFileAlreadyexists = False
For I = 0 To List1.ListCount - 1
If Trim(List1.List(I)) = txtFileName Then
blnFileAlreadyexists = True
End If
Next
If Not blnFileAlreadyexists Then
List1.AddItem (txtFileName)
List1.ItemData (txtFileName)
End If
End If
End Sub
For a listbox, after you add an item set its x.itemdata(x.newindex) to the index of an array (or UDT array) that contains the corresponding data.
For a listview you can similarly use an individual items .Tag or .Key to store an array (or collection) index.
Linking a listbox example;
Option Explicit
Private Type TFileData
OriginalFilePath As String
ListBoxIndex As Integer
MoreBlaBla As String
'//any more members
End Type
Private maFiles() As TFileData
Private Sub Form_Load()
'//initial alloc
ReDim maFiles(0)
AddToList "AAAA"
AddToList "BBBB"
AddToList "AAAA"
AddToList "CCCC"
'//test by looping listbox;
Dim i As Integer
For i = 0 To List1.ListCount - 1
MsgBox List1.List(i) & " - " & maFiles(List1.ItemData(i)).OriginalFilePath
Next
'// a better type centric test;
For i = 0 To UBound(maFiles) - 1
MsgBox maFiles(i).OriginalFilePath & " - List entry: " & List1.List(maFiles(i).ListBoxIndex)
Next
End Sub
Private Sub AddToList(ByVal txtFileName As String)
Dim i As Integer
Dim blnFileAlreadyexists As Boolean
txtFileName = Trim(txtFileName)
If txtFileName <> "" Then
blnFileAlreadyexists = False
For i = 0 To List1.ListCount - 1
If Trim(List1.List(i)) = txtFileName Then
blnFileAlreadyexists = True
End If
Next
If Not blnFileAlreadyexists Then
'//add to list
List1.AddItem (txtFileName)
'//store the original value in the array;
maFiles(UBound(maFiles)).OriginalFilePath = "TEST: " & txtFileName
'//store the index of the array in the list;
List1.ItemData(List1.NewIndex) = UBound(maFiles)
'//or better store in the type
maFiles(UBound(maFiles)).ListBoxIndex = List1.NewIndex
'//increment the array for the next item;
ReDim Preserve maFiles(UBound(maFiles) + 1)
End If
End If
End Sub

Resources