VBA, count the visible rows in a table? - excel

I have tried the following,
ActiveSheet.UsedRange.SpecialCells(xlCellTypeVisible).Rows.Count
However this always returns 1, I suspect is it because the data is within a table? Thanks

If your data is in a table, use a ListObject object:
ListObject object
(Excel)
Then count visible cells only in a single column of the data range:
Something like this should work:
Dim Mytable As ListObject
Set Mytable = ActiveSheet.ListObjects("Table1")
Debug.Print Mytable.DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
Set Mytable = Nothing
If your data is not a table object but just a range of cells then do:
Range("A1").CurrentRegion.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1
ReplaceRange("A1") with a cell of your header row. And because this count will add also the header row itself, we must do -1 at the result of the count

Related

VBA Updating Table Headers from a List

I have a Table containing a list of Names.
I would like to update a secondary table to have headers that correspond to this list of names (starting from column 2).
Example if my original List contained a,b,c. I would like my secondary table to have column headers of "blank",a,b,c
With Range("Original Table[Names]")
Range("Secondary Table").HeaderRowRange.Value = .Value
End With
The above gives me errors, however, i can't seem to figure out how to solve this
Use Transpose, and Resize.
With Range("Original Table[Names]")
Range("Secondary Table").HeaderRowRange.Cells(2).Resize(,.Rows.Count).Value = Application.Transpose(.Value)
End With
Perhaps a personal preference, but I'd work with ListObjects here:
Dim origTable As ListObject
Set origTable = ThisWorkbook.Worksheets("insertname").ListObjects("Original Table")
Dim secTable As ListObject
Set secTable = ThisWorkbook.Worksheets("insertname").ListObjects("Secondary Table")
With origTable.ListColumns("Names").DataBodyRange
secTable.HeaderRowRange.Cells(2).Resize(,.Rows.Count).Value = Application.Transpose(.Value)
End With
Also, note that a column header can't be blank in a table.

can't get value from .range.value

Im pulling data from 2 tables, one works as i expected. but the other one, same code, wont work. I just dont get it. Everything seems to be identical.
I've isolated the "find" and they return the correct line numbers on both tables.
The problem is that the loCustomerTable doesnt seem to have anything in the .value
Debug.print does a line feed, thats it.
no errors generated.
Why? What am I missing?
Dim rProjectInfo As range
Dim rCustomerInfo As range
Dim loCustomerTable As ListObject
Dim loProjectTable As ListObject
Set loProjectTable = Worksheets("projektinformation").ListObjects("tblProjektinformation")
Set loCustomerTable = Worksheets("kundinfo").ListObjects("tblKundInformation")
sProjectNumber = "20-130"
' read project information
Set rProjectInfo = loProjectTable.range.rows((loProjectTable.range.Columns(1).Find(sProjectNumber).row))
' get customer info base off project info.
Set rCustomerInfo = loCustomerTable.range.rows((loCustomerTable.range.Columns(2).Find("gateau").row))
Debug.Print rProjectInfo.Cells(, 1).Value
Debug.Print rCustomerInfo.Cells(, 2).Value
I guess you are a victim of your monster statements (I don't get it why such statements are not split into smaller pieces so that you can easily debug it).
So let us split the statement
Set rCustomerInfo = _
loCustomerTable.range.rows((loCustomerTable.range.Columns(2).Find("gateau").row))
First thing you do is fetch the table column
dim tabCol as Range
set tabCol = loCustomerTable.range.Columns(2)
Debug.Print tabCol.Address
Check if the address is correct (should by). Now you search for your string ("gateau") in that column
dim rGateau as Range, row as long
set rGateau = tabCol.Find("gateau")
row = rGateau.Row
Debug.Print rGateau.Address, rGateau.Value2, row
That gives you the address of the cell with the search string (code assumes that this string can always be found), and its row number.
Now what you will see it that the row number is the row within the sheet, not within the table (listObject) - but you use it as row number within your table. If the table does not start at row 1, you are now reading data from the wrong row (which might even be below the table).
What you can do it either consider the start of your table or intersect the table with the row where you found the name.
' Variant 1: Calculate the row number within the table
row = rGateau.Row - loCustomerTable.Range.Row + 1
Set rCustomerInfo = loCustomerTable.Range.Rows(row)
' Variant 2: Intersect the (sheet) row with the table
row = rGateau.Row
Set rCustomerInfo = Intersect(loCustomerTable.Parent.Rows(row), loCustomerTable.Range)
Debug.Print rCustomerInfo.address

How to use Offset and End.(xlDown) to Select data to graph

I am trying to create a Stacked Column Chart with the data in the table below.
I want to Select column A1:A9 and C1:F9. The Selection also needs to be adaptive to different column sizes (i.e, someone adds another Feature). The macro should also work for a table of data, anywhere in the Sheet. As long as the macro originates from the ActiveCell.
How do I not only Select until the column end, but also Select excluding the "Values" column. I am trying to use End and Offset, but I am not sure the best way to do it. And once again, I want to use it on a table that is anywhere in the sheet and then create a Stacked Column Chart from it.
Thanks for your help!
Try this code please. The idea is that you iteratively Union various ranges of the data based on the condition that the header is not 'Values'.
The working assumption is that the CurrentRegion of the ActiveCell will select your table data. Where the definition of CurrentRegion is 'The current region is a range bounded by any combination of blank rows and blank columns. ' - MSDN link
Then the code will append the first column to an output range. After that, the outer columns will only be appended to the output range if the header is not 'Values'.
Dim rngData As Range
Dim intCounter As Integer
Dim rngToSelect As Range
Set rngData = ActiveCell.CurrentRegion
Set rngToSelect = Range(rngData.Cells(1, 1), rngData.Cells(rngData.Rows.Count, 1))
For intCounter = 1 To rngData.Columns.Count
If rngData.Cells(1, intCounter).Value <> "Values" Then
Set rngToSelect = Union(rngToSelect, Range(rngData.Cells(1, intCounter), rngData.Cells(rngData.Rows.Count, intCounter)))
End If
Next intCounter
rngToSelect.Select

Sort a ListObject by Columns

I am working with ListObject objects in VBA. In particular I am creating a table dynamically (variable number of rows and columns, and variable column headers). I have the need to sort the table's columns in ascending alphabetical order.
For instance if I have the table:
I want it to be sorted like so,
Is there any way to do this? I have tried to use the Range.Sort method but it seems that this is not allowed if the range is part of a ListObject.
I also tried to record a macro to find code, but found that when I right clicked the table to sort it, the selected range left the header out and I was not able to select the "Sort left to right" option...
Any ideas?
This seems to work. It takes the name of a table (e.g. "Table1"), converts it to a range, sorts it, then reconverts it to a table with the same name:
Sub SortByCol(tableName As String)
Dim sh As Worksheet
Dim myTable As ListObject
Dim myStyle As TableStyle
Dim myRange As Range
Set sh = ActiveSheet
Set myTable = sh.ListObjects(tableName)
Set myStyle = myTable.TableStyle
Set myRange = myTable.Range
myTable.Unlist
On Error Resume Next
myRange.Sort key1:=myRange.Rows(1), Orientation:=xlSortRows
If Err.Number > 0 Then Debug.Print "Range couldn't be sorted"
On Error GoTo 0
sh.ListObjects.Add(xlSrcRange, myRange, , xlYes).Name = tableName
sh.ListObjects(tableName).TableStyle = myStyle
End Sub
On edit: I added a bit of error handling around the sort method call. Experiments showed that my original code didn't preserve the style (if the table didn't have the default style then the result was a weird blend of the default style and the original table style). I added coded to save and then restore the original table style, but I don't know much about table formatting and might have missed some subtleties. At the very least, it seems to preserve the style if it was chosen from Excel's built-in list of table styles.

ListObject Table Row Count

I have an excel table with one header row and one data body row. I want to count the data body rows. When I'm trying to check how many rows my table has with
Set myWorkSheet= ActiveWorkbook.Worksheets("Sheet1")
Set myTable= myWorkSheet.ListObjects("Table1")
countrows = myTable.ListRows.Count
countrows contains 0. If the has 2 or more rows, it gives the right row number. Why does it say 0 for one row ans is it the best way to count the rows or are there better ones?
EDIT:
Found out whats causing the problem. I use this lines to clear the table before i fill it again:
If tblChart.ListRows.Count >= 1 Then
myTable.DataBodyRange.Delete
End If
After that operation the table looks like I described it. Without it and modifying the table to look like I described the table it worked. But why is it causing this problem?
The ListObject property you are looking for is the .DataBodyRange.
Dim myWorkSheet As Worksheet, myTable As ListObject, countRows As Long
Set myWorkSheet = ActiveWorkbook.Worksheets("Sheet1")
Set myTable = myWorkSheet.ListObjects("Table1")
countRows = myTable.DataBodyRange.Rows.Count
Debug.Print countRows
A comprehensive list of the ListObject properties is available at: ListObject Interface.
Responding late in-case Google search brings user here:
I found this problem as well. DataBodyRange object does not exist unless there are two rows of data. Not just two empty rows, but two rows of data in at least one column.
What I have found to work reliably is to test if DataBodyRange exists:
If Not TableListObject.DataBodyRange is Nothing Then
Debug.Print "Data Rows Count=", TableListObject.DataBodyRange.Rows.Count
Else
Debug.Print "No Data in Table detected"
End if

Resources