I have managed to pull together some VBA code from other sources (many thanks) to create something that is about 80% complete. However when I send or open my spreadsheet on another computer my pictures do not appear (just a red X).
My research has lead me to use and insert the
ActiveSheet.Shapes.AddPicture method however I am unsure how to build this into my functioning code / where to place this. I have filenames in Column D which relate to the stored pictures from my folder. The pictures are loaded into Column C and this allworks perfectly, I have approx 550 jpeg files. However I cannot view the images once it's off my computer
My working code is:
Sub InsertPicsr1Reg()
Dim fPath As String, fName As String
Dim r As Range
Dim shp As Shape
Application.ScreenUpdating = False
fPath = "\Desktop\test workings\"
For Each r In Range("D2:D" & Cells(Rows.Count, 4).End(xlUp).Row)
On Error GoTo errHandler
If r.Value <> "" Then
With ActiveSheet.Pictures.Insert(fPath & r.Value)
.ShapeRange.LockAspectRatio = msoTrue
.Top = Cells(r.Row, 3).Top
.Left = Cells(r.Row, 3).Left
If .ShapeRange.Width > Columns(3).Width Then .ShapeRange _
.Width = Columns(3).Width
Rows(r.Row).RowHeight = .ShapeRange.Height
End With
End If
errHandler:
If Err.Number <> 0 Then
Debug.Print Err.Number & ", " & Err.Description & ", " & r.Value
On Error GoTo -1
End If
Next r
For Each shp In ActiveSheet.Shapes
shp.Placement = xlMoveAndSize
Next shp
Application.ScreenUpdating = True
End Sub
try this:
Sub InsertPicsr1Reg()
Dim fPath As String, fName As String
Dim r As Range
Dim shp As Shape
Application.ScreenUpdating = False
fPath = "\Desktop\test workings\"
For Each r In Range("D2:D" & Cells(Rows.Count, 4).End(xlUp).Row)
If r.Value <> "" Then
With ActiveSheet
.Shapes.AddPicture fPath & r.Value, _
msoFalse, msoTrue, _
.Cells(r.Row, 3).Left, _
.Cells(r.Row, 3).Top, _
.Columns(3).Width, _
.Rows(r.Row).Height
End With
end if
next
end sub
Related
I am trying to generate CSV files from a set of records from Excel.
Column A is the file name and the rest of the columns are the data to write to the the file.
As of now, I am using WriteLine, but it doesn't work as expected:
As you can see, I don't get the expected output. How do I get the expected output?
Private Sub ommandButton1_Click()
Dim Path As String
Dim Folder As String
Dim Answer As VbMsgBoxResult
Path = "C:\Access Permissions\Users"
Folder = Dir(Path, vbDirectory)
If Folder = vbNullString Then
'-------------Create Folder -----------------------
MkDir ("C:\Access Permissions")
MkDir ("C:\Access Permissions\Roles")
MkDir ("C:\Access Permissions\Users")
Else
Set rngSource = Range("A4", Range("A" & Rows.Count).End(xlUp))
rngSource.Copy Range("AA1")
Range("AA:AA").RemoveDuplicates Columns:=1, Header:=xlNo
Set rngUnique = Range("AA1", Range("AA" & Rows.Count).End(xlUp))
Set lr = Cells(rngSource.Rows.Count, rngSource.Column)
Set fso = CreateObject("Scripting.FileSystemObject")
For Each cell In rngUnique
n = Application.CountIf(rngSource, cell.Value)
Set C = rngSource.Find(cell.Value, lookat:=xlWhole, after:=lr)
Set oFile = fso.CreateTextFile("C:\Access Permissions\Users\" & cell.Value & "-Users.csv")
For i = 1 To n
oFile.WriteLine C.Offset(0, 1).Value
oFile.WriteLine C.Offset(0, 2).Value
oFile.WriteLine C.Offset(0, 3).Value
oFile.WriteLine C.Offset(0, 4).Value
oFile.WriteLine C.Offset(0, 6).Value
oFile.WriteLine C.Offset(0, 7).Value
Set C = rngSource.FindNext(C)
Next i
Next cell
rngUnique.ClearContents
MsgBox "Individual Users.csv files got generated" & vbCrLf & " " & vbCrLf & "Path - C:\Access Permissions\Groups "
End If
End Sub
Updated Image:
Let me re-phrase my questions.
Updated Image Enclosed.
Using the Data Set [Updated Image point 1], It creates unique CSV files based on column A.
File got saved at the path given.
As of now the row data associated with each file name got written in the files but in a new line manner.
As expected, how the output can be written in Columns.[ Updated Image Point 4]
Given code is working without any error.
5.1. I just need to click twice if the Path folder does not exist.
5.2. at first click, it creates the Folder at the given path.
5.3. at Second click it generates the unique files, with its records.
If you can please guide me on how the records can be written in columns [ Updated Image Point 4 ], expected output.
Download File
I assume your data does not contain any semicolons.
You are writing each field on a line by itself. Instead, join the fields on a single line:
oFile.WriteLine C.Offset(0, 1).Value & ";" & _
C.Offset(0, 2).Value & ";" & _
C.Offset(0, 3).Value & ";" & _
C.Offset(0, 4).Value & ";" & _
C.Offset(0, 6).Value & ";" & _
C.Offset(0, 7).Value
There are other bugs in your example; it should not work as far as I can see. For example, you keep opening the same file with CreateTextFile. You should only create a file once, not every time you write to it. According to the documentation, you should get an error on your second try, see CreateTextFile method. The reason you don't get an error is probably because you never close the file. You should close the files you create.
I would use this approach instead:
' Collect the data for each file into a dictionary.
' The cells in the table must not contain semicolons.
Sub Doit()
Dim Sht As Worksheet
Dim Rng As Range
Dim LastRowNum As Long, LastColNum As Long
Dim Lst As Variant, Hdr As Variant, Elem As Variant
Dim Idx As Long, Idx2 As Long
Dim Dct As Object
Dim HdrTxt, Txt As String, Sep As String
Dim Filename As String
Set Sht = ActiveSheet
' Get the last row in column 1
Set Rng = Sht.Cells(Sht.Rows.Count, 1).End(xlUp)
LastRowNum = Rng.Row
' Get the last column in row 3
Set Rng = Sht.Cells(3, Sht.Columns.Count).End(xlToLeft)
LastColNum = Rng.Column
' Get the headers in row 3
Set Rng = Sht.Range(Sht.Cells(3, 1), Sht.Cells(3, LastColNum))
Hdr = Rng
' Create a semicolon seprated line for the headers
HdrTxt = ""
Sep = ""
For Idx = LBound(Hdr, 2) To UBound(Hdr, 2)
HdrTxt = HdrTxt & Sep & Hdr(1, Idx)
Sep = ";"
Next Idx
HdrTxt = HdrTxt & vbNewLine
' Get the data from row 4 and down
Set Rng = Sht.Range(Sht.Cells(4, 1), Sht.Cells(LastRowNum, LastColNum))
Lst = Rng
' Store the data for each file in a dicitonary
Set Dct = CreateObject("Scripting.Dictionary")
For Idx = LBound(Lst) To UBound(Lst)
Filename = Lst(Idx, 1)
' Create a semicolon seprated line
Txt = ""
Sep = ""
For Idx2 = LBound(Lst, 2) To UBound(Lst, 2)
Txt = Txt & Sep & Lst(Idx, Idx2)
Sep = ";"
Next Idx2
Txt = Txt & vbNewLine
' Add the line to the dictionary
If Dct.Exists(Filename) Then
Dct(Filename) = Dct(Filename) & Txt
Else
Dct(Filename) = HdrTxt & Txt
End If
Next Idx
' Output data for each file to the immdiate window
For Each Elem In Dct
' Change this to open the file and write the contents
Debug.Print "---- Filename: " & Elem
Debug.Print Dct(Elem)
Next Elem
End Sub
The example makes sure you only create the files once:
Change the last loop For Each Elem In Dct that prints the data to the immediate window, to create a file instead. Use the Write method instead of the WriteLine method, as the data already contains the line-breaks. And remember to Close the files.
I think this is what you want.
Sub Copy_To_Workbooks()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim MyPath As String
Dim foldername As String
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
'and the header of the first column, D is the last column in the filter range.
'You can also add the sheet name to the code like this :
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A1:B" & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new workbook"
Exit Sub
End If
'This example filters on the first column in the range(change the field if needed)
'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
FieldNum = 1
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Set the file extension/format
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".txt": FileFormatNum = -4143
Else
'You use Excel 2007-2010
If ActiveWorkbook.FileFormat = 56 Then
FileExtStr = ".txt": FileFormatNum = 56
Else
FileExtStr = ".txt": FileFormatNum = 51
End If
End If
'Change ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Delete the sheet RDBLogSheet if it exists
On Error Resume Next
Application.DisplayAlerts = False
Sheets("RDBLogSheet").Delete
Application.DisplayAlerts = True
On Error GoTo 0
' Add worksheet to copy/Paste the unique list
Set ws2 = Worksheets.Add(After:=Sheets(Sheets.Count))
ws2.Name = "RDBLogSheet"
'Fill in the path\folder where you want the new folder with the files
'you can use also this "C:\Users\Ron\test"
MyPath = "C:\Users\ryans\OneDrive\Desktop\"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'Create folder for the new files
foldername = MyPath & Format(Now, "yyyy-mm-dd hh-mm-ss") & "\"
MkDir foldername
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A3"), Unique:=True
'loop through the unique list in ws2 and filter/copy to a new sheet
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A4:A" & Lrow)
'Filter the range
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Check if there are no more then 8192 areas(limit of areas)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "There are more than 8192 areas for the value : " & cell.Value _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Split in worksheets"
Else
'Add new workbook with one sheet
Set WSNew = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
'Copy/paste the visible data to the new workbook
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 will copy the columnwidth in Excel 2000 and higher
' Remove this line if you use Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
'Save the file in the new folder and close it
On Error Resume Next
ChDir MyPath
ActiveWorkbook.SaveAs Filename:= _
foldername & cell.Value & ".txt", _
FileFormat:=xlTextMSDOS, CreateBackup:=False
If Err.Number > 0 Then
Err.Clear
ErrNum = ErrNum + 1
WSNew.Parent.SaveAs foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr, FileFormatNum
.Cells(cell.Row, "B").Formula = "=Hyperlink(""" & foldername & _
"Error_" & Format(ErrNum, "0000") & FileExtStr & """)"
.Cells(cell.Row, "A").Interior.Color = vbRed
Else
.Cells(cell.Row, "B").Formula = _
"=Hyperlink(""" & foldername & cell.Value & FileExtStr & """)"
End If
WSNew.Parent.Close False
On Error GoTo 0
End If
'Show all the data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
.Cells(1, "A").Value = "Red cell: can't use the Unique name as file name"
.Cells(1, "B").Value = "Created Files (Click on the link to open a file)"
.Cells(3, "A").Value = "Unique Values"
.Cells(3, "B").Value = "Full Path and File name"
.Cells(3, "A").Font.Bold = True
.Cells(3, "B").Font.Bold = True
.Columns("A:B").AutoFit
End With
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
& vbNewLine & "There are characters in the name that are not allowed" _
& vbNewLine & "in a sheet name or the worksheet already exist."
End If
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
ws2.Select
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Before:
After:
I have a code for inserting an attached file to a certain column and resizing it so that it perfectly fills the cell. Only problem I have now is that the object is just a blank rectangle and hard to spot if there is even anything in the cell.
I've tried IconLabel:=Range("A" & ActiveCell.Row) so that it shows the ID # of the row but it seems to show it very stretched out and to the point where you can't see anything.
Sub Macro1()
Range("X" & ActiveCell.Row).Select
Dim vFile As Variant, Sh As Object
vFile = Application.GetOpenFilename("All Files,*.*", Title:="Find file to insert")
If vFile = False Then Exit Sub
Dim OleObj As OLEObject
Set OleObj = ActiveSheet.OLEObjects.Add(Filename:=vFile, Link:=False, DisplayAsIcon:=True, IconFileName:= _
"C:\WINDOWS\Installer\{90110409-6000-11D3-8CFE-0150048383C9}\xlicons.exe", _
IconIndex:=0, IconLabel:=Range("A" & ActiveCell.Row).Value)
OleObj.ShapeRange.LockAspectRatio = msoFalse
OleObj.Height = Range("X" & ActiveCell.Row).Height
OleObj.Width = Range("X" & ActiveCell.Row).Width
End Sub
This would make the cell red, because of the vbRed, furthermore, it would be about 4 times less than the standard cell:
With OleObj
.ShapeRange.LockAspectRatio = msoFalse
.Height = Range("X" & ActiveCell.Row).Height / 2
.Width = Range("X" & ActiveCell.Row).Width / 2
.Interior.Color = vbRed
End With
Thus, it would be different and visible. These are the other built-in colors, from the VBA library (Press F2):
I have code which inserts images from the given path using specific set of numbers against which I already have an image database.
Sub InsertPics()
Dim fPath As String, fName As String
Dim r As Range, rng As Range
Dim shpPic As Shape
Application.ScreenUpdating = False
fPath = "C:\Users\DELL\Documents\FY18-19\Images\"
Set rng = Range("D2:D" & Cells(Rows.Count, 4).End(xlUp).Row)
For Each r In rng
On Error GoTo errHandler
If r.Value <> "" Then
Set shpPic = ActiveSheet.Shapes.AddPicture(Filename:=fPath & r.Value & ".jpg", linktofile:=msoFalse, _
savewithdocument:=msoTrue, Left:=Cells(r.Row, 2).Left, Top:=Cells(r.Row, 2).Top, Width:=-1, Height:=-1)
With shpPic
.LockAspectRatio = msoTrue
If .Width > Columns(2).Width Then .Width = Columns(2).Width
Rows(r.Row).RowHeight = .Height
End With
End If
errHandler:
If Err.Number <> 0 Then
Debug.Print Err.Number & ", " & Err.Description & ", " & r.Value
On Error GoTo -1
End If
Next r
Application.ScreenUpdating = True
End Sub
I need to do the below as well:
ask the file path
ask whether to insert the image as image or as a comment against those set of numbers and run accordingly
If the code can be converted into a select mode run, i.e. on a set of numbers I can run the code for (instead of the entire 'D'-Column I've embedded currently).
May try this code and modify to your requirement.
Sub InsertPics()
Dim fPath As String, fName As String
Dim r As Range, rng As Range
Dim shpPic As Shape, IsCmnt As VbMsgBoxResult
'Application.ScreenUpdating = False
Set rng = ThisWorkbook.ActiveSheet.Range("D2:D" & Cells(Rows.Count, 4).End(xlUp).Row)
On Error GoTo Xexit
Set rng = Application.InputBox("Select the range to import Images", "Import Image", rng.Address, , , , , 8)
On Error GoTo 0
If rng Is Nothing Then Exit Sub
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = " Select Folder to Upload Images"
.AllowMultiSelect = False
.InitialFileName = "C:\Users\user\DeskTop\"
If .Show <> -1 Then Exit Sub
fPath = .SelectedItems(1)
End With
fPath = fPath & "\"
'Avoided further asking wheather all Images are to be uploaded as Comment
'instead used bold font of the file names to do the same
'try Next statement, if want all the images as comment
'IsCmnt = MsgBox("Is the images to be uploaded as comments", vbYesNo)
For Each r In rng
If r.Value <> "" Then
If Dir(fPath & r.Value & ".jpg") <> "" Then
'If IsCmnt = vbYes Then 'try this branch if want all the images as comment
If r.Font.Bold Then ' instead of asking multiple times
r.ClearComments
r.AddComment ""
r.Comment.Shape.Fill.UserPicture fPath & r.Value & ".jpg"
Else
Set shpPic = ActiveSheet.Shapes.AddPicture(Filename:=fPath & r.Value & ".jpg", linktofile:=msoFalse, _
savewithdocument:=msoTrue, Left:=Cells(r.Row, 2).Left, Top:=Cells(r.Row, 2).Top, Width:=-1, Height:=-1)
With shpPic
.LockAspectRatio = msoTrue
If .Width > Columns(2).Width Then .Width = Columns(2).Width
Rows(r.Row).RowHeight = .Height
End With
End If
Else
Debug.Print fPath & r.Value & ".jpg not found"
End If
End If
Next r
Xexit:
'Application.ScreenUpdating = True
End Sub
Code is tested with makeshift images. May disable ScreenUpdatingas per actual condition.
Please bear with me. My code is probably complete shit, so I appreciate all feedback! So what this does is, on my main workbook, there are a bunch of UNC hyperlinks in Row M, that link to files in a section drive.
What this code does:
Go down the list of hyperlinks in Column M, opens them up and executes the code inside of the "With WBSsource".
First, it searches for instances of the incorrect filepath (st) inside each of the cells formulas (NOT VALUES), and increments a counter using InStr (t), then after the worksheet has been searched, if the final count (c) is more than 0, meaning the search found at least one incorrect filepath, it will proceed to the next step.
It does a Cells.Replace on a worksheet (ws.) basis (at the FORMULA level)
Cells per worksheet are all done, it should save the workbook and close it before moving onto the next one.
Any links that could not be opened will appear in a final popup.
It is by Step 3 that it starts to run sluggish and crash.
I'm trying my best to get this automated and saving the workbooks. Then, once they're all updated, running this code again would be much faster cause it won't have to replace everything again.
Sub List_UpdateAndSave()
Dim lr As Long
Dim i As Integer
Dim WBSsource As Workbook
Dim FileNames As Variant
Dim msg As String
Dim ws As Worksheet
Dim r As Range, t As Long, c As Integer
' Update the individual credit models
With ThisWorkbook.ActiveSheet
lr = .Cells(.Rows.Count, "M").End(xlUp).Row
FileNames = .Range("M2:M" & lr).Value
End With
For i = LBound(FileNames, 1) To UBound(FileNames, 1)
On Error Resume Next
If FileNames(i, 1) Like "*.xls*" Then
Set WBSsource = Workbooks.Open(FileNames(i, 1), _
ReadOnly:=False, _
Password:="", _
UpdateLinks:=3)
If Err = 0 Then
With WBSsource
Application.DisplayAlerts = False
ActiveWorkbook.Final = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
st = "\\corp\Accounts\" 'Search Phrase
n = "\\corp\StackOverflow\Accounts\" 'New Phrase
c = 0
For Each ws In WBSsource.Worksheets
ws.Activate
t = 0
On Error Resume Next
For Each r In ws.Cells.SpecialCells(xlCellTypeFormulas)
t = InStr(1, r.Formula, st)
If t > 0 Then
c = c + 1
End If
Next r
Next ws
If c > 0 Then
'MsgBox ws.Name & Chr(10) & (c)
ws.Cells.Replace st, n
End If
.UpdateLink Name:=ActiveWorkbook.LinkSources, Type:=xlExcelLinks
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
.Save
.Close True
End With
Else
msg = msg & FileNames(i, 1) & Chr(10) & Chr(10)
On Error GoTo 0
End If
End If
Set WBSsource = Nothing
Next i
If Len(msg) > 0 Then
'MsgBox "The Following Files Could Not Be Opened" & _
' Chr(10) & msg, 48, "Error"
Set objShell = CreateObject("Wscript.Shell")
objShell.Popup "The Following Files Could Not Be Opened" & _
Chr(10) & Chr(10) & msg, 48, "Error"
End If
Application.DisplayAlerts = True
End Sub
It's not completely crap. I just learned that we could create an array with this.
FileNames = .Range("M2:M" & lr).Value
It may crash since there's no range limit on the 3rd step. Try getting the last row and column on each worksheet, then create a range based on that.
With ws
' Get end cells
With .Cells.SpecialCells(xlCellTypeLastCell)
intLastRow = .Row
intLastCol = .Column
End With
For each r in .Range(.Cells(1,1), .Cells(intLastRow, intLastCol))
' Check formula if it contains specific string
t = InStr(1, r.Formula, st)
If t > 0 Then
c = c + 1
End If
' Replace formula with new string
r.Formula = Replace(r.Formula, st, n)
Next r
End With
Edit: Here's the full code. Let me know if this works for you.
Option Explicit
' Update the individual credit models
Sub List_UpdateAndSave()
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
On Error GoTo ErrorHandler
' Declaration
Dim i As Long
Dim arrLinks As Variant
Dim strLinksErr As String
' Initialization
Dim strPathCur As String: strPathCur = "\\corp\Accounts\" ' search phrase
Dim strPathNew As String: strPathNew = "\\corp\StackOverflow\Accounts\" ' new phrase
With ThisWorkbook.ActiveSheet
' Get links from sheet
arrLinks = .Range("M2:M" & .Cells.SpecialCells(xlCellTypeLastCell).Row).Value
End With
For i = LBound(arrLinks, 1) To UBound(arrLinks, 1)
' Check for Excel links
If VBA.InStr(1, arrLinks(i, 1), ".xls", vbTextCompare) > 0 Then
FnExcelUpdateLinks arrLinks(i, 1), strPathCur, strPathNew
Else
' Add to list of links that could not be opened
strLinksErr = strLinksErr & arrLinks(i, 1) & Chr(10)
End If
Next i
ErrorHandler:
' Display any errors
If Err.Number <> 0 Then MsgBox Err.Description, vbCritical, "Error " & Err.Number
' Display any non-Excel links
If strLinksErr <> "" Then
MsgBox "The following files could not be opened:" & _
Chr(10) & strLinksErr, 48, "Error"
End If
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Function FnExcelUpdateLinks(ByVal strWbkPath As String, ByRef strPathCur As String, ByRef strPathNew As String)
Dim intLastRow As Long, intLastCol As Long
Dim wbkTmp As Workbook
Dim shtTmp As Worksheet
Dim rngCell As Range
' Open link as workbook
Set wbkTmp = Workbooks.Open(strWbkPath, ReadOnly:=False, Password:="", UpdateLinks:=3)
With wbkTmp
For Each shtTmp In .Worksheets
With shtTmp
' Get end cells
With .Cells.SpecialCells(xlCellTypeLastCell)
intLastRow = .Row
intLastCol = .Column
End With
For Each rngCell In .Range(.Cells(1, 1), .Cells(intLastRow, intLastCol))
If VBA.InStr(1, rngCell.Formula, strPathCur) > 0 Then
rngCell.Formula = Replace(rngCell.Formula, strPathCur, strPathNew)
End If
Next rngCell
End With
Next shtTmp
.UpdateLink Name:=.LinkSources, Type:=xlExcelLinks
.Save
.Close True
End With
End Function
Thanks to Macromarc This Problem has been resolved
The problem i had with my code was it was only putting in the picture to a cell, and the picture was sized incorrectly. When i filtered my data the pictures always collapsed into each other and it did not look too great.
Below is the correct code that will work for you thanks to Macromarc
Private Sub GrabImagePasteIntoCell()
Const pictureNameColumn As String = "A" 'column where picture name is found
Const picturePasteColumn As String = "J" 'column where picture is to be pasted
Const pathForPicture As String = "M:\Users\Dan\Pictures\LabPics\" 'path of pictures
Dim pictureFile As String
Dim pictureName As String 'picture name
Dim lastPictureRow As Long 'last row in use where picture names are
Dim pictureRow As Long 'current picture row to be processed
Dim picturePasteCell As Range
pictureRow = 3 'starts from this row
On Error GoTo Err_Handler
Dim ws As Worksheet
Set ws = ActiveSheet 'replace with better qualification
lastPictureRow = ws.Cells(ws.Rows.Count, pictureNameColumn).End(xlUp).Row
'stop screen updates while macro is running
Application.ScreenUpdating = False
'loop till last picture row
Do While (pictureRow <= lastPictureRow)
pictureName = ws.Cells(pictureRow, pictureNameColumn).Value2
If (pictureName <> vbNullString) Then
'check if pic is present
pictureFile = pathForPicture & pictureName
Set picturePasteCell = ws.Cells(pictureRow, picturePasteColumn)
If (Dir(pictureFile & ".jpg") <> vbNullString) Then
insertPictureToComment pictureFile & ".jpg", picturePasteCell, 41, 41
ElseIf (Dir(pictureFile & ".png") <> vbNullString) Then
insertPictureToComment pictureFile & ".png", picturePasteCell, 100, 130
ElseIf (Dir(pictureFile & ".bmp") <> vbNullString) Then
insertPictureToComment pictureFile & ".bmp", picturePasteCell, 100, 130
Else
'picture name was there, but no such picture
picturePasteCell.Value2 = "No Picture Found"
End If
Else
'picture name cell was blank
End If
pictureRow = pictureRow + 1
Loop
On Error GoTo 0
Exit_Sub:
ws.Range("A10").Select
Application.ScreenUpdating = True
Exit Sub
Err_Handler:
MsgBox "Error encountered. " & Err.Description, vbCritical, "Error"
GoTo Exit_Sub
End Sub
The function below handles the insertion of generic images to a cell's comment shape:
Function insertPictureToComment(pictureFilePath As String, _
pictureRange As Range, _
commentHeight As Long, _
commentWidth As Long)
Dim picComment As Comment
If pictureRange.Comment Is Nothing Then
Set picComment = pictureRange.AddComment
Else
Set picComment = pictureRange.Comment
End If
With picComment.Shape
.Height = commentHeight
.Width = commentWidth
.LockAspectRatio = msoFalse
.Fill.UserPicture pictureFilePath
End With
End Function
I rewrote some of the other code, and refactored out a function.
Tested and it is basically working for me. Any questions ask:
Private Sub GrabImagePasteIntoCell()
Const pictureNameColumn As String = "A" 'column where picture name is found
Const picturePasteColumn As String = "J" 'column where picture is to be pasted
Const pathForPicture As String = "M:\Users\Dan\Pictures\LabPics\" 'path of pictures
Dim pictureFile As String
Dim pictureName As String 'picture name
Dim lastPictureRow As Long 'last row in use where picture names are
Dim pictureRow As Long 'current picture row to be processed
Dim picturePasteCell As Range
pictureRow = 3 'starts from this row
On Error GoTo Err_Handler
Dim ws As Worksheet
Set ws = ActiveSheet 'replace with better qualification
lastPictureRow = ws.Cells(ws.Rows.Count, pictureNameColumn).End(xlUp).Row
'stop screen updates while macro is running
Application.ScreenUpdating = False
'loop till last picture row
Do While (pictureRow <= lastPictureRow)
pictureName = ws.Cells(pictureRow, pictureNameColumn).Value2
If (pictureName <> vbNullString) Then
'check if pic is present
pictureFile = pathForPicture & pictureName
Set picturePasteCell = ws.Cells(pictureRow, picturePasteColumn)
If (Dir(pictureFile & ".jpg") <> vbNullString) Then
insertPictureToComment pictureFile & ".jpg", picturePasteCell, 41, 41
ElseIf (Dir(pictureFile & ".png") <> vbNullString) Then
insertPictureToComment pictureFile & ".png", picturePasteCell, 100, 130
ElseIf (Dir(pictureFile & ".bmp") <> vbNullString) Then
insertPictureToComment pictureFile & ".bmp", picturePasteCell, 100, 130
Else
'picture name was there, but no such picture
picturePasteCell.Value2 = "No Picture Found"
End If
Else
'picture name cell was blank
End If
pictureRow = pictureRow + 1
Loop
On Error GoTo 0
Exit_Sub:
ws.Range("A10").Select
Application.ScreenUpdating = True
Exit Sub
Err_Handler:
MsgBox "Error encountered. " & Err.Description, vbCritical, "Error"
GoTo Exit_Sub
End Sub
The function below handles the insertion of generic images to a cell's comment shape:
Function insertPictureToComment(pictureFilePath As String, _
pictureRange As Range, _
commentHeight As Long, _
commentWidth As Long)
Dim picComment As Comment
If pictureRange.Comment Is Nothing Then
Set picComment = pictureRange.AddComment
Else
Set picComment = pictureRange.Comment
End If
With picComment.Shape
.Height = commentHeight
.Width = commentWidth
.LockAspectRatio = msoFalse
.Fill.UserPicture pictureFilePath
End With
End Function