Is there something I can "release" to make this faster? - vba

So this code will run through every chart I have in a presentation and look to do a Find/Replace on the values inside.
My presentations usually have 100-300 charts on them, and by the time the code gets to the 300th chart in the presentation, it takes 10-30 seconds to do everything (when it would do 5 graphs in that time when I initially run the program.)
So my question is: Is there any way to make this faster? I'm thinking something along the lines of "releasing" something from memory, if VBA has it, would be the solution but I can't find anything on that.
I added
Set c = Nothing
Excel.Application.ScreenUpdating = True
Excel.Application.EnableEvents = True
Excel.Application.DisplayAlerts = True
Application.DisplayAlerts = True
I think suppressing everything is helping out a little bit, but I can't tell with the Set c = Nothing.
There must be something that could be"refresher" or "released" to make this run the same every loop and not slow down.
Any help appreciated!
Option Explicit
Private Sub findAndReplaceChrt()
'Timer start
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
' use & vbLF & for alt + enter
Dim pptPres As Object
Dim sld As Slide
Dim shpe As Shape
Dim c As Chart
Dim sht As Object
Dim fndList As Variant
Dim rplcList As Variant
Dim listArray As Long
Excel.Application.ScreenUpdating = False
Excel.Application.EnableEvents = False
Excel.Application.DisplayAlerts = False
Application.DisplayAlerts = False
fndList = Array("a", "b", "c", "d", "e", "f")
rplcList = Array("1", "2", "3", "4", "5", "6")
'Make pptPres the ppt active
Set pptPres = PowerPoint.ActivePresentation
'Loop through each sld and check for chart title, grab avgScore values and create pptTable to paste into ppt chart
For Each sld In pptPres.Slides
'searches through shapes in the slide
For Each shpe In sld.Shapes
'Checks if shape is a Charts and has a Chart Title
If Not shpe.HasChart Then GoTo nxtShpe
Set c = shpe.Chart
If Not c.ChartType = xlPie Then
ActiveWindow.ViewType = ppViewNormal
c.ChartData.Activate
'Loop through each item in Array lists
For listArray = LBound(fndList) To UBound(fndList)
Worksheets(1).Cells.Replace What:=fndList(listArray), Replacement:=rplcList(listArray), _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
Next listArray
c.ChartData.Workbook.Close
End If
Set c = Nothing
nxtShpe:
Next shpe
Next sld
Excel.Application.ScreenUpdating = True
Excel.Application.EnableEvents = True
Excel.Application.DisplayAlerts = True
Application.DisplayAlerts = True
'End Timer
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub

Related

Moving row from one workbook to another

I am new to StackOverflow, but have been working on this problem for some time, and am pretty stuck. Right now, my code takes 'Name' input from a textbox, and if the data in column A matches the name that was input, it copies data from the entire row in that sheet, copies it to another sheet, then deletes the data from the original sheet, and tells the user how many rows were moved. This code is listed below:
I have two problems. One, I need an error check where if the name that is typed into the textbox does not exist, it displays a messagebox with that message, and two, I need to allow for this code to do what it does, but from seperate workbooks. As in, copy the data from a sheet in one workbook, and move it to a sheet in another workbook. My code only works within the same workbook right now.
Any and all help is appreciated. Thank you in advance.
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook
Dim wkBk2 As Workbook
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
Dim count As Long
On Error Resume Next
Set wkBk1 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro.xlsm")
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
End If
I = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = Worksheets("Cancelled Services").UsedRange.Rows.count
count = 0
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Current Customers").Range("A1:A" & I)
On Error Resume Next
Application.ScreenUpdating = False
For K = 1 To xRg.count
If CStr(xRg(K).Value) = Me.fName.Value Then
count = count + 1
xRg(K).EntireRow.Copy Destination:=Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
If CStr(xRg(K).Value) = Me.fName.Value Then
K = K - 1
End If
J = J + 1
End If
Next
Application.ScreenUpdating = True
MsgBox count & " rows moved"
End Sub
EDIT : OK, here is one more wrinkle. What if I wanted to search through four or five different workbooks, and move all of the rows where the conditions are met into one worksheet called 'Cancelled Services' that will be a worksheet in one of the aforementioned workbooks.
There are a LOT of strange things going on in your code, so I've tried to clean it up a bit and left some comments as to why you shouldn't have some things in there. I've addressed the first part of your question, but in order to move rows between workbooks you need to decide what data you're looking to move and where, especially by fully qualifying your ranges using Workbook, or in your case, wkBk1 and wkBk2
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook, wkBk2 As Workbook
Dim xRg As Range, xCell As Range
Dim I As Long, J As Long, K As Long, count As Long
Dim MyName As String
'Assign our name value here
MyName = Me.fName.Value
'Let's use an error handler instead - this way our Err.Number will actually be triggered
On Error GoTo Handler
Set wkBk1 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro.xlsm")
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
On Error GoTo 0
I = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = Worksheets("Cancelled Services").UsedRange.Rows.count 'Need to add either wkBk1 or wkBk2 to the front of this
'We don't really NEED this, as count is initialized as 0 anyways
'count = 0
If J = 1 Then
'What is the purpose of this? Can it ever even return true if J = 1?
If Application.WorksheetFunction.CountA(Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Current Customers").Range("A1:A" & I) 'Need to add either wkBk1 or wkBk2 to the front of this
'Here we check the range for the name. If it's not there, we throw a messsage box and exit the sub
If Not WorksheetFunction.CountIf(xRg, MyName) > 0 Then
MsgBox "Name doesn't exist in the range"
Exit Sub
End If
'Got rid of On Error Resume Next, we don't need it and it's sloppy coding
Application.ScreenUpdating = False
'This whole snippet needs to be changed
'Also since you're deleting rows, you need to step BACKWARDS through this loop
For K = 1 To xRg.count
If CStr(xRg(K).Value) = MyName Then
xRg(K).EntireRow.Copy Destination:=Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
'Why do we have this? We already know this is true?
'If CStr(xRg(K).Value) = MyName Then
K = K - 1
'End If
'Move count to AFTER we've actually moved the row, with On Error Resume Next your count could've gone up without a row being moved...
count = count + 1
J = J + 1
End If
Next
Application.ScreenUpdating = True
MsgBox count & " rows moved"
Handler:
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
End If
End Sub
This code uses FIND rather than looking at each row. It creates a range of all found rows as it goes and then copies the whole lot over in one hit before deleting the original values. Before ending it tells you how many it found.
This assumes that you have a textbox called fname and button called buttonDelete on a Userform.
Private Sub buttonDelete_Click()
Dim wrkBk1 As Workbook
Dim wrkBk2 As Workbook
Dim sPath As String
Dim wrkSht1 As Worksheet
Dim wrkSht2 As Worksheet
Dim rLastCell_Cur As Range
Dim rLastCell_Can As Range
Dim sNameToSearch As String
Dim rSearchRange As Range
Dim rFound As Range
Dim sFirstAddress As String
Dim lFoundCount As Long
Dim rFoundUnion As Range
sPath = "C:\Users\Nathan\Desktop\Sandbox\"
If Not (FileExists(sPath & "testMacro.xlsm") And FileExists(sPath & "testMacro2.xlsm")) Then
'One of the files doesn't exist so display message and exit.
MsgBox "One of the files does not exist.", vbOKOnly + vbCritical
Else
Set wrkBk1 = Workbooks.Open(sPath & "testMacro.xlsm")
Set wrkBk2 = Workbooks.Open(sPath & "testMacro2.xlsm")
If Not (WorkSheetExists("Current Customers", wrkBk1) And _
WorkSheetExists("Cancelled Services", wrkBk2)) Then
'One of the sheets doesn't exist so display message and exit.
MsgBox "One of the required sheets doesn't exist.", vbOKOnly + vbCritical
Else
'Find the limits of the two sheets.
Set wrkSht1 = wrkBk1.Worksheets("Current Customers")
Set rLastCell_Cur = LastCell(wrkSht1)
Set wrkSht2 = wrkBk2.Worksheets("Cancelled Services")
Set rLastCell_Can = LastCell(wrkSht2).Offset(1) 'We want the cell below the last cell here.
'Grab what we're searching for and where we're searching for it.
sNameToSearch = Me.fName
With wrkSht1
Set rSearchRange = .Range(.Cells(1, 1), .Cells(rLastCell_Cur.Row, 1))
End With
With rSearchRange
'Perform first search.
Set rFound = .Find(What:=sNameToSearch, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
'If something was found then we're good to go.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
lFoundCount = lFoundCount + 1
'Create a union of ranges to copy over.
If rFoundUnion Is Nothing Then
Set rFoundUnion = rFound.EntireRow
Else
Set rFoundUnion = Union(rFoundUnion, rFound.EntireRow)
End If
'Look for the next item.
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
'All instances have been found so copy it all over and then delete the original.
rFoundUnion.Copy wrkSht2.Cells(rLastCell_Can.Row, 1)
rFoundUnion.Delete Shift:=xlUp
End If
MsgBox "Found " & lFoundCount & " occurrences of " & sNameToSearch, vbOKOnly + vbInformation
End With
End If
End If
End Sub
Public Function FileExists(FilePath As String) As Boolean
FileExists = Dir(FilePath) <> ""
End Function
Public Function WorkSheetExists(SheetName As String, Optional WrkBk As Workbook) As Boolean
Dim wrkSht As Worksheet
If WrkBk Is Nothing Then
Set WrkBk = ThisWorkbook
End If
On Error Resume Next
Set wrkSht = WrkBk.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
Public Function LastCell(wrkSht As Worksheet, Optional Col As Long = 0) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With wrkSht
If Col = 0 Then
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
Else
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Columns(Col).Find("*", , , , xlByColumns, xlPrevious).Row
End If
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrkSht.Cells(lLastRow, lLastCol)
End With
On Error GoTo 0
End Function
This update to the buttonDelete_Click() procedure will open all Excel files within a specific folder and copy the found name to another file that isn't in that folder.
Private Sub buttonDelete_Click()
Dim colFiles As Collection
Dim vFile As Variant
Dim sTemp As String
Dim wrkBk1 As Workbook
Dim wrkBk2 As Workbook
Dim sPath As String
Dim wrkSht1 As Worksheet
Dim wrkSht2 As Worksheet
Dim rLastCell_Cur As Range
Dim rLastCell_Can As Range
Dim sNameToSearch As String
Dim rSearchRange As Range
Dim rFound As Range
Dim sFirstAddress As String
Dim lFoundCount As Long
Dim rFoundUnion As Range
sPath = "C:\Users\Nathan\Desktop\Sandbox\"
'Put the full path of each Excel file in to a collection.
'These contain the "Current Customers" sheet.
Set colFiles = New Collection
sTemp = Dir$(sPath & "*.xls*")
Do While Len(sTemp) > 0
colFiles.Add sPath & sTemp
sTemp = Dir$
Loop
If Not (FileExists("C:\Users\Nathan\Desktop\Cancelled.xlsx")) Then
'Cancelled Services book doesn't exist.
MsgBox "Cancelled Services doesn't exist.", vbOKOnly + vbCritical
Else
'Open Cancelled Services before working through the collection of Current Customers.
Set wrkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Cancelled.xlsx")
Set wrkSht2 = wrkBk2.Worksheets("Cancelled Services")
For Each vFile In colFiles
Set wrkBk1 = Workbooks.Open(vFile)
'The file will only be processed if it contains "Current Customers" sheet.
If WorkSheetExists("Current Customers", wrkBk1) Then
Set wrkSht1 = wrkBk1.Worksheets("Current Customers")
Set rLastCell_Can = LastCell(wrkSht2).Offset(1)
Set rLastCell_Cur = LastCell(wrkSht1)
'Grab what we're searching for and where we're searching for it.
sNameToSearch = Me.fName
With wrkSht1
Set rSearchRange = .Range(.Cells(1, 1), .Cells(rLastCell_Cur.Row, 1))
End With
With rSearchRange
'Perform first search.
Set rFound = .Find(What:=sNameToSearch, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
'If something was found then we're good to go.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
lFoundCount = lFoundCount + 1
'Create a union of ranges to copy over.
If rFoundUnion Is Nothing Then
Set rFoundUnion = rFound.EntireRow
Else
Set rFoundUnion = Union(rFoundUnion, rFound.EntireRow)
End If
'Look for the next item.
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
'All instances have been found so copy it all over and then delete the original.
rFoundUnion.Copy wrkSht2.Cells(rLastCell_Can.Row, 1)
rFoundUnion.Delete Shift:=xlUp
End If
End With
End If
Set rFound = Nothing
Set rFoundUnion = Nothing
sFirstAddress = ""
wrkBk1.Close SaveChanges:=True
Next vFile
MsgBox "Found " & lFoundCount & " occurrences of " & sNameToSearch, vbOKOnly + vbInformation
End If
End Sub
To answer the first question about checking if a sheet exist in a workbook, you can use a Function like this:
Public Function U_W_DoesWorksheetExist(ByVal sheetname As String, aWorkbook As Workbook) As Boolean
On Error Resume Next
U_W_DoesWorksheetExist = (Not aWorkbook.Sheets(sheetname) Is Nothing)
On Error GoTo 0
End Function
Now, when you reference the destination, you are saying just Worksheets("Cancelled Services") and the Macro will assume the ActiveWorkook as the main workbook where to copy the Sheet. You need to reference the Workbook where the sheet you are pasting is located. See if the code below works for you and take a look at the comments I added on it:
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook
Dim wkBk2 As Workbook
Dim xRg As Range
Dim xCell As Range
Dim i As Long
Dim J As Long
Dim K As Long
Dim count As Long
Dim arrFromWorkbookPath(1 To 4) As String
Dim c As Long
' If you need more than 4 rearrange the Array to as many as you need.
arrFromWorkbookPath(1) = "C:\Users\Nathan\Desktop\Sandbox\FromWB1.xlsm"
arrFromWorkbookPath(4) = "C:\Users\Nathan\Desktop\Sandbox\FromWB2.xlsm"
arrFromWorkbookPath(3) = "C:\Users\Nathan\Desktop\Sandbox\FromWB3.xlsm"
arrFromWorkbookPath(4) = "C:\Users\Nathan\Desktop\Sandbox\FromWB4.xlsm"
' The Workbook were you will be pasting the sheets.
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
For c = LBound(arrFromWorkbookPath) To UBound(arrFromWorkbookPath)
On Error Resume Next
' Open the Workbook from where the sheet will be copied from.
Set wkBk1 = Workbooks.Open(arrFromWorkbookPath(c))
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
Exit Sub
End If
' USE PROCEDURE LIKE THIS TO CHECK "Current Customers" in wkBk1 and Cancelled Services in wkBk2.
If U_W_DoesWorksheetExist("Current Customers", wkBk1) And U_W_DoesWorksheetExist("Cancelled Services", wkBk1) Then
i = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = wkBk2.Worksheets("Cancelled Services").UsedRange.Rows.count
count = 0
If J = 1 Then
If Application.WorksheetFunction.CountA(wkBk2.Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = wkBk1.Worksheets("Current Customers").Range("A1:A" & i)
On Error Resume Next
Application.ScreenUpdating = False
For K = 1 To xRg.count
If CStr(xRg(K).Value) = Me.fName.Value Then
count = count + 1
' Here you need to specify the workbook, not just the sheet wkBk2.Worksheets("Cancelled Services").
xRg(K).EntireRow.Copy Destination:=wkBk2.Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
If CStr(xRg(K).Value) = Me.fName.Value Then
K = K - 1
End If
J = J + 1
End If
Next
wkBk1.Close False
Else
' Display error if the sheet doesn't exist.
MsgBox "Sheets Current Customers or Cancelled Services don't exists."
End If
Next c
Application.ScreenUpdating = True
End Sub

UserForm.Show within a prior Initial User form causes blank grey un-closeable workbook to open

Below is the excerpt of code where the "error(more like an unwanted occurrence)" happens. My code is running in a userform (not userform1) after a command button click. The initial form shows on workbook open. The second userform - UserForm1 in the code below - is a check box that I want to present to the user upon my IF condition. When the program gets there, it opens the UserForm1, but also opens a blank grey excel workbook. The workbook cannot be closed until I close the Userformm1 interface.
Note: the second msgbox does not display until AFTER I close the userform.
I tried searching for this problem, but couldn't find the issue in regards to UserForm stuff. Thanks in advance for any help.
Private Sub CommandButton1_Click()
Dim wbName As String, wb As Workbook, ws As Worksheet
Dim sht As Worksheet
Dim myValue As Variant
Dim counter As Integer
Dim EstNumAttempt As Boolean
EstNumAttemp = False
counter = 0
Dim ThisNum As String
Dim EstNum As String
Dim CopyFromBook As Workbook
Dim CopyToWbk As Workbook
Dim ShToCopy As Worksheet
Set CopyToWbk = ThisWorkbook
Application.ScreenUpdating = False
ThisUserPath = Application.ActiveWorkbook.Path
userDataPath = ThisUserPath & "\SBNBidDataSet01112018.xlsx"
Dim StartDate As String
Dim EndDate As String
StartDate = TextBox1.Value
EndDate = TextBox2.Value
EstNum = TextBox3.Value
Set wb = Workbooks.Open(userDataPath)
Set CopyFromWbk = wb
WSCount = wb.Worksheets.Count
If EstNum <> "" Then
EstNumAttempt = True
For X = 1 To WSCount
Set ws = wb.Sheets(X)
ThisNum = ws.Cells(2, 2)
If ThisNum = EstNum Then
counter = counter + 1
Set ShToCopy = CopyFromWbk.Worksheets(X)
ShToCopy.Copy After:=CopyToWbk.Sheets(CopyToWbk.Sheets.Count)
End If
Next X
If counter = 0 Then
MsgBox " That's probably not a valid EST# in SmartBidNet"
End If
End If
If IsDate(StartDate) = True And IsDate(EndDate) = True And EstNumAttempt = False Then
MsgBox "h"
wb.Application.Visible = False
UserForm1.Show
wb.Application.Visible = True
MsgBox "h"
'BLANK GREY SHEET HERE
For X = 100 To 101
Set ws = wb.Sheets(X)
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
'future code
Next X
End If
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
THIS IS NOT A SOLUTION, I tested a piece of your code and here is my feedback below.
I ran just this code in a workbook named testbook.xslm and I created a form (myForm that is just a grey layout, nothing on it):
Private Sub CommandButton1_Click()
Dim wb As Workbook
Dim anotherbook As Workbook
Dim anotherbook2 As Workbook
Dim anotherbook3 As Workbook
Set wb = Workbooks.Add
Set anotherbook = wb
Set anotherbook2 = wb
Set anotherbook3 = wb
MsgBox "h"
wb.Application.Visible = False
myForm.Show
wb.Application.Visible = True
MsgBox "h"
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
From the user standpoint:
1) testbook opens
2) click the button -> book# opens on top of testbook
3) msgbox "h" pops up
4) x out of msgbox "h" -> Both workbooks disappear (testbook and book1)
5) my grey user form pops up (its empty)
6) x out of userform
7) testbook shows again on top of the new book created which is behind it
8) msgbox "h" #2 pops up
9) x out of msgbox
10) the book# behind testbook disappears
That's it. No grey box residue. How are you closing the userforms (the first one and the second one)? obviously I used the terminate with the x. I did not add any code. So how are you closing your form with no code?
Adding the same behavior occurs if I make multiple workbook references to wb.
So this code area is not your problem . . . .
Second test, still no problems, adding worksheets, running through the number of worksheets, copying them to the testbook.
Option Explicit
Private Sub CommandButton1_Click()
Dim wb As Workbook
Dim wb2 As Workbook
Dim ws As Worksheet
Dim anotherbook As Workbook
Dim anotherbook2 As Workbook
Dim anotherbook3 As Workbook
Dim X As Double
Dim lastrow As Double
Dim thisNum As String
Set wb = Workbooks.Add
Set anotherbook = wb
Set anotherbook2 = wb
Set anotherbook3 = wb
Set wb2 = ThisWorkbook
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
myForm2.Show
MsgBox "h"
wb.Application.Visible = False
myForm.Show
wb.Application.Visible = True
MsgBox "h"
For X = 1 To wb.Worksheets.Count
Set ws = wb.Sheets(X)
thisNum = ws.Cells(2, 2)
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
ws.Copy After:=wb2.Worksheets(wb2.Worksheets.Count)
'future code
Next X
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
Perhaps you have a lot of data being acted upon. Clear the clipboard after the paste? With:
Application.CutCopyMode = False
Digging - WWC

Find and Replace on PowerPoint Excel Worksheet for a Chart

So this code will run a Find and Replace on PowerPoint charts. the goal is to replace the x-axis labels. The issue I'm having is that I get this popping up: We couldn't find anything to replace. Click options for more ways to search."
It pops up every time the chart doesn't have the word I'm looking for. So I added rngFound. I want to be able to say "If word is Found then Replace" instead of having my Replace just do everything at once.
So I went and added Set rngFound = Worksheets(1).objRange.Find(fndList). But it's not working. I suspect rngFound isn't actually doing anything for me, and would like any sort of help with this issue. Thank you in advance!
Option Explicit
Private Sub findAndReplaceChrt()
'Timer start
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
Dim pptPres As Object
Dim sld As Slide
Dim shpe As Shape
Dim c As Chart
Dim sht As Object
Dim fndList As Variant
Dim rplcList As Variant
Dim listArray As Long
Dim rngFound As Variant
fndList = Array("Red", "Purple")
rplcList = Array("red", "blue")
'Make pptPres the ppt active
Set pptPres = PowerPoint.ActivePresentation
'Loop through each sld and check for chart title, grab avgScore values and create pptTable to paste into ppt chart
For Each sld In pptPres.Slides
'searches through shapes in the slide
For Each shpe In sld.Shapes
'Checks if shape is a Charts and has a Chart Title
If Not shpe.HasChart Then GoTo nxtShpe
Set c = shpe.Chart
If Not c.ChartType = xlPie Then
ActiveWindow.ViewType = ppViewNormal
c.ChartData.Activate
'Loop through each item in Array lists
For listArray = LBound(fndList) To UBound(fndList)
Set rngFound = Worksheets(1).objRange.Find(fndList)
If Not rngFound Is Nothing Then
Worksheets(1).Cells.Replace What:=fndList(listArray), Replacement:=rplcList(listArray), _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
End If
Next listArray
c.ChartData.Workbook.Close
End If
nxtShpe:
Next shpe
Next sld
'End Timer
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub

Copy UserForm data to the next empty row inside PowerPoint Chart

I created a UserForm, with the help of many, within PowerPoint to assist with consistent embedded chart data entries. From what I have learned I will never do this again because addtional code that is needed to traverse through the PowerPoint to get to the correct location for the desired updates. No matter, I would like to finish the final objective of getting data from the UserForm into the first empty row. I have code but there is an error that is preventing the data to unload. The code I have is below. Any help in identifying the glitch is greatly appreciated.
Private Sub CPDataAdd_Click()
Dim sld As Slide
Dim shp As shape
Dim chrt As Chart
Dim xlWB As Object
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.Type = msoChart Then
If shp.Name = "DVchart" Then
Set xlWB = shp.Chart.ChartData.Workbook
Exit For
End If
End If
Next
If Not xlWB Is Nothing Then Exit For
Next
Set shp = sld.Shapes("DVchart")
Set xlWB = shp.Chart.ChartData.Workbook
Dim LastRow As Long
With xlWB.Sheets(1)
LastRow = .Range("AI" & Rows.Count).End(xlup).Row + 1
.Range("AI" & LastRow).Value = CPDate.Text
.Range("BI" & LastRow).Value = CPCompleteN.Text
.Range("CI" & LastRow).Value = CPPassN.Text
.Range("DI" & LastRow).Value = CPFailN.Text
.Range("EI" & LastRow).Value = CPNotN.Text
End With
End Sub

Pulling images from a FTP site to Excel

I have the following working codes.
Column B has image names, this pulls images in the selected folder that match the names in column B and inserts them into Column A (please note, first two rows are used for my header). I've noticed that the code errors if the header in B2 is missing, then the code errors out. I would like to fix this so it will only try to find images if there is a name in Range("B3:B1002").
Option Explicit
Private Sub Add_Images_Click()
Const EXIT_TEXT As String = ""
Const NO_PICTURE_FOUND As String = "No picture found"
Dim picName As String
Dim picFullName As String
Dim rowIndex As Long
Dim lastRow As Long
Dim selectedFolder As String
Dim data() As Variant
Dim wks As Worksheet
Dim Cell As Range
Dim pic As Picture
On Error GoTo ErrorHandler
selectedFolder = GetFolder
If Len(selectedFolder) = 0 Then GoTo ExitRoutine
Application.ScreenUpdating = False
Set wks = ActiveSheet
lastRow = wks.Cells(2, "B").End(xlDown).Row
data = wks.Range(wks.Cells(1, "B"), wks.Cells(lastRow, "B")).Value2
For rowIndex = 3 To UBound(data, 1)
If StrComp(data(rowIndex, 1), EXIT_TEXT, vbTextCompare) = 0 Then GoTo ExitRoutine
picName = data(rowIndex, 1)
picFullName = selectedFolder & picName
If Len(Dir(picFullName)) > 0 Then
Set Cell = wks.Cells(rowIndex, "A")
Set pic = wks.Pictures.Insert(picFullName)
With pic
.ShapeRange.LockAspectRatio = msoFalse
.Height = Cell.Height
.Width = Cell.Width
.Top = Cell.Top
.Left = Cell.Left
.Placement = xlMoveAndSize
End With
Else
wks.Cells(rowIndex, "A").Value = NO_PICTURE_FOUND
End If
Next rowIndex
ExitRoutine:
Set wks = Nothing
Set pic = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox Prompt:="Unable to find photo", _
Title:="An error occured", _
Buttons:=vbExclamation
Resume ExitRoutine
End Sub
This is the Function that has the user select the folder that contains the images when the above sub is ran. I would like to modify this if possible to also work with an URL like an FTP site. So if the images are in a folder on the users pc, it will run like below, but if the images are located in a FTP location, it will still be able to pull the images.
Private Function GetFolder() As String
Dim selectedFolder As String
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Select the folder containing the Image/PDF files."
.Show
If .SelectedItems.Count > 0 Then
selectedFolder = .SelectedItems(1)
If Right$(selectedFolder, 1) <> Application.PathSeparator Then _
selectedFolder = selectedFolder & Application.PathSeparator
End If
End With
GetFolder = selectedFolder
End Function
This Sub is meant to remove all images from column A. The problem is that this works too well. It is fine when used with a normal button, but when I try using a CommandButton to have my buttons on a user form, this Sub removes the CommandButton. It also removes all comments from the sheet. I would like to either limit this to only remove images, or to quarantine the code to only look at Range("A3:A1002").
Private Sub Remove_Images_Click()
'Remove Images
Dim wks As Worksheet
Dim shp As Shape
Dim picArray() As String
Dim index As Integer
On Error GoTo ErrorHandler
Columns(1).Replace What:="No Picture Found", Replacement:=vbNullString, LookAt:=xlPart
Set wks = ActiveSheet
index = 1
For Each shp In wks.Shapes
If shp.Type <> msoFormControl Then
ReDim Preserve picArray(1 To index)
picArray(index) = shp.Name
index = index + 1
End If
Next shp
wks.Shapes.Range(picArray).Delete
ExitRoutine:
Set wks = Nothing
Set shp = Nothing
Erase picArray
Exit Sub
ErrorHandler:
MsgBox Prompt:="Unable to find photo", _
Title:="An error occured", _
Buttons:=vbExclamation
Resume ExitRoutine
End Sub
I see three main questions, probably better to separate these into different questions but I'll give it a shot.
Ignore row 2 in the first code block.
Change 1 to 3 on this line: data = wks.Range(wks.Cells(3, "B"), wks.Cells(lastRow, "B")).Value2 This sets your data range starting at row 3 and ignores your two header rows.
FTP link
This is better suited for a separate question. Start by creating a new function that handles FTP links. Then identify which path is in the cell, i.e. does it start with http, c://, etc... Then call appropriate function and have it return the image to the main program.
Check if shape is in column A.
Use the TopLeftCell attribute and see if it intersects column A
For Each shp In wks.Shapes
If Not Intersect(shp.TopLeftCell, Columns(1)) Is Nothing Then '<-- New Line checks if in col A
If shp.Type <> msoFormControl Then
....