Show Items and related SubItems on the spreadsheet - excel

I have a vba Array of items in column 1 and items they feed in column 2.
I want to have a clean visual way to illustrate a "branching" effect on the spreadsheet but I'm at a loss on what the best method would be.
So this question is more of "What is the best method to use" kinda thing.
Just to visualize though, let's say my array looks like this:
(Col1 and Col2 separated by a space)
Array1:
PowerStrip1 TV
PowerStrip1 DVDPlayer
PowerStrip2 Soundbar
I want to have them look something like this on the excel spreadsheet:
PowerStrip1
|---> TV
|---> DVDPlayer
PowerStrip2
|---> Soundbar
Perhaps not the neatest way of showing it but you get the just. What would be the best method of achieving this look in a clean way?

Pivot Table is your friend in this. Select your data range then insert Pivot Table and arrange like below screenshot.

Unable to comment on #Harun24HR, so adding this as new answer
After creating a pivot table as mentioned by #Harun24HR, Try the following
In pivot table fields, click on the drop down available in Items field and select field setting. This will open a pop up
On subtotals & filters, select radio button besides "None"
Now go to layout & print
Have the radio button beside "show items label in outline form checked
Now and untick the check box below them
I believe this will give the desired result

Thanks guys, Harun24HR provided a perfectly good solution but I also wanted to share a different solution I came up with that displayed the information in more of a Tree-View format just in case it helps anyone else.
Lets say the Sheet name is "Summary", and the range of information to be used is A2:B200.
Assume the "Parent" information is in column "A" and the "Child" information is in column "B".
Also, you need to go to the Developer Tab -> Insert -> Active X Controls -> More Controls -> Microsoft TreeView Control, version 6.0. This is the TreeView control which will show our information.
I changed the name of the TreeView control to "tv" for simplicity.
See code below:
Sub TreeViewStuff()
'Using TreeView Nodes to populate the power sources summary
'Clear pre-existing nodes
Dim arr as variant
Dim str as string
Dim i as integer
On Error Resume Next
Sheets("Summary").tv.Nodes.Clear
'Copy range into an array
arr = Sheets("Drop Downs").Range("A2:B200")
'The first column of the array contains the parents, lets add them as keys
For i = 1 To UBound(arr)
str = ""
'Add the parent
Sheets("Summary").tv.Nodes.Add Key:=arr(i, 1), Text:=arr(i, 1)
'Expand the node
Sheets("Summary").tv.Nodes(Sheets("Summary").tv.Nodes.Count).Expanded = True
Err.Clear
Next i
'The second column will contain the kids, lets add them
For i = 1 To UBound(arr)
str = ""
'Add the kids
Sheets("Summary").tv.Nodes.Add arr(i, 1), tvwChild, arr(i, 2), arr(i, 2)
'Expand the node
Sheets("Summary").tv.Nodes(Sheets("Summary").tv.Nodes.Count).Expanded = True
Err.Clear
Next i
End Sub
The TreeView approach can give a "Dotted Line" illustration between the parent and child nodes which was something I wanted to show. Again thanks for the help!

Related

How to generate a three level dependable dropdown list

I am a complete VBA beginner and this is the first time I have had to deal with VBA. My project is simple- a user form which heavily relies on dependent drop down lists. I watched a ton of videos and wrote (more like copy-pasted) code which actually works just fine. My issue is that I need to edit part of my code to add a feature which I have trouble finding a video on (trial and error editing only took me this far).
In it's current state, my form has two dropdown lists drawing information from a sheet where data is arranged in columns as follows:
ITEM ID | ITEM | CATEGORY
The user picks a category and then the item list if filtered based on the previous selection. I now need to rearrange those columns are add another one, making it the 1st tier selection as follows:
LOCATION | CATEGORY | ITEM ID | ITEM
Just rearranging the columns alone breaks my code. On top of that I need to add the Location combobox, which would filter the Categories, which in turn filter the Items.
This is the code which handles the CATEGORY and ITEM list:
Private Sub cmbEquipCategory_Change()
Dim sh As Worksheet
Dim lastBlankRow As Long
Me.cmbEquipment.Clear
Set sh = Sheets("Equipment_List")
lastBlankRow = sh.Cells(Rows.Count, 3).End(xlUp).Row
For i = 2 To lastBlankRow
If sh.Cells(i, 3) = Me.cmbEquipCategory.value Then
Me.cmbEquipment.AddItem sh.Cells(i, 2)
End If
Next i
End Sub
It is my impression that I need to alter this code to draw data from columns 2 and 4 (it currently does so from 3 and 2) and write another almost identical block of code which handles LOCATION and CATEGORY. Any advice, resources or help would be greatly appreciated. Thanks!
The way I do this is to used named ranges. So selecting your ITEM ID would lead to one of several ITEM ranges (I name them according to the ITEM ID options) which would lead to one of several CATEGORY ranges (I name these according to the ITEM options). The more options you have the more ranges you need. Named ranges aren't broken by adding in columns.

How do I add headers to the columns of a drop down list of a combo-box? (NOT a userform)

Right now I have a combo-box that has two columns in the drop down list. The left column displays a type of a material. The right column is a description of that material. What I would like to do is add headers when I open the drop down list from the combo-box.
I'm pretty sure this is possible because within the properties of the combo-box in the data category there is a property called "columnHeads" which either has a value of "yes" or "no". I toggled this to say "yes" however I don't see any way of changing or adding values to these headers. I assume this must be done from vba, but I was curious if there is a solution to this.
(I am not using a user form by the way which seems to be where the majority of questions about this are being asked)
I have tried specifying where I would like to place my header by providing a position, but this only added the header to the first position in the drop down list not the actual header.
SUB THAT POPULATES THE COMBO-BOX
Here my code is just showing how I populate the array from the SQL database which I use to then populate the combo-Box in excel
Public Sub AFCD_Column_Data(ByVal sql_col As String, _
ByVal sql_table As String)
' ... CODE...
' ... CODE...
' ... MORE CODE!
sqlrs.Open sqlcmd
If Not sqlrs.EOF Then
arr() = sqlrs.GetRows()
End If
Dim i As Integer
Sheet1.ComboBox3.Clear
Sheet1.ComboBox3.ListWidth = 400
Sheet1.ComboBox3.ColumnHeads = True
' Sheet1.ComboBox3.Column(0,0) = "HEADER 1"
For i = 0 To UBound(arr(), 2) ' the 2 refers to the 2nd dimension
With Sheet1.ComboBox3
.AddItem arr(0, i) ' adds the item / value to the first column
.List(i, 1) = arr(0, i) + "(DESCRIPTION)" ' adds the description to the second column
End With
Next i
sqlrs.Close
sqlconxn.Close
Exit Sub
Sorry I don't have an image of my combo-box and the drop down list. I couldn't figure out how to add the image, but all I am looking for is a combo-box where the drop down list displays two headers; followed by the rest of the data which I already have displayed.
Ex:
| "MATERIAL" | "DESCRIPTION" |
--------------------------------
| Titanium | "Description" |
| ... | ... |

How to add all available value or label filters from a pivot table into a listbox? (Excel VBA)

Okay, so I have a pivot table where there is a column of provinces and other columns of sales per years.
I have created macros through vba to apply filtering on the pivot table.
(Recorded macros)
I want to add all available label and value filters into a listbox eg:
Label filters are :
Equals...
Does not equal...
Begins with...
Etc...
I want all of them in a listbox, or combobox, or anything the user can click and expand to select what filter they want.
Any help please?
jamesalainheffer#gmail.com
Okay well I seemed to have figured it out. Most people don't know about the filtering options in excel. And if they do, they probably would go about doing it in VBA by saying something like
`With
ActiveSheet.PivotTables("pvt_Data").PivotFields("Province")`
.PivotItems("Yukon").Visible = false
and so on... By just making the field or item not visible, doesn't neccessarily mean you're applying a filter to anything...
So, here's what I found...
dim prov as string
dim letter as string
dim val2 as string
dim pvtPivotTable as PivotTable
dim pfdValueField as PivotField
dim pfdTRowField as PivotField
set pvtPivotTable = ActiveSheet.PivotTables("pvt_Data")
set pfdValueField = ActiveSheet.PivotTables("Sum of Sales")
set pfdTRowField = pvtPivotTable.PivotFields("Province")
letter = TextBox4.Value
prov = TextBox1.Value
msg = ", Caption Filters, " & listbox1.value
with pvtPivotTable
.AllowMultipleFilters = True
pfdTRowField.PivotFilters.Add2 Type:=Listbox1.Value, Value1:=prove, Value2:=letter
end with
set pfdValueField = nothing
set pfdRowField = nothing
filterlistbox.AddItem(Listbox1.Text & " " & prov & msg
now what this does along with the rest of my projects is it loads every xlFilterType into 3 listboxes, per categpry of Caption filters (text), Value Filters (numerical), and date filter (date)
3 listbox's for 3 categories of filter types, each listbox is loaded with them (filter types [xlBefore, xlCaptionIsEqual]) when you select a filter type, enter a value into a textbox and push a button and it weill then apply that filter onto my pivot table.
The listbox where the filter type gets added I did like this:
.addItem("Equall...")
.list(0, 1) = "15"
What this does is add that "Equall" to the list box, the list statement just inserts 15 into the 2nd column on the 1 st index (index starts at 0, 1 is the 2nd column)
Now, the xlFilterTypes have a value as well as a name for example XlCaptionEqualls is the name and its value is 15, the listbox1.value is this value becuase i set the bound column to number 2, so the listbox pushes out the filterTypes value (number) instead of the text I hard coded, you can then use case statements to get the name from the value and insert them into another listbox.
this is a bit all over the show but I would like to know if nayone has managed to add multiple filters onto their pivot table using vba? and the add2 method?
Kick ass.

Adding several elements to a listbox menu in vba

I am trying to create a menu with list boxes in order to be able to select a number of customers from a list in an excel sheet. There are two list boxes, one with all the (default) data and one with the selected customers.
There is no problem adding one customer but when I add a second customer the graphic interface shows nothing, but after some debugging, the SelectedCustomers.RowSource still have the two rows in its data:
?SelectedCustomers.RowSource
$8:$8,$11:$11
This would have me believe there is some error with how I save the data or some limitations to Excel that I am not aware of. This is the code I use to save the data:
Private Sub CommandButton5_Click()
Dim temp As Range
For i = 0 To DefCustomers.ListCount - 1
If DefCustomers.Selected(i) = True Then
If temp Is Nothing Then
Set temp = Range(Rows(i + 4).Address)
Else
Set temp = Application.Union(temp, Range(Rows(i + 4).Address))
End If
End If
Next i
SelectedCustomers.RowSource = temp.Address
End Sub
Has someone experienced this before or know what the problem might be?
Instead of RowSource use AddItem method:
For i = 0 To DefCustomers.ListCount - 1
If DefCustomers.Selected(i) Then
SelectedCustomers.AddItem DefCustomers.Selected(i)
End If
Next i
There are known issues with ListBox.RowSource property in Excel VBA.
[EDIT]
After the discussion...
No matter of number of columns, you can copy rows from source sheet into another sheet, then bind SelectedCustomers listbox to that data

Excel 2010: Macro for hidden column groups

VBA is not my particular strength, but here we go:
I would like to trigger a macro once a group of columns is hidden or shown. How can I archive this?
The results of my previous research
The only good hint about this I could find is this discussion at MSDN. Here, a solution is using the following way is drafted:
From the root dir of the xlsx file create a file customUI\customUI.xml with the content
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" >
<commands >
<command
idMso="ColumnsHide"
onAction="ColumnHide_onAction"/>
<command
idMso="ColumnsUnhide"
onAction="ColumnUnhide_onAction"/>
</commands >
</customUI >
and add
<Relationship Id="edTAB" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml" />
to the _rels\_rels.xml. (All this probably is much easier using Visual Studio, but I have no access to such sophisticated tools in the microsoft world...) Now, the macro can be used the following way:
Public Sub ColumnHide_onAction(control As IRibbonControl, ByRef cancelDefault)
'
' Code for onAction callback. Ribbon control command
'
MsgBox "Ribbon Column Hide"
cancelDefault = False
End Sub
Public Sub ColumnUnhide_onAction(control As IRibbonControl, ByRef cancelDefault)
'
' Code for onAction callback. Ribbon control command
'
MsgBox "Ribbon Column Unhide"
cancelDefault = False
End Sub
This approach perfectly catches hiding and unhiding of columns, but not hiding and unhiding of groups. So, close, but not quite there.
Downloading the possible idMso values from here, I got notice of the GroupViewShowHide control. Using this the same way as ColumnsHide or ColumnsUnhide does not archive the desired result, though.
Any ideas?
For hiding groups of columns, I've noticed you haven't used the .Hidden property in your code example. It can be quite useful, especially if you define a group of columns in an array. For example:
For byti = 0 To UBound(cols())
If Hide Then
ActiveSheet.columns(cols(byti)).EntireColumn.Hidden = True
...and so on.
To check if a group of columns is already hidden or not, you could also use an array. Group your columns by assigning them to an array, then compare your worksheet's current status (what columns are hidden, what are not) to that array.
The code below is a suggestion for starting, and you could adapt to your project. It doesn't require the customUI.xml file you mentioned in your question.
The key parts are the MyColumnCheck variant, which is used to check if columns are hidden, and the .Match method. This is the VBA equivalent of the Match spreadsheet function.
Working on this code taught me much about how to search within arrays, and the ups and downs of using Match versus other methods - such as Find and just looping through an array! This has been discussed in several posts already, see this one for a good example. I chose to do Match rather than a For...Next loop, although it would be easy to include a For..Next loop that checks if a hidden column is in a group you assign.
If you're wondering about the IfError statement:
Application.IfError(Application.Match(MyColumnCheck.Column, MyColumnArray, 0),...
... this is because using Match in VBA code is often somewhat tricky as mentioned here. Also, as #Lori_m wrote here, "Using Application without .WorksheetFunction returns a variant which allows for arrays in arguments and results."
Also, I chose to change the values of the group array to -1 as they were checked, so when the procedure was done a little simple math would reveal if all the columns referenced by the array were hidden. A negative number is better for this check because I'm assuming you would refer to an actual column with only positive numbers.
So, to sum up, .Match can be used effectively to check if the hidden columns on a worksheet match a group of columns defined by an array.
'the column group you're looking for, dim as a dynamic array of column numbers
Dim MyColumnArray(1) As Long
'MyColumnArray(0) is column 2 or "B", MyColumnArray(1) is column 3 or "C", etc
MyColumnArray(0) = 2
MyColumnArray(1) = 3
Dim MyColumnCheck As Variant 'column check
For Each MyColumnCheck In Worksheets("Sheet1").columns
'if the column is hidden and exists in MyColumnArray array...
If columns(MyColumnCheck.Column).EntireColumn.Hidden = True And _
Application.IfError(Application.Match(MyColumnCheck.Column, MyColumnArray, 0), 0) > 0 _
Then
MyColumnArray(Application.Match(MyColumnCheck.Column, MyColumnArray, 0) - 1) = -1
'... set that element of the MyColumnArray array to -1.
End If
Next
If WorksheetFunction.Sum(MyColumnArray) = 0 - (UBound(MyColumnArray) + 1) Then
Debug.Print "group MyColumnArray is hidden"
'execute code here for when the group is hidden
Else
Debug.Print "group MyColumnArray is visible"
'execute code here for when the group is visible
End If

Resources