VBA - error handling for deleted checkboxes - vba

I am working in MS Word 2013 and attempting to programatically delete rows in a table when Checkbox1 through CheckboxN is unchecked through use of a command button. The following abbreviated code works once (and can delete one or more rows) but breaks when run a second since the code still makes references to checkboxes that have been deleted. I have tried basic error handling but have been unsuccessful. Can anyone provide assistance so the code can be run multiple times and delete subsequent rows/checkboxes? If this is not the right forum to post this request, please let me know. Thank you!
Sub CommandButton1_Click()
If CheckBox1.Value = False Then
Selection.GoTo What:=wdGoToBookmark, Name:="Row6"
Selection.Rows.Delete
End If
If CheckBoxN.Value = False Then
Selection.GoTo What:=wdGoToBookmark, Name:="Row6"
Selection.Rows.Delete
End If
End sub

So, I'd probably take a different approach here. Rather than relying on named checkboxes, cycle backwards through all relevant checkboxes and determine the row to delete. I'm assuming that the checkboxes are in a cell within the row to be deleted. It's important to go backwards because, as you've noted, you'll be removing items as you go.
Sub checkChecks()
Dim objTable As Table
Dim objCC As ContentControl
Dim i As Long
Set objTable = ActiveDocument.Tables(1)
For i = objTable.Range.ContentControls.Count To 1 Step -1
Set objCC = objTable.Range.ContentControls(i)
If objCC.Type = wdContentControlCheckBox Then
If objCC.Checked = False Then objCC.Range.Rows(1).Delete
End If
Next i
End Sub
Obviously this only works if you can isolate the table in question, but that shouldn't be too hard.

Related

Mutually excluding checkboxes in Word table

I created a Word Document (Word 2016) that, by clicking a button, generates a Table with predefined text and formatting.
Column1
Column2
Column3
QUESTION (Y/N)
YES_Checkbox
No_Checkbox
Row number 8 (shown above) contains a YES/NO question; to manage that, I inserted two Checkboxes (one in Column2, the other in Column3) using the following syntax:
For ii = 2 To 3
Set rng = mytable.Cell(8, ii).Range
rng.Select
With Selection
.Collapse Direction:=wdCollapseStart
.Range.ContentControls.Add wdContentControlCheckBox
.MoveRight Unit:=wdCharacter, Count:=2
End With
Next ii
My idea is to have mutually exclusive checkboxes: that means, if User selects "YES" the "NO" is automatically deselected (and vice-versa). To do so, I created a Sub within the main button script. It checks for the checkbox value and then tries to 'tick it' (on un-tick it) using the following code (not yet completed):
Sub Check_YES_Not(tblNew)
Dim thisCell As Range
check1 = mytable.Cell(8, 2).Range.ContentControls(1).Checked
check2 = mytable.Cell(8, 3).Range.ContentControls(1).Checked
'If condition to be added
check1 = True 'This is how I am trying to modify the checkbox, but it is not working
'ElseIf add other conditions...
'Msgbox "to be completed..."
'End If
End Sub
Code runs and creates the table correctly, but the checkbox scripts is not behaving as I wish. Could someone please tell me what I am doing wrong and how I could make it work? Thank you very much.
UPDATE
This is how I solved it. There are still minor concerns (e.g. if I click "Yes", I need to select another cell before clicking "No", otherwise the control is not able to work correctly). Apart from this, many thanks to #macropod and Timothy for their kind support.
In order to allow the User to create additional table, I created a Public counter that is increased at each added table. It is not an elegant solution, but it works for now. The initial table has a different tag (I did not include it here).
Private Sub Document_ContentControlOnExit(ByVal oCC As ContentControl, Cancel As Boolean)
Dim collCCs As ContentControls
Dim oCCTarget As ContentControl
Dim ii As Integer
For ii = 1 To 500 'Additional tables
If Not IsEmpty(ActiveDocument.SelectContentControlsByTag("NO" + Str(ii))) Then
Select Case oCC.Tag
Case "YES" + Str(ii)
Set collCCs = ActiveDocument.SelectContentControlsByTag("NO" + Str(ii))
For Each oCCTarget In collCCs
If oCCTarget.Checked = True Then
oCCTarget.Checked = False
Exit For
End If
Next
Case "NO" + Str(ii)
Set collCCs = ActiveDocument.SelectContentControlsByTag("YES" + Str(ii))
For Each oCCTarget In collCCs
If oCCTarget.Checked = True Then
oCCTarget.Checked = False
Exit For
End If
Next
End Select
End If
Next ii
Your code isn't working as you are only setting the value of a variable, not the checked status of the checkbox. The simplest way of achieving your desired result is to set the checked status of one checkbox to the opposite of the other, like this:
mytable.Cell(8, 2).Range.ContentControls(1).Checked = Not mytable.Cell(8, 3).Range.ContentControls(1).Checked
Also your code to insert the content controls can be simplified to:
For ii = 2 To 3
mytable.Cell(8, ii).Range.ContentControls.Add wdContentControlCheckBox
Next ii
There is rarely any need to select anything when working with Word.
Finally, you appear not to be forcing variable declaration. This can lead to avoidable errors in your code. Just add Option Explicit at the top of every code module. This will prevent your code from compiling when you have undeclared variables. To add this automatically to new modules open the VBE and go to Tools | Options. In the Options dialog ensure that "Require Variable Declaration" is checked.

VBA using drop down lists on other worksheets to hide rows automatically

Afternoon all!
I am using the results of various drop down lists to hide the relevant rows on a spreadsheet as the value on the drop down list is changed (so automatically).
With some googling, I have come across the below set up which works nicely, although I have now hit a snag when trying to specify drop down list cell from another worksheet.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim disabled As Boolean
If Range("D2") = "Yes" Then
disabled = True
End If
If disabled Then
Rows("3:8").EntireRow.Hidden = False
Else
Rows("3:8").EntireRow.Hidden = True
End If
End sub
Using the following has not worked, and googling for a solution has lead me up many a dead end:
If Sheets("Topsheet").Range("D27") = "Yes" Then
Am I unable to use values from a neighbouring sheet when declaring a variable due to it being a private sub?
Any help would be much appreciated as I have been stumped on this for a couple of hours!
Your code can be massively simplified. Try using this (You'll have to update the sheet name if it's not the same as yours)
Private Sub Worksheet_Change(ByVal Target As Range)
Sheets("SheetWithRowsToBeHidden").Rows("3:8").EntireRow.Hidden = IIf(Me.Range("D27").Value2 = "Yes", True, False)
End Sub
Also, where have you put this code? Have you put it inside a Module or is it in the Sheet Object? It needs to be in the Sheet Object that has the dropdowns on.

VBA MS Project. How to move entries of lookuptable programmatically?

I have an issue. I'm working on VBA macros in MS Project 2013, that can automatically fill and change lookup table, which linked with local custom field in project professional. I have these code sections on VBA for:
-adding entries
Set objStateEntry = objOutlineCode.LookupTable.AddChild(entryName)
-changing descrption of entries
objStateEntry.Description = "some description"
-changing level of entires
objStateEntry.level = entryLevel
But I can't find how to programmatically move entries up/down in lookup table. In other words I need to use marked in the screenshot buttons programmatically. Please help me. Thank you!
Try something like this:
Private Sub SpinButton1_SpinDown()
On Error Resume Next
If ListBox1.ListIndex = ListBox1.ListCount - 1 Then Exit Sub
With Me.ListBox1
.ListIndex = .ListIndex + 1
End With
End Sub
Private Sub SpinButton1_SpinUp()
On Error Resume Next
If ListBox1.ListIndex = 0 Then Exit Sub
With Me.ListBox1
.ListIndex = .ListIndex - 1
End With
End Sub
goodluck
I tried recording a macro while using the spin button you highlighted, but this indicates that VBA can't control the spin button...
So it seems the only way to change the index of a lookup table entry by VBA is to first delete the entry then add it back, for example moving entry at index=4 up to index=2 (after saving the name and description of entry index=4):
Dim lteName As String
Dim lteDesc As String
lteName = Application.CustomFieldValueListGetItem(pjCustomResourceOutlineCode2, pjValueListValue, 4)
lteDesc = Application.CustomFieldValueListGetItem(pjCustomResourceOutlineCode2, pjValueListDescription, 4)
Application.CustomFieldValueListDelete FieldID:=pjCustomResourceOutlineCode2, Index:=4
Application.CustomFieldValueListAdd FieldID:=pjCustomResourceOutlineCode2, Value:=lteName, Description:=lteDesc, Index:=2
Two caveats:
1: It appears you can't do the above in the same macro that you are adding the lookup table entries. It only works in another macro run after adding the entries.
2: At least in my version of MS Project, the index number is flaky (it should be consecutive but sometimes index numbers repeat or there are gaps but then it corrects itself!), no doubt due to deleting and adding entries like I am suggesting. The code won't work if the index numbers that VBA is looking for don't match what is displayed in the lookuptable window. Oh dear... wish MSProject was perfect!
Noted same behaviour on another SO thread here.

Hide Active Column when cell value is changed

I have been trying to work this out myself for the last few days and caught myself in a bit of a one step forward three steps back cycle. I've been reluctant to bother you thinking this would have been answered somewhere else before now.
The idea is that I have a spreadsheet that has criteria in rows with separate entries in rows; in row 6 it is the status of each column entry, which when changed to "Completed" I would like the column to be hidden.
I've been floundering around with Worksheet_Change and been able to hide specific columns, but not the active column.
Any help offered would be much appreciated and I'm sorry if this has been covered elsewhere, but I've not been able to successfully apply any examples out there.
Thanks.
Whenever you have to work with worksheet_change events, you have to consider a cycle for it, due to user may delete multiple data at the same time or do a copy paste, if you only consider "Target" It would give a debugger error.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ItemMultipleData As Range
For Each ItemMultipleData In Target 'handles multiple cells, paste, del, etc
'your code (instead of using "Target" change to ItemMultipleData. IE:
'If ItemMultipleData.Value = "Completed" Then
Next ItemMultipleData
End Sub
Here is a starting point. It only checks row # 6:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Range("6:6")
If Intersect(Target, rng) Is Nothing Then Exit Sub
If Target.Count <> 1 Then Exit Sub
If Target.Value = "Completed" Then
Application.EnableEvents = False
Target.EntireColumn.Hidden = True
Application.EnableEvents = True
End If
End Sub
EDIT#1:
This approach assumes that only one cell at a time is being changed........that makes it easy to "find the active cell"

Making excel graphs appear/disappear

I want a graph only to appear when a condition is fulfilled. To be more precise: I have a drop down menu that changes the content of a graph. If the menu point "Total revenue" is clicked, I want a second graph to appear. I am new to VBA and this is what I came up with so far:
Sub Iffuntion()
Dim SelectedChart As Range
Dim notVisible As Boolean
If Range("D100").Value = Range("E100").Value Then
ActiveSheet.ChartObjects("Testchart").Visible = True
Else
ActiveSheet.ChartObjects("Testchart").Visible = notVisible
End If
End Sub
It works, but I have to execute the VBA to make the graph appear/disappear and I would like that to happen automatically. Also the condition should eventually be in another worksheet to keep the sheet with the graphs nice and tidy. I read that to achieve this I have toI have to activate the other worksheet. Would you recommend this way or is there a better solution?
Thanks for the help and best regards!
Pete
EDIT: Here is the link to a sample file with the proposed solution of Cor_Blimey, that I couldn't get to work properly. The interconnections in the excel are more complicated than they would have to be, but I wanted to be as accurate ad possible in displaying what is actually happening in my excel. Thanks for taking a look!
https://dl.dropboxusercontent.com/u/18406645/sample.xlsm
Assuming you mean that they change, from a data validation drop down list, the contents of a cell then you can put your code into the Worksheet's Worksheet_Change event. This event is fired when the user changes the content of a cell (or by an external link).
Then test for the cell being the right cell then run your code.
Like:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Intersect(Target, Me.Range("D100"))
If Not rng Is Nothing Then
If rng.Value = Me.Range("E100").Value Then
Me.ChartObjects("Testchart").Visible = True
Else
Me.ChartObjects("Testchart").Visible = False
End If
End If
End Sub