Grouping Sets of Rows with a toggle.button - excel

I'm attempting to hide groups of rows with a toggle button. In this instance, Rows 15 through 20, 22 through 25, 27 and finally 30 through 32.
The code I have so far works as intended.
Private Sub ToggleButton5_Click()
Dim xAddress As String
xAddress = ("15:20")
If ToggleButton5.Value Then
Application.ActiveSheet.Rows(xAddress).Hidden = True
ToggleButton5.Caption = "Show Assets"
Else
Application.ActiveSheet.Rows(xAddress).Hidden = False
ToggleButton5.Caption = "Hide Assets"
End If
End Sub
How do I add multiple groups to this row?
I tried
xAddress = ("15:20,22:25")
xAddress = "15:20,22:25"
xAddress = ("15:20 And 22:25")
and I tried individually
xAddress = ("15,16,17,18,19,20,22,23,24,25")
This last line works somewhat but runs into errors if more than maybe six row numbers are cited (going from memory on past attempts).

If you need a "toggle", then consider the implementation of a "radio-button-logic". It is either on or off, thus if it is not Hidden it should be Hidden and vice versa. Usually it is 1 line only:
Sub ToggleRowsVisibility()
With ThisWorkbook.Worksheets(1).Range("15:20,22:25")
.EntireRow.Hidden = Not .EntireRow.Hidden
End With
End Sub
In the case of the code, it can be outside the If condition:
Application.ActiveSheet.Rows(xAddress).Hidden = ToggleButton5.Value

Use Range instead of Rows.
Application.ActiveSheet.Range(xAddress).Hidden = True
If you are using Range, make sure that the row reference is in the form row:row, e.g. 1:1, 2:2, 3:3 and not 1, 2, 3.
I generally steer clear of Rows. For example,
Debug.Print Rows("1,2,3").Address
returns
$123:$123
Not what you expect, right?

Requirements:
To hide/unhide a multiple selection (i.e. non-contiguous or multiple areas) of rows by the click of a button.
Target rows: [15:20], [22:25], [27] and [30:32] (row 27 included to show a mixed of rows combination).
Non VBA Solution:
This can be achieved without VBA. Use the Range.Group method (Excel) manually to group the rows. Unfortunately, this method cannot be applied at once to a multiple selection, so you’ll have to apply the method to each range of contiguous rows separately.
Select the first range of rows to be grouped (i.e. [15:20])
In the Excel menu, click the [Data] tab then in the [Outline] group, click the [Group] option in the [Group] dropdown menu.
The rows selected are now grouped with a button beside the rows heading. Use this button to toggle the visibility of the respective grouped rows.
Repeat the action for the remaining group of rows.
The advantages of this method compared with the VBA method are:
The grouped rows are fixed, even if new rows are added or deleted. With the VBA method the rows are “hard-coded” and will lose focus when rows are inserted\deleted.
The visibility of the Group of rows can be toggle all at once using the buttons located at the top\left angle, i.e. 1 to hide and 2 to unhide.
The visibility of the Group of rows can be toggle independently from each other using each group's button located in the rows heading. Vba would required either independent buttons or additional variables.
VBA Solution:
If you must use VBA then I suggest to use the correct syntax for multiple selection:
For a single row use: Rows(15).Select or Range("15:15").Select
For a range of contiguous rows use: .Rows("15:20").Select or Range("15:20").Select
For multiple selection of rows use the Range method as the Rows method doesn't work with multiple areas and when applied to a multiple selection returns only the rows of the first area.
For multiple selection of single rows use: .Range("30:30,32:32,34:34,36:36,39:39").Select
For multiple selection of non-contiguous rows use: .Range("15:20,22:25,27:27").Select
Proposed VBA Solution:
Following the above your code should be:
Private Sub ToggleButton5_Click()
Dim xAddress As String
xAddress = "15:20,22:25,27:27,30:32" 'Update as required
With ToggleButton1
Me.Range(xAddress).Rows.Hidden = .Value
.Caption = IIf(.Value, "Show Assets", "Hide Assets")
End With
End Sub

Related

When I add a row in Excel to copy the previous row's formatting, can I also copy the form control checkboxes?

I have a table with checkboxes in certain columns (see sample table)-- they are linked to their cells and also move/size with the cells. I also added text box "headings" throughout the table so visually when you filter for checked boxes, you see under which heading the checked item is in (I know I could create a separate column for that, but it works if I add text to the cells underneath the heading that I keep checked when filtering).
I want to be able to add rows at the end of each section, or before the next heading, since the formatting changes slightly in each section. However, I also want to add the checkboxes, and my code currently doesn't do that. It's okay if they're not linked to the new cell-- I have another macro I can run to do that.
Here's what my code would look like in the sample table:
Sub Add_Row_Pepperoni()
Rows(7).Insert , xlFormatFromLeftOrAbove
End Sub
Sub Add_Row_Pineapple()
Rows(13).Insert , xlFormatFromLeftOrAbove
End Sub
And I would like to add "Next" to "Call" this code:
Sub Link_CheckBoxes()
Dim chk As CheckBox
Dim lCol As Long
lCol = 0 'number of columns to the right for link
For Each chk In ActiveSheet.CheckBoxes
With chk
.LinkedCell = _
.TopLeftCell.Offset(0, lCol).Address
End With
Next chk
End Sub
My other concern is the row I'm referencing (here rows 7 and 13) will change every time I add a row above it (I'll no longer be referencing the "header" row). Any tips?

How can a compare a cell with the previous visible cell above

I am trying to shade every other group of visiable cells.
Each row of my data contains information on a given Order and there can be multiple rows for each order, e.g. Order 1 many have 3 rows while order 2 may have 1 row, etc. The data is sorted by Order Number so all rows for a given order are contiguous.
I have shaded each group vis a helper column (AS) containing the following formula: =IF(ROW()=2,TRUE,IF(A2=A1,AS1,NOT(AS1)))
which results in every other Order group being either TRUE or False. Then I use conditional formatting to shade every "TRUE" row.
This works until I begin filtering my data and then I can end up with either two shaded or to unshaded groups next to each other.
I think what I'm looking for is a VBA function that will compare a cell with previous VISIBLE cell and will return TRUE or FALSE if the match or not.
Any help will be much appreciated.
you can use this code that shades every other row
Sub ShadeThem()
Dim okShade As Boolean
Dim r As Range
For Each r In Range("A1", Cells(Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeVisible)
If okShade Then
r.EntireRow.Interior.Color = vbRed
okShade = False
Else
okShade = True
End If
Next
End Sub
I assumed your filtered data affect column A from row 1 downwards
Did they not, just change "A1" and Cells(Rows.Count, "A") to affect the needed column
In order to have it run at every new filtering, you could:
add a helper cell which counts the number of visible rows
=SUBTOTAL(103;A1:A1000)
this will trigger the Worksheet_Calculate event at every filtering
add the Worksheet_Calculate event hander in the relevant sheet code pane
Private Sub Worksheet_Calculate()
ShadeThem
End Sub
As I said in the comments, there's almost surely a better way to do what you're trying as a whole with your spreadsheet (a table!). However, if you really wanted a VBA custom formula to test if a cell is hidden or not you could use this...
Function isHiddenRow(aRange As Range) As Boolean
isHiddenRow = aRange.EntireRow.Hidden
End Function
There's some possibilities this formula assumes:
Only one cell.
Filtering impact of recalculations.

How to display SUM of visible cells in a userform label?

I would like to display the SUM of visible cells from column D in a Userform Label, and have it update automatically as the spreadsheet gets filtered.
I have this code
Private Sub SUM_click()
Me.SUM.caption = range ("AA2")
End Sub
This is problematic.
I use a SUM formula in cell AA2.
I’d like to avoid using formulas in any cells, if possible.
The return value isn’t excluding rows which are hidden.
It displays the value after I click on the label.
I want it to display automatically.
Automate display of SubTotals in UserForm
This reveals being not as trivial as it may seem.
Of course you might profit from a sheet's Worksheet_Calculate event
to get subtotals (of visible cells) by means of VBA whenever the (enabled) calculation processes a new result.
This is effective when filtering and/or when changing values, whereas the Worksheet_Change event wouldn't cover filtering.
Private Sub Worksheet_Calculate()
Dim subtotal As Double
subtotal = Sheet1.Evaluate("=Subtotal(109,D:D)") ' argument 109 sums up only visible cells!
Debug.Print "Subtotal: " & Format(subtotal, "0.00") ' display in VB Editor's immediate window
End Sub
... but there's no synchronized event to refresh a label in the Userform's code.
So I suggest the following tricky workaround profiting from the ListBox property RowSource:
add the subtotal formula =SUBTOTAL(109,D:D) to cell AA2
instead of a label ... let a listbox do the display binding it to a .RowSource; whenever a subtotal gets changed this will be reflected in the only list value of the bound listbox.
Defining the appearance via .SpecialEffect = fmSpecialEffectFlat makes the Listbox appear nearly like a label. Small beauty mistake: the background color can't be modified
UserForm code example
Private Sub UserForm_Initialize()
With Me.ListBox1 ' << rename control to any other name
.ColumnCount = 1 ' define columncount
.ColumnWidths = .Width - 8 ' play around with small sizes to avoid scroll bars
.Height = 12
.RowSource = "Sheet1!AA2" ' reference to cell containing subtotal formula
.SpecialEffect = fmSpecialEffectFlat
.ListIndex = 0 ' activate first (and only) record
End With
Tip
To enable concurrent actions like editing or filtering in the table, you need to show the UserForm modeless, e.g. via
With New UserForm1
.Show vbModeless
End With
Alternative suggested in comment
Thx to #norie's hint, it would also be possible to profit from a textbox'es .ControlSource property (having more ressemblance to a label) without the need of further cosmetics. Nevertheless this promising approach needs further (or even more complicated?) steps: a textbox allows inputs which would overwrite the initial formula in the referred cell which isn't wanted.
Possible ways out I won't develop here: prevent key-event entries (have a look into other SO posts) or use the TextBox1_Change event to rewrite the formula each time the textbox got changed (doubtful), place a blocking control over the textbox etc.

Select multiple values from a slicer

I have a pivot table with a slicer. The slicer has 50+ values in it and these values can change. I use the slicer to filter the data - I am always looking for the same 5 values, and my 5 values start with the same text string.
I had recorded a macro to select my 5 values. this macro selects the items that are true and then lists all the other values and sets selection as false.
When new values are added the macro crashes because I don't have an explicit line of code to set the selection of the new value to false.
I found code to select one value from the slicer and deselect all other values without having to list them all explicitly, but I can't find code to find the 5 values and deselect all other values without having to list them explicitly, or
a way to modify this code to select all slicer items that "contains" the consistent text string. either would help...
this is the code I have to find one specific value, but deselect the rest without stating them explicitly:
For Each slcCache In ActiveWorkbook.SlicerCaches
slcCache.ClearManualFilter
Next
With ActiveWorkbook.SlicerCaches("Slicer_Fruit")
For Each oSlicerItem In .SlicerItems
If oSlicerItem.Name = "abcx Apple" Then
oSlicerItem.Selected = True
Else
oSlicerItem.Selected = False
End If
Next oSlicerItem
End With
How can I change the code to select the slicer items that starts with "abcx" or contains this text?
or is there a way to select "abcx Apple" and "abcx Pear" and "abcx Banana" but not select any other values?
Try this :
Sub Slicer_select()
ActiveWorkbook.SlicerCaches("Slicer_Fruit").ClearManualFilter
Dim Sl_I As SlicerItem
For Each Sl_I In ActiveWorkbook.SlicerCaches("Slicer_Fruit").SlicerItems
If Not Sl_I.Value Like "abcx*" Then Sl_I.Selected = False
Next
End Sub

Receipt printing - how to not show zero value rows

I am setting up a receipt printout from Excel 2010. I have multiple items on the worksheet and can print everything ok.
The receipt is to be printed in a busy environment and as such we just want the operators to enter the numbers and press CTRL+P.
Not all the items on the receipt will be used:
Item 1 10:00
Item 2 0.00 <--- This is an example of the row I do not want to print
Item 3 10.00
Total 20.00
The number of items could increase over time so the solution must be able to include the entire print range. Use of the hide function is not an option as it takes to long.
The solution must require no action by the user as they are not 'computer people'.
All cells are locked except those which require data to be entered to minimise input errors. i.e. VAT calculations
I had tried a VB routine but with no luck, hence the question.
EDIT: The VB I had written was-
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Dim RngCol As Range
Dim i As Range
Set RngCol = Range("B1", Range("B" & Rows.Count). _
End(xlUp).Address)
For Each i In RngCol
If i.Value = 0 Then
i.EntireRow.Hidden = True
End If
Next i End Sub
I have tried Jeeped's suggestion but some how the page size has now changed - won't change back either?
Although Jeeped's suggestion has done what I wanted it is now ignoring the header which is needed although I can move the info to the main sheet.
Use a conditional format rule. I always use rules based on formulas like =NOT($D1) to cover columns A:E depending on the value in column D but any of the others will do if you can determine criteria that equals zero. When you decide on how you want to handle the criteria, click Format and go to the Number tab. Choose Custom from the list down teh left and use ;;; (three semi-colons) for the Type:.
Click OK to accept the format and then OK to create the rule. Nothing in A:E will be visible if there is a blank or 0 in column D.
Alternate AutoFilter Method:
The individual worksheets do not have any standard events to do with printing but the workbook has a BeforePrint Event.
Go the workbook's VBE and locate ThisWorkbook in the Project Explorer then double-click it. Paste the following into the new pane on the right titled something like ThisWorkbook (Code).
Option Explicit
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Cancel = False
With Worksheets("Sheet2")
If .AutoFilterMode Then .AutoFilterMode = False
With .Range(.Cells(1, 2), .Cells(Rows.Count, 2).End(xlUp))
.AutoFilter Field:=1, VisibleDropDown:=False, _
Criteria1:="<>0.00", Operator:=xlAnd, Criteria2:="<>"
End With
End With
End Sub
Edit to suit the actual column that holds the numbers. I've used column B. Note that the AutoFilter requires a header row.
Tap Alt+Q to return to your worksheet. Any method of printing the page will result in the AutoFilter Method being applied to column B and hiding any blanks or zeroes (in the form of 0.00) in that column.
Before:        
After:    
As you can see from the sample images, printing to a .PDF filters the code column. I've also chosen not to display the little drop-down arrow normally associated with an AutoFilter.
You can unhide the rows with conventional unhide commands, clear the filter or just turn the autofilter off to get the rows back.
This latter method is a bit more involved but it gets rid of (aka hides or filters out) the undesired rows rather than simply not displaying the text in them. If need be, the worksheet could be unprotected for the duration of the print cycle.

Resources