In a specific row of a table replace a "*" with a checked checkbox, and "" with a checkbox that is not checked - vba

I have a couple of tables and want to replace column 2 or column 5 (if it exists) with check boxes.
If there is an asterisk in the cell, I want the check box checked = True.
If there's no asterisk, the cell will only be a unchecked check box. These check boxes are from the developer tab, under controls, legacy forms.
I researched but failed:
replacing an asterisk with a check box (checked)
limiting it to a specific column (see image)
replacing a blank cell with a check box (unchecked)
limiting the action to a specific column (2 and 5 (if it exists))
Dim oCell As Cell
Dim oRow As Row
For Each oRow In Selection.Tables(1).Rows
For Each oCell In oRow.Cells 'this won't work specifically with my example, needs to be a little more specific
If oCell.Range.Text = "*" Then
MsgBox oCell.RowIndex & ", " & oCell.ColumnIndex & " check it!"
'I don't how to put in a check box here
End If
Next oCell
Next oRow
'I want to combine the top code and code below...right?
'do for each cell in column 2
With ActiveDocument.FormFields.Add(Range:=ActiveDocument.Selection, Type:=wdFieldFormCheckBox)
If cellvalue = "" Then 'just verbal logic here
.CheckBox.Value = False
End If
If cellvalue = "*" Then 'just verbal logic here
.checkbox.Value = True
End If
End With

Here's how I would do this:
Dim objDoc As Document
Dim oCell As Cell
Dim oCol As Column
Dim objTable As Table
Dim bFlag As Boolean
Set objDoc = ActiveDocument
Set objTable = Selection.Tables(1)
'This may or may not be necessary, but I think it's a good idea.
'Tables with spans can not be accessed via the spanned object.
'Helper function below.
If IsColumnAccessible(objTable, 2) Then
For Each oCell In objTable.Columns(2).Cells
'This is the easiest way to check for an asterisk,
'but it assumes you have decent control over your
'content. This checks for an asterisk anywhere in the
'cell. If you need to be more specific, keep in mind
'that the cell will contain a paragraph return as well,
'at a minimum.
bFlag = (InStr(oCell.Range.Text, "*") > 0)
'Delete the content of the cell; again, this assumes
'the only options are blank or asterisk.
oCell.Range.Delete
objDoc.FormFields.Add Range:=oCell.Range, Type:=wdFieldFormCheckBox
'Set the value. I found some weird results doing this
'any other way (such as setting the form field to a variable).
'This worked, though.
If bFlag Then
oCell.Range.FormFields(1).CheckBox.Value = True
End If
Next oCell
End If
'Then do the same for column 5.
Public Function IsColumnAccessible(ByRef objTable As Table, iColumn As Integer) As Boolean
Dim objCol As Column
'This is a little helper function that returns false if
'the column can't be accessed. If you know you won't have
'any spans, you can probably skip this.
On Error GoTo IsNotAccessible
IsColumnAccessible = True
Set objCol = objTable.Columns(iColumn)
Exit Function
IsNotAccessible:
IsColumnAccessible = False
End Function

Related

MS Word - find table rows with wrapped text

I have a table where all cells have Cell.WordWrap set to true. Some of them have text longer than cell width so it's wrapped. I need to find them (with longer text) and set them Cell.FitText = True, but can't figure how.
I tried to read row/cell .height. But it does not return real row/cell height but minimum height regardless how Cell.HeightRule is set.
Thanks for your tips!
One way to determine whether the content of a cell wraps is to compare the line numbering of the start and end of the cell content, as demonstrated in the following code example.
The Word object model provides the Information property, which has numerous enumeration members, including wdFirstCharacterLineNumber.
Each cell in a table is checked in a loop. After determining the line number of the first character in the cell, the Range is collapsed to its end-point (which is the beginning of the next cell), then moved back one character (putting it in the original cell) and the line number of the last character in the cell is checked.
If the second is greater than the first, the cell is added to an array. (Note: possibly, you could process the cell directly. But if this could affect other cells, better to add them all to an array, first, then process the array.)
Finally, the array is looped and each cell formatted with FitText = True
Sub ChangeCellWrapForLongLinesOfText()
Dim tbl As Word.Table
Dim cel As Word.Cell
Dim rngCel As Word.Range
Dim multiLineCells() As Word.Cell
Dim firstLine As Long
Dim lastLine As Long
Dim i As Long, x As Long
Set tbl = ActiveDocument.Tables(1)
For Each cel In tbl.Range.Cells
Set rngCel = cel.Range
firstLine = rngCel.Information(wdFirstCharacterLineNumber)
rngCel.Collapse wdCollapseEnd
rngCel.MoveEnd wdCharacter, -1
lastLine = rngCel.Information(wdFirstCharacterLineNumber)
If lastLine > firstLine Then
ReDim Preserve multiLineCells(i)
Set multiLineCells(i) = cel
i = i + 1
End If
Next
'Debug.Print i, UBound(multiLineCells())
For x = LBound(multiLineCells()) To UBound(multiLineCells())
'Debug.Print multiLineCells(x).Range.Text
multiLineCells(x).FitText = True
Next
End Sub

formula leaving whitespace

I have the following formula designed to flag rows in a ListObject:
=IF( [#[Is Closed]]="Y", "", "Y")
I have some vba code that looks for these value via StrCmp, and was surprised to find that the Text property of the cell was " Y " (as opposed to "Y").
There are some obvious easy work arounds but can someone explain why the formula is leaving whitespace and how to force it not to?
Cheers,
UPDATE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' FindAllInColumn
' To find a value regardless of hidden rows and autofulter settings that can make
' other methods unreliable
'
' aSearchRange : the range of data to search, which MUST be a single column
' aLookUpVal : the value
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FindAllInColumn(aSearchRange As Range, aLookUpVal As Variant) As Excel.Range
Debug.Assert aSearchRange.Columns.Count = 1
Dim rngEach As Range
Dim rngResult As Excel.Range
For Each rngEach In aSearchRange
' Debug.Print rngEach.Address & ": Value " & rngEach.Text
' If IsValued(rngEach.Text) Then Stop
If (StrComp(rngEach.Text, aLookUpVal) = 0) Then
If rngResult Is Nothing Then
Set rngResult = rngEach
Else
Set rngResult = Application.Union(rngResult, rngEach)
End If
End If
Next rngEach
Set FindAllInColumn = rngResult
End Function
The FIX
StrComp(rngEach.Value2, aLookUpVal, vbTextCompare)
Changing .Text to .Value2 instead. Odd, but at least it works now
In general empty spaces in Excel sometimes cause a lot of problems. As the OP has found out himself, .Value2 seems like a universal problem-solver of many strange cases.
Try to select the cell and check the following code, it will print possible "hidden" empty spaces:
Option Explicit
Public Sub TestMe()
Dim rng As Range
Dim cnt As Long
Set rng = Selection
For cnt = 1 To Len(rng)
Debug.Print Asc(Mid(rng, cnt, 1))
Next cnt
End Sub

Finding a cell based on the header of a section of data, then selecting the last row of that section

I am attempting to find the text of a header row based on the value of a cell relative to the cell that is clicked in. The way I have attempted to do this is follows:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim var1 As Variant
Dim var2 As Variant
Dim var3 As Variant
Dim FormName As String
FormName = "New Form"
Static NewFormCell As Range
Application.ScreenUpdating = False
If Not Intersect(Target, Range("G16:X80")) Is Nothing Then
If Target.Cells.Count = 1 Then
var1 = Cells(Target.Row, 2).Value
var2 = Cells(15, Target.Column).Value
If Not (IsEmpty(var1)) And Not (IsEmpty(var2)) And var2 <> "+" And Target.Interior.ColorIndex <> 2 And Target.Borders(xlEdgeLeft).LineStyle <> xlNone Then
If IsEmpty(Target) Then
Target.Value = "X"
Target.HorizontalAlignment = xlCenter
Target.VerticalAlignment = xlCenter
Target.Font.Bold = True
Dim Header As Range
Set Header = Range("A54:E160").Find(var2, LookIn:=xlValues)
Header.Offset(1, 1).End(xlDown).EntireRow.Select
Dim CopyCell As Range
'Header.End(xlDown).EntireRow.Insert
'Set CopyCell = Header.End(xlDown). [offset?]
'CopyCell.Value = var1
Else
Target.ClearContents
End If
Else
Exit Sub
End If
End If
End If
Application.ScreenUpdating = True
End Sub
The issue is VBA is throwing Run-Time Error 91 ("Object variable or With block variable not set"). It then highlights the last row in that section of code. Since I set that variable in the previous line, I'm not sure why I'm receiving this error or if I'm even going about this the right way.
Any input would be greatly appreciated!
EDIT: I cleared the above issue by searching over a wider range. The cell I wanted to select was merged, but I still assumed the value was stored within column A. But this code still isn't quite doing what I'd like it to:
I want to select the last row in the section (not the last row of data in the sheet, but the last contiguous data in column B), but right now my code is jumping me all the way to the bottom of the sheet.
The problem is that your .Find isn't finding the value. In this case, you can add some code to handle that.
...
Dim Header As Range
Set Header = Range("A59:A159").Find(var2, LookIn:=xlFormulas)
If Header Is Nothing Then
' There's no value found, so do something...
msgbox(var2 & " was not found in the range, will exit sub now."
Exit Sub
End If
MsgBox Header
...
...of course there are myriad ways/things you can do to handle this. If you still want to execute other code, then wrap everything in an If Header is Nothing Then // 'do something // Else // 'other code // End IF type thing.
It really just depends on what you want to do. Again, your error is being caused by the fact that the var2 isn't being found, so just find other things to do in that case.

Excel/VBA uncheck checkboxes if mandatory field is empty

I wrote a function which for each checkbox in document check if field C140 is empty if is then uncheck checkbox in same row.
Sub MarkCheckBoxes()
Dim chk As CheckBox
Dim ws As Worksheet
Set ws = ActiveSheet
For Each chk In ws.CheckBoxes
If ws.Range("C140").Value = "" Then
chk.Value = False
Else
chk.Value = True
End If
Next chk
End Sub
Now I want change it that for each row check if mandatory fields are empty if is then uncheck checkbox in the same row as empty field, also I need clean row color by:
EntireRow.Interior.ColorIndex = xlColorIndexNone
When I changed range("c140") to range("c140:c150") then I had an error mismatch..
ALSO
Ralph give me an answer for first part, but now I have another problem.
I'd like to make some function which allow me check if any of field in row 149 is text "Mandatory then it check if rows belows are empty if is then do uncheck. So I tried sth like this:
If ws.Rows("149") = "Mandatory" Then
If ws.Range("C" & chk.TopLeftCell.Row).Value
But I don't have any idea how to write second if to check value in each column
Use the Cells property of the Worksheet instead of the Range like this in your If statent:
If ws.Cells(3, chk.TopLeftCell).Value = ""
I believe you might be looking for something like this:
Sub MarkCheckBoxes()
Dim chk As CheckBox
Dim ws As Worksheet
Set ws = ActiveSheet
For Each chk In ws.CheckBoxes
If ws.Range("C" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
Else
chk.Value = True
End If
Next chk
End Sub
Explanations:
I changed merely the row for C140 to C + the row number in which the checkbox is located. I hope this is what you've been looking for.
In respect to your initial attempt to change Range("C140") (which is one cell) to a range of cells like C140:C150: of course that cannot work. That would be like please compare this apple to these 10 apples. In return you would get 10 answers some of which might be true and others might be false for your If clause. VBA wouldn't know which ones of the ture or the false to take.

excel checkspelling single cell

I'm struggling a bit with CheckSpelling in Excel. I have a merged cell that I want to check, but only this cell. Here's what I'm doing.
ActiveSheet.Unprotect strSheetPassword
Application.DisplayAlerts = False
Set ma = Range("B21").MergeArea
ma.MergeCells = False
Union(Range("B1"), ma(1, 1)).CheckSpelling
ma.MergeCells = True
Application.DisplayAlerts = True
ActiveSheet.Protect strSheetPassword
It's checking the cell I want, but it's also checking the rest of the document. In reading other posts, I got the impression that checking a single cell causes CheckSpelling to check the entire document. This is why I put in the Union with the Range("B1") - B1 contains header text that doesn't have any misspellings and is normally locked, so that users can't change it. But, it is still checking the rest of the sheet! I've tried quite a few variations on this, but it still keeps checking the rest of the sheet.
CONCLUSION
I had been under the impression that it was possible to invoke the CheckSpelling form and have it only check certain cells. Apparently, this isn't true. Instead of building my own form, I should be able to get away with checking the whole sheet each time, although I really don't like that. Thanks for all the feedback!
For a single merged cell:
Sub spell_me()
Dim b As Boolean
b = Application.CheckSpelling(Word:=ActiveCell.Text)
MsgBox b & vbCrLf & ActiveCell.Address & vbCrLf & ActiveCell.Text
End Sub
EDIT#1:
To find the miscreant word, you could Split() the text into individual words and check each word.
If it is enough if the wrong part gets highlighted you can use this:
Sub SpellCheck()
Dim response As Boolean
Dim words As Variant
Dim wordCount As Long
Dim startAt As Long
words = Split(ActiveCell.Text, " ")
'set all of the text to automatic color
ActiveCell.Font.ColorIndex = xlAutomatic
For wordCount = LBound(words) To UBound(words)
response = Application.CheckSpelling(word:=words(wordCount))
If Not response Then
'find out where it is in the text and color the font red
startAt = InStr(ActiveCell.Text & " ", words(wordCount) & " ")
ActiveCell.Characters(Start:=startAt, Length:=Len(words(wordCount))).Font.Color = vbRed
End If
Next
End Sub