Using Len(Dir) to check for picture file and insert into file - excel

I am trying to insert pictures into a column F. Links for picture files are listed in column C.
I researched on-line, and found a way.
If the file is there it works, if cell in column C is left blank it leaves the corresponding cell in column F blank, but if the link contains a file name does not exist it stops.
If the filename is corrupt = stated but not existing, I want to leave the cell blank and move on to the next cell.
Sub Insertpicture()
Dim myPict As Picture
Dim curWks As Worksheet
Dim myRng As Range
Dim myCell As Range
Set curWks = Sheets(1)
curWks.Pictures.Delete
With curWks
Set myRng = .Range("c2", .Cells(.Rows.Count, "c").End(xlUp))
End With
For Each myCell In myRng.Cells
If Trim(myCell.Value) = "" Then
‘do nothing, move on
ElseIf Len(Dir(myCell.Value)) = 0 Then
’here I want to leave the cell empty and just move on to check next cell
Else
With myCell.Offset(0, 3)
Set myPict = myCell.Parent.Pictures.Insert(myCell.Value)
myPict.Top = .Top
myPict.Width = .Width
myPict.Height = .Height
myPict.Left = .Left
myPict.Placement = xlMoveAndSize
End With
End If
Next myCell
End Sub

If the cell is empty, Dir(myCell.Value) will be the same thing as Dir(vbNullString), which will return the next result from your last Dir command. Since Dir holds state this way, it isn't the ideal way to determine if a file (or lack of a file) exists. I'd use the Scripting.FileSystemObject instead:
'Add a reference to Microsoft Scripting Runtime
Sub Insertpicture()
Dim myPict As Picture
Dim curWks As Worksheet
Dim myRng As Range
Dim myCell As Range
Set curWks = Sheets(1)
With curWks
.Pictures.Delete
Set myRng = .Range("c2", .Cells(.Rows.Count, "c").End(xlUp))
End With
With New Scripting.FileSystemObject
For Each myCell In myRng.Cells
If IsError(myCell.Value) Then
'do nothing, move on
ElseIf Not .FileExists(myCell.Value) Then
'leave the cell empty
myCell.Value = vbNullString
Else
With myCell.Offset(0, 3)
'You need to test to see if it's an image file here.
Set myPict = myCell.Parent.Pictures.Insert(myCell.Value)
myPict.Top = .Top
myPict.Width = .Width
myPict.Height = .Height
myPict.Left = .Left
myPict.Placement = xlMoveAndSize
End With
End If
Next myCell
End With
End Sub
Note that you also need to test for errors in the cells before you use the values and you should also either add error handling or test to see if the file you found was a valid image file.

Related

Adding Another Condition - Use ElseIf?

I am trying to add a line of code in VBA that will ask if the range has a value of HP-1 to then to make it 16 GA. else, it needs to be 26 GA.
Currently code just converts everything to 26 GA.
Sheets("TRIM").Select
Range("D13").Select
Do Until ActiveCell.Offset(0, -1).Value = ""
If ActiveCell.Value <> "" Then
ActiveCell.Value = "26 GA."
End If
ActiveCell.Offset(1, 0).Select
Loop EndIf
So I need to add in something that will do the HP-1 condition...I did try to make an Else statement but getting NO compile errors but getting this one.
this error has nothing to do with 32bit/64 bit as we are all still using 32bit Excel with 32bit VBA codeI'm sure it is pretty easy but can't seem to get the syntax down...
Any suggestions?
This is the original function in total...
Nest your If Statements:
Note: depending on your data layout, you may need to find a different way of defining RG, however, this should work.
Option Explicit
Sub Example()
Dim WS As Worksheet
Dim RG As Range
Dim CL As Range
Set WS = Worksheets("TRIM")
' Build Range "RG" from D13 to last used cell in D column
With WS
Set RG = .Range("D13", .Range("D" & Rows.Count).End(xlUp))
End With
' For each cell in the range "RG"
For Each CL In RG.Cells
If CL.Value <> "" Then 'Check if the value of the cell is ""
If CL.Value = "HP-1" Then 'Check if the value of the cell is "HP-1"
CL.Value = "16 GA" 'Change Value of the cell
Else
CL.Value = "26 GA" 'Change Value of the cell
End If
End If
Next CL
End Sub
Populate Cells Conditionally
Replace your code with the following.
Dim ws As Worksheet: Set ws = Sheets("TRIM")
If ws.Visible = xlSheetVisible Then
Dim cell As Range: Set cell = ws.Cells(ws.Rows.Count, "C").End(xlUp)
Dim rg As Range, rCount As Long
With ws.Range("D13")
rCount = cell.Row - .Row + 1
If rCount > 0 Then Set rg = .Resize(rCount)
End With
If Not rg Is Nothing Then ' data found
For Each cell In rg.Cells
If StrComp(CStr(cell.Value), "HP-1", vbTextCompare) = 0 Then
cell.Value = "16 GA."
Else ' is not 'HP-1'
cell.Value = "26 GA."
End If
Next cell
'Else ' no data found; do nothing!?
End If
'Else ' worksheet not visible; do nothing!?
End If

How to convert each line of text on the same cell to hyperlinks , Excel vba?

How to convert each line of text on the same cell to hyperlinks ?
the below code works correctly if cells has only one line of text !
Note: any workarounds is accepted
This link for the Sheet https://easyupload.io/wqmpkg
Sub Convert_To_Hyperlinks()
Dim Rng As Range
Dim WorkRng As Range
Dim LastRow As Long
Dim ws As Worksheet
Set ws = ActiveSheet
Set WorkRng = ws.Range("N2", ws.Cells(Rows.Count, "N").End(xlUp))
For Each Rng In WorkRng
Application.ActiveSheet.Hyperlinks.Add Rng, Rng.Value
Next Rng
End Sub
Excel allows only one hyperlink per cell. So, in order to do what you need, a workaround should be necessary. I would propose adding text boxes over each cell, placing the hyperlink text in them and add hyperlink to each text box.
Please, test the next code:
Sub testHyperlinkUsingShapes()
Dim sh As Worksheet, s As Shape, arrH, cHyp As Range, sHeight As Double
Dim rngHyp As Range, sWidth As Double, relTop As Double, i As Long
Set sh = ActiveSheet
Set rngHyp = sh.Range("N2:N" & sh.Range("N" & sh.Rows.Count).End(xlUp).Row)
'a little optimization to make the code faster:
Application.EnableEvents = False: Application.ScreenUpdating = False
deleteTextBoxes 'for the case when you need repeating the process (if manually changed some cells hyperling strings)
For Each cHyp In rngHyp.Cells 'iterate between cells of the range to be processed
If cHyp.Value <> "" Then 'process only not empty cells
arrH = filterSimilarH(cHyp) '1D array 1 based af unique hyperlink strings...
sHeight = cHyp.Height / UBound(arrH) 'set the height of the text boxes to be created
sWidth = cHyp.Width 'the same for the with
For i = 1 To UBound(arrH) 'for each found (unique) hyperlink strings:
'create a text box with dimensions set above
Set s = sh.Shapes.AddTextbox(msoTextOrientationHorizontal, cHyp.Left, cHyp.Top + relTop, sWidth, sHeight)
sh.Hyperlinks.Add Anchor:=s, Address:=arrH(i) 'add hyperlink address
With s
.TextFrame2.TextRange.Text = arrH(i) 'place the hyperlink string as the text box text
.TextFrame2.TextRange.Font.Size = cHyp.Font.Size 'match the font size with the cell one
.TextFrame2.TextRange.Font.Name = cHyp.Font.Name 'match the font type with the cell one
.TextFrame2.VerticalAnchor = msoAnchorMiddle 'center the text
.Line.ForeColor.ObjectThemeColor = msoThemeColorText1 'match the border line coloor with the cell one
.Placement = xlMoveAndSize
End With
s.Hyperlink.Address = arrH(i) 'set the hyperlink address
relTop = relTop + sHeight 'adapt the Top position for the next text box to be places in the same cell
Next i
relTop = 0 'reinitialize the top for the next cell
End If
Next
Application.EnableEvents = True: Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
Sub deleteTextBoxes() 'delete the existing text boxes, if any
Dim s As Shape
For Each s In ActiveSheet.Shapes
If s.Type = msoTextBox Then
If s.TopLeftCell.Column = 14 Then
s.Delete
End If
End If
Next
End Sub
Function filterSimilarH(rngCel As Range) As Variant
Dim arr, uniques: arr = Split(rngCel.Value, vbLf) 'keep only unique hyperlinks, if duplicates exist
With Application
uniques = .Index(arr, 1, Filter(.IfError(.Match(.Transpose(.Evaluate("ROW(1:" & _
UBound(.Match(arr, arr, 0)) & ")")), .Match(arr, arr, 0), 0), "|"), "|", False))
End With
filterSimilarH = uniques
End Function
As told by others, in one cell you can have only one hyperlink.
Note: You have in some cells the same attachment name duplicated!
I quote what you said "is it possible to split cells with multi lines to adjacent cells and converts to hyperlinks afterwards", so this code might do what you need.
Sub Convert_To_Hyperlinks()
Dim rng As Range
Dim WorkRng As Range
Dim LastRow As Long
Dim ws As Worksheet: Set ws = ActiveSheet
Dim i As Integer
Dim lastCol As Long
Dim arrStr() As String
Set WorkRng = ws.Range("N2", ws.Cells(Rows.Count, "N").End(xlUp))
For Each rng In WorkRng
' find last column for current row
lastCol = ws.Cells(rng.Row, Columns.Count).End(xlToLeft).Column
If InStr(1, rng.Value, Chr(10)) > 0 Then
' multiple attachments: split text into array
arrStr = Split(rng.Value, Chr(10))
' copy array after last column
Cells(rng.Row, lastCol + 1).Resize(1, UBound(arrStr) - LBound(arrStr) + 1) = arrStr
' create hyperlink
For i = LBound(arrStr) To UBound(arrStr)
Application.ActiveSheet.Hyperlinks.Add Cells(rng.Row, lastCol + 1 + i), arrStr(i)
Next i
ElseIf rng.Value <> "" Then
' only one attachment: copy range value after last column
Cells(rng.Row, lastCol + 1).Value = rng.Value
' create hyperlink
Application.ActiveSheet.Hyperlinks.Add Cells(rng.Row, lastCol + 1), rng.Value
End If
Next rng
End Sub

Way to tell if ActiveSheet.Pictures.Insert(Filename).Select Fails?

I have made an excel macro for my company that mass inserts images in a picture folder by their cell value.
The cell.Value contains the SKU number, so I add the rest of the file path in a for each loop and then use ActiveSheet.Pictures.Insert(Filename).Select.
Everything works great, but when files are not found within the picture folder, the filepath is left in the cell. I would like to change all cells that don't find an image to say "No Image" rather than the filepath.
Is there anyway to test if ActiveSheet.Pictures.Insert(Filename).Select failed to find an image, then I could rewrite the cell.Value if it failed?
I've tried to add another For each loop to see if the cell.Value has contents in it. This is because the insert image portion runs a cell.ClearContents once it's done so all the cells with images inserted don't have their SKU numbers behind the image. I'm having trouble with this process as well and would like to avoid for eaching through the selection twice.
Option Explicit
Dim rng As Range
Dim cell As Range
Dim Filename As String
Sub PictureImport()
Set rng = ActiveSheet.Range("A2:A3000")
For Each cell In Selection '<-- *For Each cell In rng* For Hard Coded selection
If cell.Value <> "" Then cell.Value = "\\Pictures\" & cell.Value & ".jpg" '<---NEEDS TO SKIP HEADER
Next
Dim theShape As Shape
Dim xRg As Range
Dim xCol As Long
On Error Resume Next
Application.ScreenUpdating = False
Set rng = ActiveSheet.Range("A2:A3000") ' <---- CHANGE TO START AT A2 TO SKIP HEADER
For Each cell In Selection
Filename = cell
If InStr(UCase(Filename), "JPG") > 0 Then '<--- ONLY USES JPG'S
ActiveSheet.Pictures.Insert(Filename).Select
Set theShape = Selection.ShapeRange.Item(1)
If theShape Is Nothing Then GoTo isnill
xCol = cell.Column
Set xRg = Cells(cell.Row, xCol)
With theShape
.LockAspectRatio = msoFalse
' Shape position and sizes stuck to cell shape
.Top = cell.Top + 1
.Left = cell.Left + 1
.Height = cell.Height - 2
.Width = cell.Width - 2
' Move with the cell (and size, though that is likely buggy)
.Placement = xlMoveAndSize
End With
cell.ClearContents
isnill:
Set theShape = Nothing
Range("A2").Select
End If
Next
Debug.Print "Done " & Now
Application.ScreenUpdating = True
End Sub
Actual Results as stands: Images in the pictures folder will be inserted to the size of the cell, but will leave the cells that could not find a picture with the file path still in the the cell value.

In range find this and do that

Have a range of cell with column headings as weeks In the range of cells I want to look for a number, say
1 if it finds a 1 then look at a column in said row for a variable, 2 or 4 whatever Now I want to put a triangle (can be copy and paste a cell) in the cell that has the "1" in it then skip over the number of week variable and add another triangle and keep doing this until the end of the range. Then skip down to the next row and do the same, until the end of the range.
Then change to the next page and do the same thing... through the whole workbook.
I think I have it done, don't know if it's the best way.
I get a error 91 at the end of the second loop, the first time the second loop ends it goes through the error code.
The second time the second loop ends it errors.
I don't understand it runs through once, but not twice.
Sub Add_Triangles2()
Dim Rng As Range
Dim OffNumber As Integer
Dim SetRange As Range
Dim OffsetRange As Range
Dim ws As Worksheet
Set SetRange = Sheets("Sheet1").Range("G25") ' Used to stop the second loop in range
Worksheets(1).Activate
Worksheets(1).Range("A1").Select ' Has item to be pasted (a triangle)
Selection.Copy
For Each ws In Worksheets
Worksheets(ws.Name).Activate
With Range("C4:G25")
Set Rng = .Find(1, LookIn:=xlValues)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Rng.Activate
ActiveSheet.Paste
Do
OffNumber = Range("A" & ActiveCell.Row)
Set OffsetRange = SetRange.Offset(0, -OffNumber)
If Not ActiveCell.Address < OffsetRange.Address Then
Exit Do
Else
End If
ActiveCell.Offset(, OffNumber).Select
ActiveSheet.Paste
Loop While (ActiveCell.Address <= OffsetRange.Address)
On Error GoTo ErrorLine
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
End With
ErrorLine:
On Error GoTo 0
Application.EnableEvents = True
Next ws
Application.CutCopyMode = False
End Sub
I was not able to get an Error 91 using the data set I built from your explanation, maybe a screenshot of the layout could help recreate the issue.
However, I would do something like this, it will look at the value of each cell in the range C4:G25, and if it equals 1, it will paste the symbol stored in Cell A1.
Sub Add_Triangles2()
Dim Rng As Range
Dim rngSymbol As Range
Dim intFindNum As Integer
Dim ws As Worksheet
Set rngSymbol = Range("A1") 'Set range variable to hold address of symbol to be pasted
intFindNum = 1 'Used to hold number to find
Worksheets(1).Activate
For Each ws In Worksheets
Worksheets(ws.Name).Activate
For Each Rng In Range("C4:G25")
If Rng.Value = intFindNum Then
rngSymbol.Copy Rng
End If
Next Rng
Next ws
End Sub
I got it....
Sub Add_TriWorking()
Dim Rng As Range
Dim rngSymbol As Range
Dim intFindNum As Integer
Dim ws As Worksheet
Dim OffNumber As Integer
Dim SetRange As Range
Dim OffsetRange As Range
Set SetRange = Sheets("Sheet1").Range("G25") ' Used to stop the second loop in range
Set rngSymbol = Range("A1") 'Set range variable to hold address of symbol to be pasted
intFindNum = 1 'Used to hold number to find
Worksheets(1).Activate
For Each ws In Worksheets
Worksheets(ws.Name).Activate
For Each Rng In Range("C4:G25")
If Rng.Value = intFindNum Then
rngSymbol.Copy Rng
Rng.Activate
ActiveCell.Copy
Do
OffNumber = Range("A" & ActiveCell.Row)
Set OffsetRange = SetRange.Offset(0, -OffNumber)
If Not ActiveCell.Address < OffsetRange.Address Then
Exit Do
Else
End If
ActiveCell.Offset(, OffNumber).Select
ActiveSheet.Paste
Loop While (ActiveCell.Address <= OffsetRange.Address)
On Error GoTo ErrorLine
End If
Next Rng
ErrorLine:
On Error GoTo 0
Application.EnableEvents = True
Next ws
Application.CutCopyMode = False
End Sub

Excel autofit row height doesn't work on meged cells with word wrap

I'm programmatically inserting some text into merged cells in a row. I have Wrap Text set and want the row height to expand as necessary to accommodate multiple lines of text. I was programmatically applying AutoFit once the cells had been filled but that didn't work. I subsequently found a Knowledge Base article saying the AutoFit doesn't work for merged cells! I can try to compute the row height required to accommodate the number of lines of wrapping text. But I don't really want to climb into calculating character widths etc. Any ideas gratefully appreciated.
Question credit goes to David (I had the exact same question, just reposting here for posterity) source
I found a VB macro here that will simulate the autofit of any merged cells on the active sheet. Source credits parry from MrExcel.com
Sub AutoFitMergedCellRowHeight()
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
Dim StartCell As Range, c As Range, MergeRng As Range, Cell As Range
Dim a() As String, isect As Range, i
'Take a note of current active cell
Set StartCell = ActiveCell
'Create an array of merged cell addresses that have wrapped text
For Each c In ActiveSheet.UsedRange
If c.MergeCells Then
With c.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
If MergeRng Is Nothing Then
Set MergeRng = c.MergeArea
ReDim a(0)
a(0) = c.MergeArea.Address
Else
Set isect = Intersect(c, MergeRng)
If isect Is Nothing Then
Set MergeRng = Union(MergeRng, c.MergeArea)
ReDim Preserve a(UBound(a) + 1)
a(UBound(a)) = c.MergeArea.Address
End If
End If
End If
End With
End If
Next c
Application.ScreenUpdating = False
'Loop thru merged cells
For i = 0 To UBound(a)
Range(a(i)).Select
With ActiveCell.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
'Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = ActiveCell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
MergedCellRgWidth = 0
Next i
StartCell.Select
Application.ScreenUpdating = True
'Clean up
Set CurrCell = Nothing
Set StartCell = Nothing
Set c = Nothing
Set MergeRng = Nothing
Set Cell = Nothing
End Sub

Resources