The complete macro is at the end of this section of the post, but first I'll describe the added parts.
To restrict the values of F and S to integers from 1 to 5, add this sequence just after setting ccF through ccL:
CC.Range.Text = Int(Val(CC.Range.Text))
If Val(CC.Range.Text) < 1 Or Val(CC.Range.Text) > 5 Then
MsgBox "Value must be from 1 to 5", vbCritical, "Oops!"
Cancel = True
Exit Sub
End If
The Val function converts text to a numeric data type; if the text doesn't start with a digit, the function returns 0. The Int function converts any number with a decimal part to just the integer part. Thus, the first line makes sure that the content of
CC is an integer. If that integer is out of the range, then the message appears, and the cursor doesn't leave the content control.
Making sure that RF <= LF is a little more complicated. For one thing, the code in the second half of the macro has to get the LF value, which would not have been retrieved in this execution of the macro (the first Case was skipped). So the second Case adds
the lines
Dim ccLF As ContentControl
Set ccLF = ActiveDocument.SelectContentControlsByTag("LF" & intRow)(1)
Then the verification of the 1-to-5 range is done as in the first Case, followed by the test for RF <= LF:
If CC.Tag = ccF.Tag And Val(ccLF.Range.Text) < Val(ccF.Range.Text) Then
MsgBox "Value must be less than or equal to " & ccLF.Range.Text, vbCritical, "Oops!"
Cancel = True
Exit Sub
End If
Here's the complete macro:
Private Sub Document_ContentControlOnExit(ByVal CC As ContentControl, Cancel As Boolean)
Dim ccCH1 As ContentControl
Dim ccCH2 As ContentControl
Dim ccATnum As ContentControl
Dim ccF As ContentControl
Dim ccS As ContentControl
Dim ccR As ContentControl
Dim ccL As ContentControl
Dim intRow As Integer
Dim intVal As Integer
Dim rg As Range
Select Case True
Case (CC.Tag Like "LF*") Or (CC.Tag Like "LS*") ' exiting control in left side of table
' get the row number from the tag
intRow = Right(CC.Tag, Len(CC.Tag) - 2)
Set ccF = ActiveDocument.SelectContentControlsByTag("LF" & intRow)(1)
Set ccS = ActiveDocument.SelectContentControlsByTag("LS" & intRow)(1)
Set ccR = ActiveDocument.SelectContentControlsByTag("LR" & intRow)(1)
Set ccL = ActiveDocument.SelectContentControlsByTag("LL" & intRow)(1)
CC.Range.Text = Int(Val(CC.Range.Text))
If Val(CC.Range.Text) < 1 Or Val(CC.Range.Text) > 5 Then
MsgBox "Value must be from 1 to 5", vbCritical, "Oops!"
Cancel = True
Exit Sub
End If
' calculate value for LR control
intVal = Val(ccF.Range.Text) * Val(ccS.Range.Text)
ccR.Range.Text = intVal
Set rg = ccR.Range.Duplicate
'include cell marker, thus whole cell
rg.MoveEnd wdCharacter, 2
If intVal < 5 Then
rg.Shading.BackgroundPatternColor = wdColorOliveGreen
ccL.Range.Text = "Low, Broadly Acceptable"
ElseIf intVal <= 9 Then
rg.Shading.BackgroundPatternColor = wdColorLightOrange
ccL.Range.Text = "Medium, Tolerable"
Else
rg.Shading.BackgroundPatternColor = wdColorRed
ccL.Range.Text = "High, Unacceptable"
End If
' make RF control's value same as LF control
ActiveDocument.SelectContentControlsByTag("RF" & intRow)(1).Range.Text = _
ccF.Range.Text
Case (CC.Tag Like "RF*") Or (CC.Tag Like "RS*") ' exiting control in right side of table
' get the row number from the tag
intRow = Right(CC.Tag, Len(CC.Tag) - 2)
Set ccF = ActiveDocument.SelectContentControlsByTag("RF" & intRow)(1)
Set ccS = ActiveDocument.SelectContentControlsByTag("RS" & intRow)(1)
Set ccR = ActiveDocument.SelectContentControlsByTag("RR" & intRow)(1)
Set ccL = ActiveDocument.SelectContentControlsByTag("RL" & intRow)(1)
Dim ccLF As ContentControl
Set ccLF = ActiveDocument.SelectContentControlsByTag("LF" & intRow)(1)
CC.Range.Text = Int(Val(CC.Range.Text))
If Val(CC.Range.Text) < 1 Or Val(CC.Range.Text) > 5 Then
MsgBox "Value must be from 1 to 5", vbCritical, "Oops!"
Cancel = True
Exit Sub
End If
If CC.Tag = ccF.Tag And Val(ccLF.Range.Text) < Val(ccF.Range.Text) Then
MsgBox "Value must be less than or equal to " & ccLF.Range.Text, vbCritical, "Oops!"
Cancel = True
Exit Sub
End If
' calculate value for RR control
intVal = Val(ccF.Range.Text) * Val(ccS.Range.Text)
ccR.Range.Text = intVal
Set rg = ccR.Range.Duplicate
'include cell marker, thus whole cell
rg.MoveEnd wdCharacter, 2
If intVal < 5 Then
rg.Shading.BackgroundPatternColor = wdColorOliveGreen
ccL.Range.Text = "Low, Broadly Acceptable"
ElseIf intVal <= 9 Then
rg.Shading.BackgroundPatternColor = wdColorLightOrange
ccL.Range.Text = "Medium, Tolerable"
Else
rg.Shading.BackgroundPatternColor = wdColorRed
ccL.Range.Text = "High, Unacceptable"
End If
Case Else
Exit Sub
End Select
End Sub
=========================================
If a row contains content controls that have been set to "Content control cannot be deleted", Word won't allow that row to be deleted. First the option would have to be turned off in each control. Of course, that's too much work to be reasonable :) so here's
a macro that will turn off the option in all the controls in the selected rows and then delete the rows.
Sub DeleteTableRowsWithControls()
Dim oRow As Row
Dim cc As ContentControl
If Not Selection.Information(wdWithInTable) Then
MsgBox "Select rows to delete."
Exit Sub
End If
If MsgBox("Delete selected rows?", vbYesNo) = vbYes Then
For Each oRow In Selection.Rows
For Each cc In oRow.Range.ContentControls
cc.LockContentControl = False
Next cc
Next oRow
Selection.Rows.Delete
End If
End Sub
=========================================
For your last request, the answer is more complicated than I can write up here. First take a look at https://gregmaxey.com/word_tip_pages/link_content_to_dropdown_list.html.
After that, if you have questions about how to handle your particular application, please start a new thread here. I'll keep an eye out for your post.