Compares two column based on the value of a third column's value - vba

What I want to do is create a macro to look at a column (AF) and based on that value, compare column (BI), (BJ), and/or (BK) together and if its false, highlight the compared cells in yellow. I know that's a little hard to follow but this example should help clarify:
My Sheet has the following columns:
Column AF Column BI Column BJ Column BK
PRODUCT Height Length Width
I need a macro to look at the product type and compare the dimensions for that product as follows:
- If product = A, then Length = Width, if not then highlight Length and Width Cells
- If product = B then Length > Width, if not then highlight Length and Width Cells
- If product = C then Width > Height < Length, if not highlight Length, Width, and Height cells
- If product - D then Width = Length < Height, if not highlight Width, Length, and/or Height
My Data starts on row 3 and ends at row 5002.
I have tried researching this and was only able to find solutions that compare two cells then write a third column. I could combine an IF formula and conditional formatting to achieve this but I don't want to have this run all the time as the sheet will be sorted and color coded. I plan to place this macro into a command button.

Suggest to combine Statements such as Select Case, If...Then...Else, together with Operators And, Or. See the following pages:
https://msdn.microsoft.com/en-us/library/office/gg251599.aspx
https://msdn.microsoft.com/en-us/library/office/gg278665.aspx
https://msdn.microsoft.com/EN-US/library/office/gg251356.aspx
After which you should be able to write something that resembles this:
(Code below is just a sample, it will not work)
Select Case Product
Case A
If Length <> Width Then
Rem Highlight Length And Width Cells
End If
Case B
If Length <= Width Then
Rem Insert here the code to highlight Length And Width Cells
End If
Case C
If Width <= Height And Height >= Length Then
Rem Insert here the code to highlight Length, Width, and Height cells
End If
Case D
If Width <> Length And Length >= Height Then
Rem Insert here the code to highlight Width, Length, and/or Height
End If
End Sub
In case you don’t know to highlight the Width, Length and Height Cells; I suggest to do it manually while recording a macro, this shall give a good starting point.

I suggest to work with objects, defining variables for the Data range, each row being validated, the position of the fields to validate, etc. see below code with comments
Sub Highlight_Cells_based_Comparison()
Dim rData As Range
Dim rRow As Range
Dim rCllsUnion As Range
Rem Set variables to hold Fields position within the DATA range
Dim bPosProd As Byte, bPosHght As Byte, bPosLeng As Byte, bPosWdth As Byte
Rem Set variables to hold Fields values
Rem (data type Variant as don't know type of values these fields are holding, change as appropriated)
Rem see https://msdn.microsoft.com/en-us/library/office/gg251528.aspx)
Dim sProd As String, vHght As Variant, vLeng As Variant, vWdth As Variant
Dim lRow As Long
Rem Set Range (assuming it goes from column C to BK - change as needed)
Rem Not starting from column A on porpuse
Set rData = ActiveSheet.Range("C3:BK5002")
Rem Get Fields position from Header row
Rem Suggest to use this method instead of hard coding columns
On Error Resume Next
With rData
bPosProd = WorksheetFunction.Match("PRODUCT", .Rows(1), 0)
bPosHght = WorksheetFunction.Match("Height", .Rows(1), 0)
bPosLeng = WorksheetFunction.Match("Length", .Rows(1), 0)
bPosWdth = WorksheetFunction.Match("Width", .Rows(1), 0)
End With
If Err.Number <> 0 Then Exit Sub
On Error GoTo 0
Rem Loop thru each row excluding header
For lRow = 2 To rData.Rows.Count
Set rRow = rData.Rows(lRow)
With rRow
Rem Get Row Field values
sProd = .Cells(bPosProd).Value2
vHght = .Cells(bPosHght).Value2
vLeng = .Cells(bPosLeng).Value2
vWdth = .Cells(bPosWdth).Value2
Select Case sProd
Case A 'Change value of A as required
Rem If product = A, then Length = Width, if not then highlight Length and Width Cells
Rem If Length <> Width Then Highlight Length And Width 'Cells
If vLeng <> vWdth Then
Set rCllsUnion = Union(.Cells(bPosLeng), .Cells(bPosWdth))
Rem Suggest to use a subroutine for this piece as it's a repetitive task
Rem see https://msdn.microsoft.com/en-us/library/office/gg251648.aspx
GoSub CllsUnion_Highlight
End If
Case B
Rem repeat as in Case A with required changes
Case C
'...
Case D
'...
End Select: End With: Next
Exit Sub
Rem Subroutine to highlight cells
CllsUnion_Highlight:
With rCllsUnion.Interior
.Color = 65535
.TintAndShade = 0
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.PatternTintAndShade = 0
End With
Return
End Sub

Related

How to make a table fit the window height in Word?

I am New to VBA. I have a table with 4 columns and almost 2000 rows and it is displayed in a 3 column Word layout. My problem is that the last rows of the 3 columns are not always on one height as shown in the image (Masked the personal data with the white font in cells). [Image of the Table1
I think a solution would be to set the height of the rows with 2-lines to 0.54cm and the 1-line rows to 0.27cm. I did this manually and it worked. I am looking for a macro to achieve this. The below code will provide an understanding of what I am trying to do.
Sub height ()
ActiveDocument.Tables(1).Rows.HeightRule = wdRowHeightAuto
'this automatically sets the 2-line rows to 0.53cm and the 1-line rows to 0.25cm
For Each row in Rows
If Row.RowHeight < 0.5cm Then
Row.RowHeight = 0.27cm
Else Row.RowHeight = 0.54cm
End If
Next Row
End Sub
I know that this code cant work but i think it shows you what i want to do.
As Row.RowHeight won't return a useful value unless the row has been set to an exact height you can change the line spacing for the text so that the required cell heights are achieved automatically.
The code below assumes that the table you want to adjust is the first one in the document.
Sub AdjustLineSpacingForTable()
Dim reqdLineSpacing As Single
'start with the height of a double height cell
reqdLineSpacing = CentimetersToPoints(0.54)
With ActiveDocument.Tables(1)
'table cells have padding top and bottom so we need to subtract that from the required height
reqdLineSpacing = reqdLineSpacing - (.TopPadding + .BottomPadding)
'now we can adjust the text spacing
With .Range.ParagraphFormat
'ensure there is no additional spacing on the paragraphs
.SpaceAfter = 0
.SpaceBefore = 0
'set line spacing to an exact amount
.LineSpacingRule = wdLineSpaceExactly
.LineSpacing = reqdLineSpacing / 2
End With
End With
End Sub

How to bold line in one cell based on another cell in the same row

I am trying to bold the last line of a multi-line cell (column E), but specifically based on if another cell in the same row (column L) is blank/empty or not. I have working code that bolds just the last line, but trying to incorporate the IF portion has me stuck. This is what I have so far, and it keeps giving me a data mismatch error.
Thanks in advance for any help or advice.
Sub BoldLastLine1()
Dim p As Long
Dim r As Range
For Each r In ActiveSheet.Range("A3:L100")
If Len(Trim(ActiveSheet.Cells(r, 12).Value)) <> 0 Then
p = InStrRev(r.Value, vbLf)
If p > 0 Then
With r.Characters(p + 1, Len(r.Value) - p).Font
.Bold = True
.Size = 16
End With
End If
End If
Next
MsgBox ("Updates Completed.")
End Sub
The cells-property of a worksheet or range expects 2 numeric parameter for row and column.
You are defining a Range r and passing it as first parameter, this causes the error.
You can use for example
If Len(Trim(ActiveSheet.Cells(r.Row, 12).Value)) Then
This points to the cell in column 12 (=L) of the row of range r
UPDATE:
Cells accepts also a string as second parameter, you could also write
If Len(Trim(ActiveSheet.Cells(r.Row, "L").Value)) Then

Shapes.AddPicture in Word Table

I am using a Word table as a placeholder for images, where table cells contain only pictures and no text.
When inserting a picture into a Word table, I have no problems when inserting an Inline Shape. The picture appears into the expected cell. However, with the "equivalent" code which inserts the picture as a Shape, the shape does not always appear in the expected cell. So far, I have seen this problem in Word 2013, 32 bit version.
Sub test()
Dim s As Shape
Dim x As String
Dim f As String
Dim r As Long
Dim c As Long
Dim h As Single
Dim w As Single
Dim rng As Word.Range
Dim ins As Word.InlineShape
f = "file name of a picture, .bmp .jpg etc."
Word.Application.ScreenUpdating = False
If Selection.Information(wdWithInTable) Then
' insert a picture in a table cell
r = Selection.Information(wdStartOfRangeRowNumber)
c = Selection.Information(wdStartOfRangeColumnNumber)
With Selection.Tables(1).Cell(r, c)
Set rng = .Range
rng.collapse wdCollapseStart
.Range.Text = ""
h = .height
w = .width
End With
' Works reliably
Set s = Word.Selection.InlineShapes.AddPicture(f, False, True, rng).ConvertToShape
s.height = h
s.width = w
' Not at all reliable
' Set s = Word.ActiveDocument.Shapes.AddPicture(f, False, True, 0, 0, w, h, rng)
Else
' insert a picture at the cursor
h = 100
w = 100
Set s = Word.ActiveDocument.Shapes.AddPicture(f, False, True, 0, 0, w, h)
End If
Word.Application.ScreenUpdating = True
s.WrapFormat.Type = wdWrapInline
s.Title = "Title"
s.AlternativeText = "Some metadata"
End Sub
The idea is to select either a cell in a table in a document or somewhere on the page outside of the table. The outside of the table case works as expected where the picture appears at the cursor location.
To see the problem, start with a fresh document, single page, add a 3 x 3 table and deepen the rows a bit. Be sure to supply a file to insert, variable f. Select one of the cells, then run the code. This works correctly when the picture is inserted as an inline shape then immediately converted to a shape. That happens with this line:
Set s = Word.Selection.InlineShapes.AddPicture(f, False, True, rng).ConvertToShape
However, the preferred solution would be to insert a Shape from the beginning with code something like this:
Set s = Word.ActiveDocument.Shapes.AddPicture(f, False, True, 0, 0, w, h, rng)
The picture appears, but usually not in the expected location. It could be placed into a different cell or somewhere outside the table.
Is the rng argument to Shapes.AddPicture being ignored or mangled somehow?
Experimenting some more with the 3 x 3 table - adding pictures then setting every possible WrapFormat.Type (there are 8 possible values), I see that:
for every WrapFormat.Type except wdWrapInLine, picture insertion works correctly as long as they are done from left to right on a table row, and;
for every WrapFormat.Type without exception, when the row is initially empty, pictures inserted in columns 2 or 3 appear one column to the left.
Making the picture smaller, such as setting h = .height * 0.5 and w = .width * 0.5, has no effect on placement.
Thanks very much for any insight or elucidation.
The main problem appears to be about the pictures inserting in the wrong column. This would be because the "focus point" (location of the Range) of an empty table cell has its starting point in the previous cell. Doesn't really make a lot of sense, but that's how Word works...
Try collapsing the Range to the End, rather than the Start (wdCollapseEnd) in this extract from your code:
With Selection.Tables(1).Cell(r, c)
Set rng = .Range
rng.collapse wdCollapseEnd 'instead of wdCollapseStart
.Range.Text = ""
h = .height
w = .width
End With
In the end, selective usage of rng.collapse did the trick. I have yet to check whether this behaviour is the same in Word 2010 or 2016.
For the first shape anywhere in a table row, rng.collapse wdCollapseEnd.
For all subsequent shapes on that table row, rng.collapse wdCollapseBegin.
I used the following code to count up the shapes in table rows:
Dim numShapes() As Integer
Dim cel As Word.cell
ReDim numShapes(1 To Selection.Tables(1).Rows.Count)
For Each cel In Selection.Tables(1).Range.Cells
If cel.Range.ShapeRange.Count <> 0 Then
numShapes(cel.RowIndex) = numShapes(cel.RowIndex) + 1
End If
Next cel
and the check is simply
If numShapes(r) <> 0 Then
rng.collapse wdCollapseStart
Else
rng.collapse wdCollapseEnd
End If
where r is the row number from the first code example.
Initial experiments with merged cells suggest other problems...

Change colors specfic range in words

I have an Excel sheet as shown below:
I want to change the color for characters in column E depending on the values of C and D.
The output should be like what's shown below:
Column C = 1
Column D = 3
So column E's color should change in positions 1 to 3.
You can use the Characters function to change attributes of certain characters within a cell's text. The second parameter to Characters() is the length, not the end, however, so you just need to do a little math to get from your example to where you need to be.
For example:
Dim r As Range, intStart As Long, intEnd As Long
For Each r In Range("E1:E3")
intStart = r.Offset(, -2)
intEnd = r.Offset(, -1)
r.Characters(intStart, intEnd - intStart + 1).Font.Color = RGB(255, 0, 0)
Next

How to get the height of a table row in Word

I've looked all over the place and tried various things. It's been assumed that it can't be done. So I'm going to try here and see if anybody else has had any luck.
Is there any way to get the height of a table row in Word when the row's HeightRule is set to wdRowHeightAuto?
Alternatively, if there's a way to get the cell's height instead, I'll accept that as a solution since you can calculate the row's height by finding the row's biggest cell.
It's possible to find the row height with Range.Information(). The following snippet doesn't work for the last row in a table or the last row on a page
Dim Tbl as Table
Dim RowNo as Integer
Dim RowHeight as Double
' set Tbl and RowNo to the table and row number you want to measure
RowHeight=Tbl.Rows(RowNo+1).Range.Information(wdVerticalPositionRelativeToPage) _
- Tbl.Rows(RowNo).Range.Information(wdVerticalPositionRelativeToPage)
This returns the height of the row in points by calculating the difference in position between the selected row and the following one.
I have a routine which works in all cases and returns the height in points of the second and subsequent lines in a cell, i.e. a single-line cell returns 0. (I use this in an application which reduces the font size in certain cells to fit the text on one line.)
Dim Doc As Document
Dim Tbl As Table
Dim Pos As Long
Dim RowNo As Integer
Dim ColNo As Integer
Dim CellHeight As Single
' set Doc, Tbl, RowNo and Colno to the document,table and row number you want to
' measure or provide a cell's range if you prefer
Pos = Tbl.Cell(RowNo, ColNo).Range.End - 1 ' last character in cell
CellHeight = Doc.Range(Pos, Pos).Information(wdVerticalPositionRelativeToTextBoundary)
How about cheating?
Dim tbl As Word.Table
Dim r As Row
Dim c As Cell
Set tbl = ActiveDocument.Tables(1)
For Each r In tbl.Rows
iHeight = r.HeightRule
r.HeightRule = 1
Debug.Print r.Height
r.HeightRule = iHeight
Next
I tried the above and found that changing the HeightRule changes the height of the row, which given I am trying to "freeze" the height on what appears in my table beforehand, makes nonsense of the above.
For rows which are empty or contain a single paragraph of unwrapped text in a consistent paragraph format adding up the font size, para before and after can work as follows:
Set r = c.Row
With r
If .HeightRule <> wdRowHeightExactly Then
.HeightRule = wdRowHeightExactly
Set p = c.Range.ParagraphFormat
.Height = c.BottomPadding + c.TopPadding + p.SpaceBefore + p.SpaceAfter + p.LineSpacing
End If
End With