Editing the cell value in Specialcells fails? - vba

I have two sheets, one that information about decks played by players, who owns it, what the deck name is, and earlier names. Then another where I have match information of said player, owner and deck name.
My aim is to update match information deck names to newest. I've these two subprocedures. First finds what we need to update, then uses a filtering subprocedure to filter the match list to only have matches containing the player, owner and deck combination visible.
Then it calls the other method, where I try to update the name. It runs nicely, says happily in the debug log that it has beeen renamed from oldname to new name, but when it's finished, the value in the deck name cell remains unchanged.
What am I doing wrong?
EDIT: I tried out your script, Pefington, and amended the split of for i and for each loops. I also used the Variant approach you suggested. Now it runs again, and says it tries to update 'chulane precon to chulane', but that change is not reflected in the excel sheet.
Had to do an rather ugly way of populating the array of Variants with from the array of Strings.
I also added a rownumber to just check in debugger that it indeed goes through the row with chulane precon, and it does, but still fails to actually save the chulane into the cell. Which is the thing I need help with. :)
Sub CleanOldDeckNames()
' DISABLE EXCEL ANIMATIONS
Application.ScreenUpdating = False
Dim player As String
Dim owner As String
Dim concatenatedOldNames As String
Dim oldNamesArray() As Variant
Dim currentName As String
Dim currentOldName As String
Dim temporaryOldNameStringArray() As String
Dim j As Integer
Dim oldName As Variant
Sheets("Decklist").Select
Call dl_search_deck_hidden_reset
For i = 12 To 50
player = ActiveWorkbook.Worksheets("Decklist").range("A" & i).Value
owner = ActiveWorkbook.Worksheets("Decklist").range("B" & i).Value
currentName = ActiveWorkbook.Worksheets("Decklist").range("C" & i).Value
concatenatedOldNames = ActiveWorkbook.Worksheets("Decklist").range("D" & i).Value
If Not (StrComp(concatenatedOldNames, "") = 0) Then
temporaryOldNameStringArray = Split(concatenatedOldNames, ",")
j = 0
For Each oldNameToBeConverted In temporaryOldNameStringArray
ReDim Preserve oldNamesArray(j)
oldNamesArray(j) = CStr(oldNameToBeConverted)
j = j + 1
Next oldNameToBeConverted
For Each oldName In oldNamesArray
currentOldName = Trim(CStr(oldName))
Sheets("Game Logs").Select
ActiveWorkbook.Worksheets("Game Logs").range("E1:G1").Value = Array(player, owner, currentOldName)
Call gl_find_rename_deck
Call RenameInSpecialCells(currentOldName, currentName)
Next oldName
End If
Next
Call gl_find_rename_deck_reset
' ENABLE EXCEL ANIMATIONS
Application.ScreenUpdating = True
End Sub
Sub RenameInSpecialCells(oldName As String, currentName As String)
For Each cell In ActiveWorkbook.Worksheets("Game Logs").AutoFilter.range.SpecialCells(xlCellTypeVisible)
If (StrComp(cell, oldName) = 0) Then
Dim rownumber As Integer
rownumber = cell.row
cell = currentName
Debug.Print ("Renamed " & oldName & " to " & currentName)
End If
Next cell
End Sub

Edit to add after feedback:
Sub RenameInSpecialCells(oldName As String, currentName As String)
dim rng as range, c as range
set rng = ActiveWorkbook.Worksheets("Game Logs").AutoFilter.range.SpecialCells(xlCellTypeVisible) #.range? can't get intellisense to trigger on this one#
For Each c In rng.cells
If (StrComp(c.value, oldName) = 0) Then
c.value = currentName
Debug.Print ("Renamed " & oldName & " to " & currentName)
End If
Next
End Sub
First post here, and new at coding, but I think I see some issues and hopefully can help.
Dim oldNameS As String
Note the s, plural.
You then use:
For Each oldName In oldNamesArray
Now you are calling oldName (singular) as if it was a member of an oldNames collection, but it is not.
You could go with:
For Each oldNames in oldNamesArray
The second problem I think is that you are trying to use a for each loop on a string array. To do that, your array needs to be a variant.
So your array declaration should read:
Dim oldNamesArray() as Variant
Lastly:
Dim name As Variant
I don't see this one getting used, maybe lost in the process?
With those comments the code looks like this:
Sub CleanOldDeckNames()
' DISABLE EXCEL ANIMATIONS
Application.ScreenUpdating = False
Dim player As String
Dim owner As String
Dim oldName As String
Dim oldNamesArray() As Variant
Dim currentName As String
Dim currentOldName As String
Sheets("Decklist").Select
Call dl_search_deck_hidden_reset
For i = 12 To 50
player = ActiveWorkbook.Worksheets("Decklist").range("A" & i).Value
owner = ActiveWorkbook.Worksheets("Decklist").range("B" & i).Value
currentName = ActiveWorkbook.Worksheets("Decklist").range("C" & i).Value
oldName = ActiveWorkbook.Worksheets("Decklist").range("D" & i).Value
oldNamesArray = Split(oldName, ",")
next
For Each oldName In oldNamesArray
currentOldName = Trim(CStr(oldName)) #not sure if CStr required#
Sheets("Game Logs").Select
ActiveWorkbook.Worksheets("Game Logs").range("E1:G1").Value = Array(player, owner, currentOldName)
Call gl_find_rename_deck
Call RenameInSpecialCells(currentOldName, currentName)
Next
Call gl_find_rename_deck_reset
' ENABLE EXCEL ANIMATIONS
Application.ScreenUpdating = True
End Sub
Sub RenameInSpecialCells(oldName As String, currentName As String)
For Each cell In ActiveWorkbook.Worksheets("Game Logs").AutoFilter.range.SpecialCells(xlCellTypeVisible)
If (StrComp(cell, oldName) = 0) Then
cell = currentName
Debug.Print ("Renamed " & oldName & " to " & currentName)
End If
Next cell
End Sub
Apologies if I'm way off the mark.
Edit to add: Your for each in array loop doesn't use i, so you can run the for i loop and for each loop in sequence rather than nesting them. Code amended accordingly.

I finally managed to circumvent the saving. I could not find any reason for why I could not edit the cell via SpecialCells, so I grabbed the row number and column number and edited it directly in the sheet. Turned out that worked.
I also did not need to use Variant as suggested, this simply works.
Sub CleanOldDeckNames()
' DISABLE EXCEL ANIMATIONS
Application.ScreenUpdating = False
Dim player As String
Dim owner As String
Dim oldNames As String
Dim oldNamesArray() As String
Dim currentName As String
Dim currentOldName As String
Dim j As Integer
Sheets("Decklist").Select
Call dl_search_deck_hidden_reset
For i = 12 To 50
player = ActiveWorkbook.Worksheets("Decklist").range("A" & i).Value
owner = ActiveWorkbook.Worksheets("Decklist").range("B" & i).Value
currentName = ActiveWorkbook.Worksheets("Decklist").range("C" & i).Value
oldNames = ActiveWorkbook.Worksheets("Decklist").range("D" & i).Value
oldNamesArray = Split(oldNames, ",")
Dim name As Variant
For Each oldName In oldNamesArray
currentOldName = Trim(oldName)
Sheets("Game Logs").Select
ActiveWorkbook.Worksheets("Game Logs").range("E1:G1").Value = Array(player, owner, currentOldName)
Call gl_find_rename_deck
Call RenameInSpecialCells(currentOldName, currentName)
Next oldName
Next i
Call gl_find_rename_deck_reset
' ENABLE EXCEL ANIMATIONS
Application.ScreenUpdating = True
End Sub
Sub RenameInSpecialCells(oldName As String, currentName As String)
For Each cell In ActiveWorkbook.Worksheets("Game Logs").AutoFilter.range.SpecialCells(xlCellTypeVisible)
If (StrComp(cell, oldName) = 0) Then
Debug.Print ("Attemtping to rename: " & cell)
ActiveWorkbook.Worksheets("Game Logs").Cells(cell.row, cell.Column).Value = "Chulane"
Debug.Print ("New content: " & ActiveWorkbook.Worksheets("Game Logs").Cells(cell.row, cell.Column))
End If
Next cell
End Sub

Related

Return the Worksheet that an Excel Chart is referencing using VBA

I need to be able to identify the worksheet that an excel chart (on a worksheet) is getting it's data from. I only need the data sheet which series 1 is referencing. I've started trying to extract the sheet name from .SeriesCollection(1).Formula but it gets realy complex. here's what I've got so far:
Sub GetChartDataSheet()
Dim DataSheetName As String
Dim DataSheet As Worksheet
DataSheetName = ActiveChart.SeriesCollection(1).Formula
DataSheetName = Left(DataSheetName, InStr(1, DataSheetName, "!$") - 1)
DataSheetName = WorksheetFunction.Replace(DataSheetName, 1, Len("=series("), "")
If Left(DataSheetName, 1) = "'" And Right(DataSheetName, 1) = "'" Then DataSheetName = Mid(DataSheetName, 2, Len(DataSheetName) - 2)
DataSheetName = Replace(DataSheetName, "''", "'")
Set DataSheet = Sheets(DataSheetName)
End Sub
this works in a lot of cases, but if my users have a strange worksheet name (eg Sh'e e$,,t!3!$) it fails. the same goes if series 1 has been named (eg .SeriesCollection(1).Formula = "=SERIES(**"Hell,o !"**,'Sh''e e$,,t!3!$'!$B$2:$B$18,'Sh''e e$,,t!3!$'!$C$2:$C$18,1)".
Is there a simple way to solve this?
I thought this is an easy one, turns out it's not. One of the cases where Excel has the information but will not give it away for free. I ended up with a function like this - maybe this helps:
Function getSheetNameOfSeries(s As Series) As String
Dim f As String, i As Integer
Dim withQuotes As Boolean
' Skip leading comma if not all parts of series is filled. Check if sheetname is in single quotes
For i = 9 To Len(s.Formula)
If Mid(s.Formula, i, 1) <> "," Then
If Mid(s.Formula, i, 1) = "'" Then
withQuotes = True
f = Mid(s.Formula, i + 1)
Else
withQuotes = False
f = Mid(s.Formula, i)
End If
Exit For
End If
Next i
' "f" now contains a part of the formula with the sheetname as start
' now we search to the end of the sheet name.
' If name is in quotes, we are looking for the "closing" quote
' If not in quotes, we are looking for "!"
i = 1
Do While True
If withQuotes Then
' Sheet name is in quotes, found closes quote --> we're done
' (but if next char is also a quote, we have the case the the sheet names contains a quote, so we have to continue working)
If Mid(f, i, 1) = "'" Then
If Mid(f, i + 1, 1) <> "'" Then
getSheetNameOfSeries = Mid(f, 1, i - 1)
Exit Do
Else
i = i + 1 ' Skip 2nd quote
End If
End If
Else
' Sheet name is quite normal, so "!" will indicate the end of sheetname
If Mid(f, i, 1) = "!" Then
getSheetNameOfSeries = Mid(f, 1, i - 1)
Exit Do
End If
End If
i = i + 1
Loop
getSheetNameOfSeries = Replace(getSheetNameOfSeries, "''", "'")
End Function
You can use the Find function to look for the values of SeriesCollection(1).
In the worksheet that hold the data of SeriesCollection(1), you will be able to find all the values in that array.
More explanations inside the code below.
Code
Option Explicit
Sub GetChartDataSheet()
Dim DataSheetName As String
Dim DataSheet As Worksheet
Dim ws As Worksheet
Dim ValuesArr As Variant, Val As Variant
Dim FindRng As Range
Dim ShtMatch As Boolean
Dim ChtObj As ChartObject
Dim Ser As Series
' if you want to use ActiveChart
Set ChtObj = ActiveChart.Parent
Set Ser = ChtObj.Chart.SeriesCollection(1)
ValuesArr = Ser.Values ' get the values of the Series Collection inside an array
' use Find to get the Sheet's origin
For Each ws In ThisWorkbook.Sheets
With ws
ShtMatch = True
For Each Val In ValuesArr ' loop through all values in array
Set FindRng = .Cells.Find(what:=Val) ' you need to find each value in the worksheet that SeriesCollection data is tied to
If FindRng Is Nothing Then
ShtMatch = False
Exit For
End If
Set FindRng = Nothing ' reset
Next Val
If ShtMatch = True Then
Set DataSheet = ws
Exit For
End If
End With
Next ws
DataSheetName = DataSheet.Name
End Sub

VBA - worksheet parameter in function

I have a function 'mergeCategories' taking into argument (worksheet, worksheet, long). The idea is to read the value of a cell and replace it with another value based on a mapping table.
The content of the function works well when I run it as a sub and declaring the values inside the sub. But when i call the function from a sub, i get error Run-time error 424 Object Required at the line:
last_row_matching = ws_matching.Range("A1").End(xlDown).Row
Apparently, there is an issue with the worksheet ws_matching
Here is the function:
Function mergeCategories(ws_source As Worksheet, ws_macthing As Worksheet, last_row_used As Long) As Boolean
'Variables
'Result boolean
Dim final_result As Boolean
final_result = False
'Source category name
Dim src_cat_name As String
'Destination category name
Dim dest_cat_name As String
'Index of last row in matching table
Dim last_row_matching As Long
last_row_matching = ws_matching.Range("A1").End(xlDown).Row
MsgBox "Last row matching " & last_row_matching
'Result of the matching (as range, .Value used to get name)
Dim result_range As Range
'Loop
For i = 1 To last_row_used
'get the source category name
src_cat_name = ws_source.Range("A" & i).Value
MsgBox "The category name pulled is " & src_cat_name
'Find the mapping
Set result_range = ws_matching.Range("A2:A" & last_row_matching).Find(src_cat_name)
dest_cat_name = result_range.Offset(0, 1).Value
MsgBox "The new category name is " & dest_cat_name
ws_source.Range("A" & i).Value = dest_cat_name
ws_source.Range("A" & i).Activate
MsgBox "Check"
Next i
final_result = True
End Function
Here is the macro:
Sub test_mergeCategories()
Dim ws_matching As Worksheet
Set ws_matching = Sheets("Matching")
Dim ws_source As Worksheet
Set ws_source = Sheets("Temp_Import")
Dim last_row_used As Long
last_row_used = ws_source.Range("A1").End(xlDown).Row
Call mergeCategories(ws_source, ws_matching, last_row_used)
End Sub
Any idea of what is the issue?

GetValue + loop = Can it go faster?

I have created main file which imports data from other (closed) excel files. There is x-ten of files from which I need to import data. I made a code in UserForm so that mine boss can choose where to import (sheet = wariant) file. It is not completed because I need to add options button (for choosing which file to import), but main core will look like beneath.
But there is a problem, in our company we have a medium class laptops, so that code (beneath) in executin in 5-7 minutes for each file (wariant). I need it to run as fast as possible. Can you make something with it?
Private Sub CommandButton1_Click()
StartTime = Timer
Dim p As String
Dim f As String
Dim s As String
Dim a As String
Dim r As Long
Dim c As Long
Dim Warinat As String
If UserForm1.War1 = True Then Wariant = "Wariant 1"
If UserForm1.War2 = True Then Wariant = "Wariant 2"
If UserForm1.War3 = True Then Wariant = "Wariant 3"
If UserForm1.War4 = True Then Wariant = "Wariant 4"
p = ThisWorkbook.path
f = "files.xlsx"
s = "Sheet1"
Application.ScreenUpdating = False
For r = 7 To 137
For c = 2 To 96
a = Cells(r, c).Address
If IsNumeric(Cells(r, c)) = True And ThisWorkbook.Sheets(Wariant).Cells(r, c) <> "" _
Then ThisWorkbook.Sheets(Wariant).Cells(r, c) = _
ThisWorkbook.Sheets(Wariant).Cells(r, c).Value + GetValue(p, f, s, a)
Else
ThisWorkbook.Sheets(Wariant).Cells(r, c) = GetValue(p, f, s, a)
End If
Next c
Next r
EndTime = Timer
MsgBox Format(EndTime - StartTime, ssss)
Unload Me
End Sub
Private Function GetValue(path, file, sheet, ref)
Dim arg As String
If Right(path, 1) <> "\" Then path = path & "\"
If Dir(path & file) = "" Then
GetValue = "Files is missing"
Exit Function
End If
arg = "'" & path & "[" & file & "]" & sheet & "'!" & _
Range(ref).Range("A1").Address(, , xlR1C1)
GetValue = ExecuteExcel4Macro(arg)
End Function
Private Sub CommandButton2_Click()
Unload Me
End Sub
Private Sub UserForm_Click()
End Sub
Your ExecuteExcel4Macro call is likely slowing down the process, as it opens the same workbook 12,445 times. You're dealing with two 2-D arrays; one in your Wariant sheet and one in your imported workbook. Try something like this.
Dim var1 As Variant
Dim var2 As Variant
Dim wbImport As Workbook
'Set var1 as your range value
var1 = ThisWorkbook.Sheets(Wariant).Range("B7:CR137").Value
'Open the Import workbook, set the value, then close it.
Set wbImport = Application.Workbooks.Open(p & f)
var2 = wbImport.Sheets("Sheet1").Range("B7:CR137").Value
wbImport.Close
'Now loop through the variant arrays - much faster
For r = 1 To 131
For c = 1 To 95
If IsNumeric(var1(r, c)) And var1(r, c) <> "" Then
var1(r, c) = _
var1(r, c) + var2(r, c)
Else
var1(r, c) = var2(r, c)
End If
Next c
Next r
'Finally, copy the variant array back into the workbook.
ThisWorkbook.Sheets(Wariant).Range("B7:CR137").Value = var1
It will probably run faster if you open each workbook rather than reading cell-by-cell from a closed workbook.
not without knowing what you are calling with ExecuteExcel4Macro function, because called macro can be anything and very likely is reason why your code excecutes slowly
GetValue = ExecuteExcel4Macro(arg)
To do this without opening the workbook you can paste this code into a new module:
Dim v As Variant
Function GetValues(p As String, f As String, s As String, a As String)
v = Empty
Application.ExecuteExcel4Macro "'" & ThisWorkbook.Name & "'!SetV('" & p & "\[" & f & "]" & s & "'!" & a & ")"
GetValues = v
End Function
Public Function SetV(Value)
v = Value
End Function
You can then retrieve all the values from the closed workbook in a single call like this:
GetValues(ThisWorkbook.path,"files.xlsx","Sheet1","r7c2:r137c96")

Looping Macro in Excel

I would like to loop through an Excel worksheet and to store the values based on a unique ID in a text file.
I am having trouble with the loop and I have done research on it with no luck and my current nested loop continually overflows. Instead of updating the corresponding cell when the control variable is modified, it continues to store the initial Index value for all 32767 iterations.
Please can someone explain why this is happening, and provide a way of correcting it?.
Sub SortLetr_Code()
'sort columns for Letr_Code files
Dim lr As Long
Application.ScreenUpdating = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
Range("A2:B" & lr).Sort key1:=Range("B2"), order1:=1
Application.ScreenUpdating = True
'Value of cell for example B1 starts out as X
Dim x As Integer
Dim y As Integer
x = 2
y = 2
'Cell References
Dim rwCounter As Range
Dim rwCorresponding As Range
Dim rwIndexValue As Range
Dim rwIndexEnd As Range
Dim rwIndexStore As Range
'Variables for files that will be created
Dim FilePath As String
Dim Filename As String
Dim Filetype As String
'Variables defined
FilePath = "C:\Users\Home\Desktop\SURLOAD\"
Filetype = ".dat"
'Use Cell method for Loop
rwIndex = Cells(x, "B").Value
Set rwCounter = Range("B" & x)
'Use Range method for string manipulation
Set rwCorresponding = Range("A" & x)
Set rwIndexValue = Range("B" & y)
Set rwIndexStore = Range("B" & x)
Set rwIndexEnd = Range("B:B").End(xlUp)
'Objects for creating the text files
Dim FileCreate As Object
Set FileCreate = CreateObject("Scripting.FileSystemObject")
'Object for updating the file during the loop
Dim FileWrite As Object
For Each rwIndexStore In rwIndexEnd.Cells
'Get Substring of cell value in BX for the file name
Do Until IsEmpty(rwCounter)
Filename = Mid$(rwIndexValue, 7, 5)
Set FileWrite = FileCreate.CreateTextFile(FilePath + Filename + Filetype)
'Create the file
FileWrite.Write (rwCorresponding & vbCrLf)
Do
'Add values to the textfile
x = x + 1
FileWrite.Write (rwCorresponding & vbCrLf)
Loop While rwCounter.Value Like rwIndexValue.Value
'Close this file
FileWrite.Close
y = x
Loop
Next rwIndexStore
End Sub
I don't see a place you are setting rwCounter inside the loop.
It looks like it would stay on range("B2") and x would just continue to increase until it hits an error, either at the limit of integer or long.
add Set rwCounter = Range("B" & x) somewhere inside your loop to increment it
This is the solution.
Sub GURMAIL_File()
'sort columns for Letr_Code files
Dim lr As Long
Application.ScreenUpdating = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
Range("A2:B" & lr).Sort key1:=Range("B2"), order1:=1
Application.ScreenUpdating = True
'Variables that store cell number
Dim Corresponding As Integer
Dim Index As Integer
Dim Counter As Integer
Corresponding = 2
Index = 2
Counter = 2
'Cell References
Dim rwIndexValue As Range
'Variables for files that will be created
Dim l_objFso As Object
Dim FilePath As String
Dim Total As String
Dim Filename As String
Dim Filetype As String
Dim FolderName As String
'Variables defined
FilePath = "C:\Users\Home\Desktop\SURLOAD\"
'Name of the folder to be created
FolderName = Mid$(ActiveWorkbook.Name, 9, 8) & "\"
'Folder path
Total = FilePath & FolderName
'File Extension
Filetype = ".dat"
'Object that creates the folder
Set l_objFso = CreateObject("Scripting.FileSystemObject")
'Objects for creating the text files
Dim FileCreate As Object
Set FileCreate = CreateObject("Scripting.FileSystemObject")
'Object for updating the file during the loop
Dim FileWrite As Object
'Get Substring of letter code in order to name the file. End this loop once ID field is null.
Do While Len(Range("A" & Corresponding)) > 0
'Create the directory if it does not exist
If Not l_objFso.FolderExists(Total) Then
l_objFso.CreateFolder (Total)
End If
'Refence to cell containing a letter code
Set rwIndexValue = Range("B" & Index)
'Substring of that letter code
Filename = Mid$(rwIndexValue, 7, 5)
'Create the file using the substring and store it in the proper location
Set FileWrite = FileCreate.CreateTextFile(Total + Filename + Filetype, True)
'For each letter code, find the corresponding values. End the loop once the last value for the letter code is stored.
Do While Range("B" & Index) Like Range("B" & Counter)
'Add each line to the text file.
FileWrite.WriteLine (Range("A" & Corresponding))
'Incrementer variables that allow you to exit the loop
'if you have reached the last value of the current letter code.
Corresponding = Corresponding + 1
Counter = Counter + 1
Loop
'Close the file you were writing to
FileWrite.Close
'Make sure that Index value is updated to the next letter code
Index = Counter
'In case Index value needs updating (safeguard to make sure that the new letter code is stored to index value).
Set rwIndexValue = Range("B" & Index)
Loop
End Sub

Exporting PowerPoint sections into separate files

Every week I separate a long PowerPoint file into separate files. The files must be in PowerPoint format, and contain only the slides that are contained in the 'sections' from the PowerPoint file.
I need to:
1) Scan to see the number of slides in a given section
2) Make a file containing the slides within that section
3) Name that file the same as the name of the section, and save it in the same directory as the source file.
4) Repeat the process for subsequent sections.
5) Do this without damaging the original file.
I've located code (http://www.pptfaq.com/FAQ01086_Break_a_presentation_up_into_several_smaller_presentations.htm) that can break the file into many parts, but only by the number of files requested per file. I found some other helpful references here: http://skp.mvps.org/2010/ppt001.htm
I have coded in Basic and a number of easy gaming scripting languages. I need help understanding how this is done in VBA.
Since you do this very often, you should make an Add-In for this. The idea is to create copies of the presentation up to the number of sections in it, then open each one and delete the other sections and save.
Create blank presentation with macros enabled (*.pptm) and possibly add Custom UI button to call SplitIntoSectionFiles
Test and when satisfy, save as PowerPoint Add-In (*.ppam). Don't delete the pptm file!
Assuming that all are pptx files you are dealing with, you can use this code. It opens the splited pptx files in background, then remove irrelevant sections and save, close. If all goes well you get a message box.
Private Const PPT_EXT As String = ".pptx"
Sub SplitIntoSectionFiles()
On Error Resume Next
Dim aNewFiles() As Variant, sPath As String, i As Long
With ActivePresentation
sPath = .Path & "\"
For i = 1 To .SectionProperties.Count
ReDim Preserve aNewFiles(i)
' Store the Section Names
aNewFiles(i - 1) = .SectionProperties.Name(i)
' Force Save Copy as pptx format
.SaveCopyAs sPath & aNewFiles(i - 1), ppSaveAsOpenXMLPresentation
' Call Sub to Remove irrelevant sections
RemoveOtherSections sPath & aNewFiles(i - 1) & PPT_EXT
Next
If .SectionProperties.Count > 0 And Err.Number = 0 Then MsgBox "Successfully split " & .Name & " into " & UBound(aNewFiles) & " files."
End With
End Sub
Private Sub RemoveOtherSections(sPPT As String)
On Error Resume Next
Dim oPPT As Presentation, i As Long
Set oPPT = Presentations.Open(FileName:=sPPT, WithWindow:=msoFalse)
With oPPT
' Delete Sections from last to first
For i = .SectionProperties.Count To 1 Step -1
' Delete Sections that are not in the file name
If Not InStr(1, .Name, .SectionProperties.Name(i), vbTextCompare) = 1 Then
' Delete the Section, along with the slides associated with it
.SectionProperties.Delete i, True
End If
Next
.Save
.Close
End With
Set oPPT = Nothing
End Sub
Read about Custom UI if you don't have experience creating you own ribbon tab: msdn and use the "Office Custom UI Editor", I would use imageMso "CreateModule" for the button.
None of the proposed routines actually works, so I wrote mine from scratch:
Sub Split()
Dim original_pitch As Presentation
Set original_pitch = ActivePresentation
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
With original_pitch
.SaveCopyAs _
FileName:=fso.BuildPath(.Path, fso.GetBaseName(.Name) & ".pptx"), _
FileFormat:=ppSaveAsOpenXMLPresentation
End With
Dim i As Long
For i = 1 To original_pitch.SectionProperties.Count
Dim pitch_segment As Presentation
Set pitch_segment = Presentations.Open(Replace(original_pitch.FullName, "pptm", "pptx"))
section_name = pitch_segment.SectionProperties.Name(i)
For k = original_pitch.SectionProperties.Count To 1 Step -1
If pitch_segment.SectionProperties.Name(k) <> section_name Then pitch_segment.SectionProperties.Delete k, True
Next k
With pitch_segment
.SaveCopyAs _
FileName:=fso.BuildPath(.Path, original_pitch.SectionProperties.Name(i) & ".pptx"), _
FileFormat:=ppSaveAsOpenXMLPresentation
.Close
End With
Next i
MsgBox "Split completed successfully!"
End Sub
I could not get the above code to work.
However this is simpler and does work:
Sub SplitToSectionsByChen()
daname = ActivePresentation.Name
For i = 1 To ActivePresentation.SectionProperties.Count
For j = ActivePresentation.SectionProperties.Count To 1 Step -1
If i <> j Then ActivePresentation.SectionProperties.Delete j, True
Next j
ActivePresentation.SaveAs ActivePresentation.SectionProperties.Name(1)
ActivePresentation.Close
Presentations.Open (daname)
Next i
End Sub
I have edited fabios code a bit to look like this. And this works well for me in my PC
Option Explicit
Sub Split()
Dim original_File As Presentation
Dim File_Segment As Presentation
Dim File_name As String
Dim DupeName As String
Dim outputFname As String
Dim origName As String
Dim lIndex As Long
Dim K As Long
Dim pathSep As String
pathSep = ":"
#If Mac Then
pathSep = ":"
#Else
pathSep = "/"
#End If
Set original_File = ActivePresentation
DupeName = "TemporaryFile.pptx"
DupeName = original_File.Path & pathSep & DupeName
original_File.SaveCopyAs DupeName, ppSaveAsOpenXMLPresentation
origName = Left(original_File.Name, InStrRev(original_File.Name, ".") - 1)
For lIndex = 1 To original_File.SectionProperties.Count
If original_File.SectionProperties.SlidesCount(lIndex) > 0 Then
Set File_Segment = Presentations.Open(DupeName, msoTrue, , msoFalse)
File_name = File_Segment.SectionProperties.Name(lIndex)
For K = original_File.SectionProperties.Count To 1 Step -1
If File_Segment.SectionProperties.Name(K) <> File_name Then
Call File_Segment.SectionProperties.Delete(K, 1)
End If
Next K
outputFname = pathSep & origName & "_" & original_File.SectionProperties.Name(lIndex) & "_" & Format(Date, "YYYYMMDD")
With File_Segment
.SaveAs FileName:=.Path & outputFname & ".pptx", FileFormat:=ppSaveAsOpenXMLPresentation
.Close
End With
Set File_Segment = Nothing
End If
Next
Set original_File = Nothing
Kill DupeName
MsgBox "Split completed successfully!"
End Sub
This works for me (except for the filename):
Option Explicit
Sub ExportSlidesAsPresentations()
Dim oPres As Presentation
Dim sSlideOutputFolder As String
Set oPres = ActivePresentation
sSlideOutputFolder = oPres.Path & "\"
'Export all the slides in the presentation
Call oPres.PublishSlides(sSlideOutputFolder, True, True)
Set oPres = Nothing
End Sub