How to get consistent shape name when adding new slides? - vba

I have a macro that lets me insert text in a text box in all slides, based on my excel file. The problem is that when I insert a new slide with a placeholder the shapes in that new slide is renamed with a different number, even when I name them in the slide master. Is there a way for the shapes to keep their name when I insert a new slide?
Example:
My PPT VBA code:
Slide.Shapes("Title 1").TextFrame.TextRange.Text = blablabla
Slide.Shapes("Subtitle 2").TextFrame.TextRange.Text = blablabla
In my slide master, I have named my shapes "Title 1" and "Subtitle 2" respectively.
After I exited slide master, I add a new slide (note: not duplicate slide). However, it became "Title 3" and "Subtitle 4". The numbering will be different.
Appreciate your advise on how to keep the Name same when we add a new slide.

If You want to do this automatically you need to create event procedure. First in VBE you add a class module, name it clsAppEvents and add code
' Class module clsAppEvents
Option Explicit
Public WithEvents App As Application
Sub App_PresentationNewSlide(ByVal oSld As Slide)
' Add your code here e.g.
oSld.Shapes(1).Name = "Title 1"
oSld.Shapes(2).Name = "Subtitle 2"
End Sub
Then in your Module1 add this
' Module code
Option Explicit
Public oAppEvents As New clsAppEvents
Sub InitialiseApp()
Set oAppEvents.App = Application
End Sub
Now if you run InitialiseApp() (once is enough) every time you add new slide your Sub App_PresentationNewSlide will execute. (In event class you may further define other events procedures too).

Related

Maintain Slide.Name when copying slide

At this link, the official documentation says of the Slide.Name property says:
If you copy a slide from one presentation to another, the slide loses the name it had in the first presentation and is automatically assigned a new name in the second presentation.
I can see the rationale for this. However, I am now trying to implement a procedure which guarantees unique names. Specifically, in the first presentation, I run this code:
Dim last As Long: last = GetLastSlideNumber("LastSection")
Dim i As Integer
For i = 1 To last
With ActivePresentation.Slides(i)
Dim newName As String: newName = "new" & i
.Name = newName
End With
Next
which names all the slides in this presentation as new1, new2, etc. Then, I run similar code in the other one to name the slides as old1, old2, etc.
Now, I have guaranteed that the names are unique. Is there any way I can leverage off this to copy slides over without losing the slide name?
Try maybe do it trough the event class
' AppEvents class module
Option Explicit
Public WithEvents App As Application
Private Sub App_PresentationNewSlide(ByVal Sld As Slide)
Sld.Parent.Slides(Sld.SlideIndex).Name = "MyuniqueSlideName#Number"
End Sub
Then you call from Module1
' Module 1
Option Explicit
Public pApp As AppEvents
Sub GetAppClass()
Set pApp = New AppEvents
Set pApp.App = Application
End Sub
After that, every time you add new slide the App_PresentationNewSlide will occur.

Change one interactive textbox based on input of another

I have an interactive textbox in my powerpoint, which I can input text into while presentation mode. I am wondering how I can change the text within another interactive textbox on another slide to what I input in the original interactive textbox?
I have tried some code in vba:
ActivePresentation.Slides(8).Shapes("TextBoxNAME2").TextFrame.TextRange.Text = "TEST"
to no avail. Any ideas?
Concerning your sample
ActivePresentation.Slides(8).Shapes("TextBoxNAME2").OLEFormat.Object.Text = "TEST"
Or maybe this.
If it is an ActiveX Textbox object you may use event handler:
' put this in Slide's module, where You input new value at
' e.g Slide No.1 Module
Private Sub TextBox1_LostFocus()
' You want to update TextBox1 ona Slide 2
Slide2.TextBox1.Text = Me.TextBox1.Text
End Sub

Deleting specific ActiveX Objects in MS Word using VBA without affecting other buttons

I am trying to delete two specific objects, an combobox named ComboBox1 and a button named btnselect.
The code would run when clicking the btnselect.
The code that I've written is this one:
Dim obj1 As Object
For Each obj1 In ActiveDocument.InlineShapes
If obj1.OLEFormat.Object.Name = "ComboBox1" Then
obj1.Delete
End If
Next obj1
Dim obj2 As Object
For Each obj2 In ActiveDocument.InlineShapes
If obj2.OLEFormat.Object.Name = "btnselect" Then
obj2.Delete
End If
Next obj2
Also, I have tried the following code:
ActiveDocument.InlineShapes(1).Delete
ActiveDocument.InlineShapes(1).Delete
Both the code work and the specified ActiveX objects are deleted.
However, after running this code, the other buttons that have vba code attached to them would not work.
To be more specific, the problem occurs only when a create new document based on the template. If I run the buttons directly from the template, there is no problem. Without these codes, the buttons work as intended in a new document based on the template.
Could you help me find a way to delete these two objects without interfering with the other objects?
LATER EDIT: I narrowed the code down as much as I could so that the problem still persists.
Private Sub btnselect_Click()
ActiveDocument.InlineShapes(1).Delete
End Sub
Private Sub btnSubmit_Click()
MsgBox "Working"
End Sub
Private Sub btnPrint_Click()
MsgBox "Working"
End Sub
The template has three buttons, btnselect, btnSubmit and btnPrint and it contains the above-mentioned VBA code.
I want to delete the btnselect in a new document that's based on the template.
If I create a new document based on the template and click the btnselect, the button gets deleted, but then the other two buttons aren't working anymore.
If I open the template and click the btnselect, the button gets deleted and the other two buttons are working (they are displaying the messages).
To keep the other buttons working, don't delete any button. If you delete it, all other buttons from your ActiveDocument loose their reference to their VBA-code within your template.
Unfortunately you can not simply hide command buttons, but you may disable them and set their size to 1x1 points:
With ActiveDocument.InlineShapes(1)
.OLEFormat.Object.Enabled = False
.Width = 1
.Height = 1
End With

VBA Word Macro to Allow User to Select and Copy Text Multiple Times

I am working on a VBA script with Microsoft Word that allows the user to select text that will be be copied to the clipboard so that it can exported to an Excel file. The user will make a number of selections and finally indicate he/she is done when the contents of the clipboard will be copied to a template Excel file.
There are two forms: the first (UserForm1 in the code below) queries the user for the Word filename. The filename variable is passed to the second form. The second form (frmModeLessForInput) is a modeless form. The behavior I need is that program control goes to the second form with two buttons "Continue" and "Done".
The user is allowed to navigate the document and place the cursor anywhere in the document. Then when "Continue" is pressed the form will call a subroutine (Highlight_Sentence) to copy the selected text to a "clipboard" variable. When "Done" is pressed control will be passed to called main module which will then copy the clipboard to the Excel file.
Below is the code. I have noted with comments where I am trouble with the code. One problem is the variables defined as Public in the ThisDocument module are not defined in the userforms and their subroutines.
The second problem is in the main module that the frmModelessForInput is supposed to be displayed and control is not supposed to be transferred to next statement {MsgBox "Sentences will now be copied to Excel file"....this is where I will put the code to copy the clipboard to the Excel file.} but the message appears before the frmModelessForInput form is run...thus the clipboard will be empty.
The third problem is that in frmModelessForInput form the statement str_clipboard = str_clipboard + str_clipboard_line is not working. Each time the "Continue" button is pushed str_clipboard loses it previous contents.
Any assistance in resolving these problems is appreciated. As VBA programming is a sideline for me I am still learning.
Note this an updated question Pause VBA Word macro, allow user to make a selection, and restart where it left off adding some more detail on the requirement and the sample code.
MAIN MODULE:
Option Explicit
Public str_clipboard As String
Public txt_active_document As String
Public i_how_many_sentences As Integer
Private Sub Test_master_macro()
UserForm1.Show
i_how_many_sentences = 0
Call DisplayModeless
MsgBox "Sentences will now be copied to Excel file" 'Problem: this msg displays before the frmModelessForInput is displayed
End Sub
Sub DisplayModeless()
Dim frm As frmModelessForInput
Set frm = New frmModelessForInput
With frmModelessForInput
.str_word_doc_filename = txt_active_document
.str_no_copied = "0"
.Show False
End With
Set frm = Nothing
End Sub
USERFORM1: form has field for user entering the document filename to user (str_filename) and a command button to close form (cmd_start_selecting_text)
Private Sub cmd_start_selecting_text_Click()
'User enters filename on form for use in frmModelessForInput subroutine
txt_active_document = UserForm1.str_filename 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
Unload Me
End Sub
FRMMODELESSFORINPUT: Form displays filename of Word file entered in UserForm1 and how many sentences have been copied to the clipboard
Option Explicit
Private Sub cmdContinue_Click()
Dim str_clipboard, str_clipboard_line As String
Call Highlight_Sentence(str_clipboard_line)
i_how_many_sentences = i_how_many_sentences + 1 'Problem: VBA reports i_how_many_sentences as undefined even though it is a Public variable
frmModelessForInput.str_no_copied = i_how_many_sentences 'Same Problem
str_clipboard = str_clipboard + str_clipboard_line 'Problem: each time I select a new text/sentence str_clipboard does not contain the contents of the previous selection
End Sub
Private Sub cmdDone_Click()
Me.Hide
End Sub
Private Sub UserForm_Activate()
'Position the form near the top-left of the window
'So that the user can work with the document
Me.Top = Application.ActiveWindow.Top + 15
Me.Left = Application.ActiveWindow.Left + 15
End Sub
Private Sub Highlight_Sentence(clipboard As String)
'This sub extends the selection to the entire sentence and copies the selection, the page number on which the selection is contained and the filename to the clipboard variable
Dim txt_sentence, txt_page_no As String
With Selection
' Collapse current selection.
.Collapse
' Expand selection to current sentence.
.Expand Unit:=wdSentence
End With
txt_sentence = Selection.Text
txt_page_no = Selection.Information(wdActiveEndPageNumber)
clipboard = txt_active_document & vbTab & txt_page_no & vbTab & txt_sentence & vbCrLf 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
End Sub
From what you stated you are running this from the ThisDocument Class Module and unless you fully qualify your references to those Public variables with the Class Name that is why you cannot access them from the UserForms Class Modules.
If you are going to leave your "Main Module" code in the ThisDocument Class Module then whenever you reference those Public variable you need to add ThisDocument.str_clipboard to the command.
I recommend however, to place your Main Module in a general Module such as NewModule and if you need to run it at a Document_Open event that you put a call to the Main Module and its Public variables in the Private Sub Document_Open event of the ThisDocument Class Module.
Your Msgbox is appearing at the wrong time because you are displaying a modeless user form, which means the VBA script thread continues to run after the UserForm is displayed. Move the Msgbox to the UserForm_Activate routine of the second UserForm you are displaying or move it to the Click_Done routine of the first UserForm before you Hide or Unload it.
Finally, you are not really using the Clipboard and using that term makes your code confusing in my opinion. I think you should rename it. Your code also appears to just be building one continuous string of text. Is that really what you want to do? Or, do you really mean to capture each selected text string and ultimately place each into separate cells within an Excel Worksheet? If that is the case, use an Array for the separate text strings.

VBA: Code not running after ToggleFormsDesign

I have the following code in VBA (MS Word), that is meant to run after I click in a button, named cmdFormPreencher inserted in my Document:
Private Sub cmdFormPreencher_Click()
'
If ActiveDocument.FormsDesign = False Then
ActiveDocument.ToggleFormsDesign
End If
'
ThisDocument.cmdFormPreencher.Select
ThisDocument.cmdFormPreencher.Delete
ActiveDocument.ToggleFormsDesign
'
UserForm2.Show
End Sub
The purpose of the code above is to delete that button inserted in my document.
But when I run the code only the button is selected. When I tried to figure out what is happening by debugging, it showed me the code runs until ActiveDocument.ToggleFormsDesign and not running the code remaining
Is this a bug of VBA, or am I doing something wrong? If so, how can I get around this problem?
Thanks!
Note: The ActiveX button is not in Header and Footer. The Text Wrap is set to In Front of Text
Edit:
When I try to run a macro, activating FormDesign, Selecting the ActiveX button and then deleting, I get this code:
Sub Macro1()
'
' Macro1 Macro
'
'
ActiveDocument.ToggleFormsDesign
ActiveDocument.Shapes("Control 52").Select
Selection.ShapeRange.Delete
ActiveDocument.ToggleFormsDesign
End Sub
But when I run this code nothing happens...
This is by design. When an Office application is in Design Mode code should not run on an ActiveX object that's part of the document.
I take it this is an ActiveX button and in that case, it's a member of the InlineShapes or Shapes collection - Word handles it like a graphic object. It should be enough to delete the graphical representation, which you can do by changing it to display as an icon instead of a button.
For example, for an InlineShape:
Sub DeleteActiveX()
Dim ils As word.InlineShape
Set ils = ActiveDocument.InlineShapes(1)
ils.OLEFormat.DisplayAsIcon = True
ils.Delete
End Sub
You just have to figure out how to identify the InlineShape or Shape. You could bookmark an InlineShape; a Shape has a Name property.
EDIT: Since according to subsequent information provided in Comments you have a Shape object, rather than an InlineShape, the following approach should work:
Dim shp As word.Shape
Set shp = ActiveDocument.Shapes("Shape Name") 'Index value can also be used
shp.Delete
Note that Word will automatically assign something to the Shape.Name property, but in the case of ActiveX controls these names can change for apparently no reason. So if you identify a control using its name instead of the index value it's much better to assign a name yourself, which Word will not change "on a whim".
Activate Design Mode.
Click on the control to select it
Go to the VB Editor window
Ctrl+G to put the focus in the "Immediate Window"
Type the following (substituting the name you want), then press Enter to execute:
Selection.ShapeRange(1).Name = "Name to assign"
Use this Name in the code above