VBA Expand/Collapse rows - vba

I have a report in which I am asking the users to click buttons to reveal where they need to add their commentary. I have it working but wanted to put in an If statement in case they have already expanded the row.
I have two macros, the first relates to the button they push and sends to the main macro the name of the button and a row number which is part of the section that is either expanded or collapsed
Sub ROccupancy()
'
Dim RecName As String
RecName = "ROccupancy"
Dim RowNum As Integer
RowNum = 27
Call ToogleRec(RecName, RowNum)
End Sub
The next macro is where I am having the trouble
Sub ToogleRec(RecName, RowNum)
'
Dim Toogle As String
Dim MyObj As Object
Set MyObj = ActiveSheet.Shapes.Range(Array(RecName))
Toogle = Left(MyObj.TextFrame2.TextRange.Characters.Text, 4)
TextName = Mid(MyObj.TextFrame2.TextRange.Characters.Text, 5, 100)
If Toogle = "Show" Then
MyObj.ShapeStyle = msoShapeStylePreset9
MyObj.TextFrame2.TextRange.Characters.Text = _
"Hide" & TextName
MsgBox Rows(RowNum).ShowDetail
If Rows(RowNum).ShowDetail = False Then
Rows(RowNum).ShowDetail = True
End If
Else
MyObj.ShapeStyle = msoShapeStylePreset11
MyObj.TextFrame2.TextRange.Characters.Text = _
"Show" & TextName
MsgBox Rows(RowNum).ShowDetail
If Rows(RowNum).ShowDetail = True Then
Rows(RowNum).ShowDetail = False
End If
End If
Range("C" & RowNum).Select
End Sub
The issue is the Rows(RowNum).ShowDetail is always TRUE, no matter if it's expanded or collapsed. I can remove the If section and set it to TRUE or FALSE using "Rows(RowNum).ShowDetail = False" or "Rows(RowNum).ShowDetail = TRUE". However, if the user has manually expanded or collapsed the row it causes an error (which freaks them out)
This question and answer seemed promising but Rows(RowNum).ShowDetail always seems to be TRUE
I put the MsgBox in there for error checking. I'll remove it in the final version.

Have you tried using Hidden property? Something like:
With Sheet1.Rows(5)
.ShowDetail = .Hidden
End With
Take note though that for you to use .ShowDetail method, you'll need to Group the rows first (needs to be in outline form).
True if the outline is expanded for the specified range (so that the detail of the column or row is visible). The specified range must be a single summary column or row in an outline.
Above code toggles hiding/unhiding a grouped row 5. You don't even need an If statement for the toggling. HTH.

Related

Repeating legacy option buttons within a repeating section

I am currently attempting to turn a form I am working on into a more dynamic one using vba in word, but I am facing two issues with the option buttons within a repeating section:
The code is not dynamic; when I run the code it does what I need it to but doesn't dynamically recalculate as I change my choice.
The option buttons do not repeat when I add a new section, and the only way for me to include them is by readding them and creating a new module specific for the new option button group.
Below is a picture of the section I am repeating and the code I am using.
enter image description here
Private Sub Yes_Click()
Dim k(0 To 3) As String
k(0) = "Select one"
k(1) = "Pass"
k(2) = "Fail"
k(3) = "N/A"
Dim i As Long
If Yes = True Then
Me.Controls.Clear
Me.Controls1.Clear
For i = 0 To 3
Me.Controls.AddItem k(i)
Me.Controls1.AddItem k(i)
Next i
End If
On Error Resume Next
Me.Controls = "Select one"
Me.Controls1 = "Select one"
If Yes = False Then
Me.Controls = "N/A"
Me.Controls1 = "N/A"
End If
On Error Resume Next
End Sub
Is there a way to approach either issues?
Thanks in advance.

Assign a different macro per click of VBA Button

I have an excel button that hides columns "S-U" when I click it. I want to click the button a 2nd time and it hides columns "P-R" and etc. Can you manipulate an excel button per click?
If there are just a few things you want it to do (it sounds like it), I would have my macro evaluate the current state and act accordingly.
In your example, you indicate that you first want it to hide S-U, then P-R on a second click. This will do that:
Sub HideColumns()
If Sheets("Sheet1").Range("S:S").EntireColumn.Hidden = False Then
Sheets("Sheet1").Range("S:U").EntireColumn.Hidden = True
Else
Sheets("Sheet1").Range("P:R").EntireColumn.Hidden = True
End If
End Sub
Of course, you can extend this with additional conditions and actions.. like changing the text of the button to represent what it will do next:
Assume you have it labeled "Hide Rows S:U" to start, you can change it inside VBA to indicate what it would do on the next click:
Sub HideColumnsUpdateText()
If Sheets("Sheet1").Range("S:S").EntireColumn.Hidden = False Then
Sheets("Sheet1").Range("S:U").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows P:R"
Else
Sheets("Sheet1").Range("P:R").EntireColumn.Hidden = True
End If
End Sub
There's really no end to what you can do once you start evaluating the current state (extend using ElseIf, or even use Case). You just have to keep the logic straight.
Edit to further expand:
If your situation is linear - that is, if want to hide more and more columns in the same order, you just need to do else ifs to evaluate the situation, and step through the order that you want to hide them.
Personal note: I find that "IF whatever =true" statements are a little easier to follow than "if whatever = false" (and technically, you don't even have to have type the "=True"). But it means you need to start at the last possibility, and work backwards. Otherwise you need to evaluate by "= False" (like I first demonstrated), but I find it a little harder to follow. Your results may vary.
You indicated that you want these hidden in order: "S:U","P:R","M:O","J:L","G:I" . Here is a script that, once all of those rows are hidden, the button would then show them all. So I start by evaluating if the last possibility is true -that is- are Rows G:I hidden already? If so, then show them all. I've also included updating the button text, but that's optional.
Sub hideSetsOfColumnsProgressively()
' progressive order of button function: "S:U","P:R","M:O","J:L","G:I","Unhide Rows"
If Sheets("Sheet1").Range("G:I").EntireColumn.Hidden = True Then
Sheets("Sheet1").Range("G:U").EntireColumn.Hidden = False 'shows all rows
'optionally change the text of the button to indicate the next function:
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows S:U"
ElseIf Sheets("Sheet1").Range("J:L").EntireColumn.Hidden = True Then
'then we've already hidden all of the other columns, so do the last set
Sheets("Sheet1").Range("G:I").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Unhide Rows"
ElseIf Sheets("Sheet1").Range("M:O").EntireColumn.Hidden = True Then
Sheets("Sheet1").Range("J:L").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows G:I"
ElseIf Sheets("Sheet1").Range("P:R").EntireColumn.Hidden = True Then
Sheets("Sheet1").Range("M:O").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows J:L"
ElseIf Sheets("Sheet1").Range("S:U").EntireColumn.Hidden = True Then
Sheets("Sheet1").Range("P:R").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows M:O"
Else
Sheets("Sheet1").Range("S:U").EntireColumn.Hidden = True
Sheets("Sheet1").Buttons("Button 1").Text = "Hide Rows P:R"
End If
End Sub
The nice part about this script is that it loops. You can just keep clicking it and it will hide progressively more and more rows, then show them all.
I hope this answers your question. Keep in mind that the logic has to be solid, or you'll get unexpected results.
One solution to this problem is be declaring a global variable, and assigning a counter to it:
Private i As Integer
Sub Button1_Click()
If i = 0 Then
Do Stuff 'This is the first click
i = i + 1
Else
Do Stuff the Second Time 'This is the second time and beyond.
i = i + 1
End If
End Sub
i will automatically be assigned a value of 0. The first time it checks i = 0 it will operate however you want the first time. Once it sets i = i + 1 then it will do whatever else you want it to do for the second time. If you want to make it a third time, you can always do Else If i = 1 Then, etc.
Under the Visual Basic Editor, create a new module if you don't already have one and place this in there. Create a button and assign the Button1_Click Macro to the Button.
If you only need to alternate between two options, e.g. like a toggle on off, then use a boolean:
Public x As Boolean
Private Sub CommandButton1_Click()
If x Then MsgBox ("ON") Else MsgBox ("OFF")
x = Not x
End Sub

Sub or function not defined: Buttons()

I had this sub in another spreadsheet where I could click a button to collapse and expand certain columns. I copied it into a new spreadsheet to use to collapse some rows but now I get the error "Sub or function not defined". It highlights Buttons
Sub HideDetails()
Range("3:8").Select
If Selection.EntireColumn.Hidden Then
Selection.EntireColumn.Hidden = False
Buttons("btnToggleDetails").Caption = "-"
Else
Selection.EntireColumn.Hidden = True
Buttons("btnToggleDetails").Caption = "+"
Range("A1").Select
Application.CutCopyMode = False
End If
Range("A1").Select
Application.CutCopyMode = False
End Sub
There are no other scripts in this workbook. This one was originally in Module1 but I tried moving it to a new module.
Edit: I changed the button name in the code but not the screenshot. Both references are to btnToggleDetails now but it still throws the same error.
It's telling you that the identifier Buttons() can't be found in the current scope. If Buttons() is something that you've declared somewhere else, you either need to make it public or you need to fully qualify the object that contains the Buttons() object, for example:
Sheet1.Buttons("btnToggleDetails").Caption = "+"
Had to add my answer as was sure I could shorten the lines of code:
If you consider that Selection.EntireColumn.Hidden returns TRUE/FALSE or 0/-1.
CHR(45) is a minus sign.
CHR(43) is a plus sign.
ABS turns -1 into 1.
So:
If TRUE (0) then 45-(0*2) = 45
If FALSE (-1) then 45-(1*2) = 43
This will swap the columns from hidden to visible and vice-versa and display the correct button caption in the immediate window:
Sub HideShowColumns()
Selection.EntireColumn.Hidden = Not (Selection.EntireColumn.Hidden)
Debug.Print Chr(45 - (Abs(CLng(Selection.EntireColumn.Hidden)) * 2))
End Sub
This should work in your procedure:
Sub HideDetails()
Dim rng As Range
Set rng = ActiveSheet.Range("3:8")
rng.EntireColumn.Hidden = Not (rng.EntireColumn.Hidden)
Buttons("btnToggleDetails").Caption = Chr(45 - (Abs(CLng(rng.EntireColumn.Hidden)) * 2))
End Sub

VBA Excel Toggle Button: With 10 rows, how do I unhide each row separately and not in a group?

I'm working in VBA and Excel 2007 with active control toggle button, which I'm trying to figure out how to get to function the way I need it to. Will someone please help me out?
This works for only unhiding a single row at a time for two hidden rows:
Private Sub ToggleButton1_Click()
If ToggleButton1 Then
Rows(76).EntireRow.Hidden = False
Else
Rows(77).EntireRow.Hidden = False
End If
End Sub
This does not work for only unhiding a single row at a time for more than two hidden rows:
Private Sub ToggleButton1_Click()
If ToggleButton1 Then
Rows(76).EntireRow.Hidden = False
Else
Rows(77).EntireRow.Hidden = False
Else
Rows(78).EntireRow.Hidden = False
End If
End Sub
What do I need to do to get this to work? This is all I need the toggle button to do. Each row has identical information (text fields, field names, etc.), but I need each row to only become visible upon clicking just one toggle button. I know multiple toggle buttons will works like a breeze, but I really am wanting to just use one toggle button to unhide each row, one at a time. By default, the rows will be hidden first, too.
You can use a counter and then count down and you should be able to do what you are looking for. In this example if the counter is 0 we hide the rows 1-3 and then show each row untill we are back to 0 and then hide them again when we click the button.
Dim counter As Integer
Private Sub ToggleButton1_Click()
If counter = 0 Then
Rows(1).EntireRow.Hidden = True
Rows(2).EntireRow.Hidden = True
Rows(3).EntireRow.Hidden = True
counter = 3
Else
Rows(counter).EntireRow.Hidden = False
counter = counter - 1
End If
End Sub
Hope it helps
//KH
Try this:
Private Sub ToggleButton1_Click()
Dim rng As Range
Dim myrow As Range
Set rng = Me.Rows("75:85")
If Me.ToggleButton1 Then
For Each myrow In rng
If Not myrow.Hidden Then
myrow.Hidden = True
If myrow.row = 85 Then
myrow.Offset(-10, 0).Hidden = False
Else
myrow.Offset(1, 0).Hidden = False
End If
Exit For
End If
Next
End If
End Sub
This hides and unhides Rows76-85 simultaneously.
You start with all 10 Rows hidden.
After 1st click, Row 76 will appear and so on.
All will be hidden again after Row 85 was shown.
I used 10 rows based on your question title, adjust it to suit your needs.
Edit1:
Private Sub ToggleButton1_Click()
Dim rng As Range
Dim myrow As Range
Set rng = Me.Rows("76:85")
If Me.ToggleButton1 Then
For Each myrow In rng
If myrow.Hidden Then
myrow.Hidden = False
Exit Sub
End If
Next
rng.Hidden = True
End If
End Sub
Above will work as you want it.
Although you already accepted an answer, I still would want to correct my code.
At least for you and others reference.

Deselect all items in a pivot table using vba

Can some quicly explain the way to deselect all items in a newly created pivot table so that I can go back and select only one or two items? I tried the following:
.PivotItems("(Select All)").Visible = False
Thanks.
This is probably the closest you can get to what you want:
Dim i As Long
.PivotItems(1).Visible = True
For i = 2 To .PivotItems.Count
.PivotItems(i).Visible = False
Next
This will make the very first option the only selected option (assuming this is within a with that points to the pivotfield). If you know what you want before hand... modify accordingly.
I've found that looping through each data item takes a lot of time, what you can do if you want to filter on a single item in a pivot without looping through all items is use the following code:
ActiveSheet.PivotTables("Your Pivot Name").PivotFields("Your Field Name").ClearAllFilters
ActiveSheet.PivotTables("Your Pivot Name").PivotFields("Your Field Name").PivotFilters.Add _
Type:=xlCaptionEquals, Value1:="Your string here"
this is basically a label filter but it worked for me.
Check the following out. Select data for specific field name. Please do note that you have to at least select one item by default. And also do not forget that if you want to hide items, Only contiguous items in a PivotTable Field can be hidden. Perhaps at page load, or worksheet open or any of your other sub trigger, you could select a particular items to be selected based on a specific field. Then allow your code to proceed with anything else.
Sub specificItemsField()
Dim pf As PivotField
Dim pi As PivotItem
Dim strPVField As String
strPVField = "Field Name"
Set pt = ActiveSheet.PivotTables(1)
Set pf = pt.PivotFields(strPVField)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
On Error Resume Next
pf.AutoSort xlManual, pf.SourceName
For Each pi In pf.PivotItems
pi.Visible = True
Next pi
pf.AutoSort xlAscending, pf.SourceName
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
This is how I do for custom filter selection. May be slower due to double looping.
Dim toSelect(1 To 3) As String
toSelect(1) = "item1"
toSelect(2) = "item2"
toSelect(3) = "item3"
For Each pvItem In objField.PivotItems
For Each st In toSelect
If pvItem.Value = st Then
pvItem.Visible = True
Exit For
Else
pvItem.Visible = False
End If
Next
Next
Well.
Because you have not how to hide all, because, always you need to have 1 item visible
I do this:
I start hiding the first field, and before go to the next, i show all fields i need visible, then, i go to the secont item, and hide, and again show all items i want, and so on. Then, always will be visible any field, and wont have error.
After the loop, i again try to show all fields i want.
With ActiveSheet.PivotTables("TablaD2").PivotFields("Entity")
Dim i As Long
For i = 1 To .PivotItems.Count
.PivotItems(i).Visible = False
.PivotItems("ARG").Visible = True
.PivotItems("BRL").Visible = True
.PivotItems("GCB").Visible = True
.PivotItems("MEX").Visible = True
Next
.PivotItems("ARG").Visible = True
.PivotItems("BRL").Visible = True
.PivotItems("GCB").Visible = True
.PivotItems("MEX").Visible = True
End With