How can I set focus through Word vba range.find - vba

I am writing a macro in Word, for replacing some text with a mapped definition.
I want to give the user the option to give confirmation for each replace, just like the default Find & Replace.
How can I set focus on the text that is found?
How can the particular section be scrolled into view?
I need to use custom VBA code(rather than default Find & Replace) as I have to process the document after reading in the mappings.
I am already able to replace the text, and also show the alerts to the user.
However, I want to put the focus on the text while showing the alert.
Current code:
Do While myRange.Find.Execute( _
FindText:=dict.Items()(i) & " (" & Word & ")", _
MatchCase:=False, _
MatchWholeWord:=True _
)
myRange.Select
If MsgBox("Replace '" & myRange.Find.Text & "' with '" & Word & "'?", vbYesNo) = vbYes Then
myRange.Text = Word
End If
myRange.Start = myRange.Start + Len(myRange.Find.Text)
myRange.End = cached
Loop
p.s. I have a custom form/dialog open, from which the macro is being run;
so the text is behind the dialog.
EDIT: Based on Jay's response, I again checked the behavior of the Find & Replace dialog. The dialog gets moved based on the location of the text. Can I achieve the same when I have a form and a confirmation dialog over the text?

The statement myRange.Select that's already in your code puts the Selection on the found text, and scrolls it into view if it's offscreen. That won't help, though, if the Selection is hidden behind a custom form (userform?) or the message box. You may be able to move the form out of the way, if you can figure out where the Selection is with respect to the screen coordinates.

Related

How to count how many tabs are in a selection using Macro for formatting tables

I have to format a large document for a file that has been created from a PDF which is editable, so I know all the text is there.
The document is a series of tables. In Word the tables look pretty OK, but in some cases where there should be various cells there is just 1 and tabs have been used to align the text. So, it looks good, but if any of the text gets changed then the formatting will get messed up. I would like to have a macro that looks for cells with a tab, selects the cell, counts the number of tabs, divides the cell into the right number of cells and puts the text into the right cell. For example, a cell that contains "text 1 [tab]text 2[tab]text 3" would become 3 cells "text 1", "text 2" and "text 3".
I thought Word would be able to convert the text to a table, but when the text is already in a table it doesn't work.
If anyone has any suggestions as to how I might achieve this, then they would be much appreciated!
My main issue is not knowing how to count how many tabs are in a selection.
This function will return the number of Tabs in the given string.
Function CountTabs() As Integer
Dim Txt As String
Txt = "This is" & vbTab & "a test" & vbTab & "to count Tabs"
CountTabs = Len(Txt) - Len(Replace(Txt, vbTab, ""))
End Function
The tab character - Chr(9) - is replace with nothing and the number of tabs is the difference in character count before and after the replacement. Here is an implementation of the idea in a snippet.
Private Sub Snippet()
Dim Txt As String
Dim Count As Integer
Txt = "This is" & vbTab & "a test" & vbTab & "to count Tabs"
Count = Len(Txt) - Len(Replace(Txt, vbTab, ""))
MsgBox "There are " & Count & " tabs."
End Sub
Of course, how you get the text for the variable Txt is another story and, in the context of this forum, another question. Prophylactically, I advise against using the Selection object, however. Try to use the Range object instead.

Hide commandbutton when coverting Word Doc to PDF

When converting to pdf using a commandbutton that creates an Outlook email, coverts docfile to pdf, and attached file - the pdf file still displays the commandbuttons on the form.
Is there a way to hide the commandbuttons or make them invisible before converting from Word Doc to pdf format.
If VName.Value = "" Then
Doc.SaveAs ("Quotation_Blank 2016") Else
FileName = "QFORM" & "_" & JNumber.Value & "_" & VName.Value
Doc.ExportAsFixedFormat OutputFileName:=THE_PATH & FileName, _
ExportFormat:=wdExportFormatPDF
End If
Depending on the button type there might be a Print Object property for the button object that might show/hide the button when being exported. Otherwise you might have to set the Visible property on the button to 'False' before exporting, then turn Visible back to 'True' after. Might depend on if you're using 'ActiveX' controls or 'Form' controls, so you might have to play around with those settings a bit depending on your setup.

Outlook VBA Script Moving Text From Custom Form to Message Body

I have never used Outlook VBA (2010), but my manager tasked me to create a user form that sends IT requests and IS requests. I have the custom form created, where I gather all my text fields and print the text to a single text box.
This action is all defined within Sub CommandButton1_Click(), which ends with Send(). Within the sub, I have something like this for all text boxes:
Set Sj =Item.GetInspector.ModifiedFormPages("P.2").Controls("Subject_Text")
Set YNbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("YNBox")
Set Rbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("ReasonBox")
What I want to know is how do I take the texts within "P.2" and paste it into the Message area of "Message" Page?
Here is the code snippet for the printing out to a single text box:
FinalBox.Text = "Subject: " & Sj.Text & vbCrLf & _
vbCrLf & "Can work around the issue?: " & YNbox.Text & _
vbCrLf & "Reason For Ticketing: " & Rbox.Text & _
vbCrLf & "Department: " & Dbox.Text & _
vbCrLf & "Impact: " & Ibox.Text & _
vbCrLf & "Urgency: " & Ubox.Text & _
vbCrLf & "System/Machine Number: " & Mbox.Text & _
vbCrLf & "Was trying to accomplish: " & Abox.Text & _
vbCrLf & "Has it occured before?: " & Bbox.Text & _
vbCrLf & "First Noticed: " & Tbox.Text & _
vbCrLf & "Others affected by the issue: " & Affbox.Text & _
vbCrLf & "Additonal Comments: " & Addbox.Text
So, how do I take this and append it to the actual message field in Message page?
.
Thank you very much!!
P.S. I've been having issues with MailItem.body and whenever I create an object, for example:
Dim objMsg As Object,
I get an error that says "Expected end of statement"... I understand VB and VBA is different, but I didn't think it'd be giving me this much headache.
Edit:
Hello dbMitch and Tony Dallimore, thanks for helping me clarify my questions. Like I mentioned, I am a mere beginner when it comes to VBA, and I Just wanted to
`Sub Commandbutton
Set Sj = Item.GetInspector.ModifiedFormPages("P.2").Controls("Subject_Text")
Set YNbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("YNBox")
Set Rbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("ReasonBox")
Set Dbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("DepartmentDropbox")
Set Mbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("MachineBox")
Set Ibox = Item.GetInspector.ModifiedFormPages("P.2").Controls("ImpactBox")
Set Ubox = Item.GetInspector.ModifiedFormPages("P.2").Controls("UrgencyBox")
Set Abox = Item.GetInspector.ModifiedFormPages("P.2").Controls("AccomplishBox")
Set Bbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("BeforeText")
Set Tbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("Timebox")
Set Affbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("AffectedBox")
Set Addbox = Item.GetInspector.ModifiedFormPages("P.2").Controls("AdditionalBox")
Set Tbox8 = Item.GetInspector.ModifiedFormPages("P.2").Controls("TextBox8")
Set MESBOX = Item.GetInspector.ModifiedFormPages("Message").Controls("Message")
Tbox8.Text = "Subject: " & Sj.Text & vbCrLf & _
vbCrLf & "Can work around the issue?: " & YNbox.Text & _
vbCrLf & "Reason For Ticketing: " & Rbox.Text & _
vbCrLf & "Department: " & Dbox.Text & _
vbCrLf & "Impact: " & Ibox.Text & _
vbCrLf & "Urgency: " & Ubox.Text & _
vbCrLf & "System/Machine Number: " & Mbox.Text & _
vbCrLf & "Was trying to accomplish: " & Abox.Text & _
vbCrLf & "Has it occured before?: " & Bbox.Text & _
vbCrLf & "First Noticed: " & Tbox.Text & _
vbCrLf & "Others affected by the issue: " & Affbox.Text & _
vbCrLf & "Additonal Comments: " & Addbox.Text
Send
End Sub
`
Sub I found online that is suppose to take an item and append the text onto message body. There seems to be an error every time I try to declare the object's type (Ex. ____ As _____). I was not sure how to modify this to make it fit with my code, but the error is thrown at Dim objItem As Object that says
Expected end of statement
Sub TestAppendText()
Dim objItem As Object
Dim thisMail As Outlook.MailItem
'On Error Resume Next
Set objItem = Application.ActiveExplorer.Selection(1)
If Not objItem Is Nothing Then
If objItem.Class = olMail Then
Set thisMail = objItem
Call AppendTextToMessage(thisMail, "Some text added at " & Now())
End If
End If
Set objItem = Nothing
Set thisMail = Nothing
End Sub
Sub AppendTextToMessage(ByVal objMail As Outlook.MailItem, ByVal strText As String)
Dim objCDO As MAPI.Session
Dim objMsg As MAPI.Message
Dim objField As MAPI.Field
Set objCDO = CreateObject("MAPI.Session")
objCDO.Logon "", "", False, False
If Not objMail.EntryID = "" Then
Set objMsg = objCDO.GetMessage(objMail.EntryID, _
objMail.Parent.StoreID)
objMsg.Text = objMsg.Text & vbCrLf & strText
objMsg.Update True, True
Set objField = objMsg.Fields(CdoPR_RTF_COMPRESSED)
If Not objField Is Nothing Then
objField.Delete
objMsg.Update True, True
End If
Set objField = Nothing
Set objField = objMsg.Fields(CdoPR_RTF_SYNC_BODY_COUNT)
If Not objField Is Nothing Then
objField.Delete
objMsg.Update True, True
End If
Else
strMsg = "You must save the item before you add text. " & _
"Do you want to save the item now?"
intAns = MsgBox(strMsg, vbYesNo + vbDefaultButton1, "Append Text to Message")
If intAns = vbYes Then
Call AppendTextToMessage(objMail, strText)
Else
Exit Sub
End If
End If
Set objMsg = Nothing
objCDO.Logoff
Set objCDO = Nothing
End Sub
I've also tried using a CDO object, but it gives me an error that says
ActiveX component can't create object: 'CDONTS.NewMail'
Set Item1 = Item.MessageClass
Set objCDONTS = CreateObject ("CDONTS.NewMail")
objCDONTS.Body = Tbox8.Text
Item1.Message = "Hi"
I apologize if this seems very simple to others.. I just have 0 experience with VBA/VBScript and Outlook designs. That's why I'm here, to learn!
Please do not ask a question like this again. I do understand the difficulty of telling one’s manager that you lack the background to tackle a task. The typical response seems to be: “It is easy: just look it up on the internet.” In one sense this is true. There is nothing in the answer below that you could not find in other answers. What you lack is the background to identify the features you require and to fit them together to create the solution. VBA is not a difficult language but it has many significant differences from other languages that will confuse an experienced programmer new to VBA. The Outlook Object model takes time to master.
There are many online Excel VBA and Outlook VBA tutorials. I think the Excel VBA tutorials are better. If you are asked to perform a similar task again, you must insist on having the time to study first. These answers of mine might help:
Update excel sheet based on outlook mail
How to copy Outlook mail message into excel using VBA or Macros
I wanted to create a complete solution since I did not believe another snippet would help. You need: “This works. Adjust it step by step to your exact requirement.”
I am not familiar with custom forms and can find nothing that says what advantage they offer over user forms which work with all versions of VBA. I did not want to take the time to study custom forms particularly as I have code for user forms that I can easily adjust to your requirement. If your custom form is working to your satisfaction, replace that part of my solution.
There are five parts to my solution:
The user form.
The first part of the subroutine SendTicket() which loads the user form and calls it to get data from the user.
The subroutine UserForm_Initialize() within the user form’s code which builds the form from parameters supplied by SendTicket().
The subroutine CommandButton1_Click() which performs minimal validation of the user’s data and stores it for SendTicket().
The second part of the subroutine SendTicket() which builds the email from the user’s data and sends it to the IT department.
1. The user form
I inserted a new user form, adjusted its size and added controls. If you do not know how to do this then look at one of the tutorials that introduce user forms.
If I add a label control to a user form and name it X, I can, for example:
Move it by changing X.Top.
Display some text by changing X.Caption.
The user form includes a Collection named Controls. A collection is what most languages call an unsorted list. Within Controls there will be an entry for every control (label, text box, command button, etc.) on the form. If the label X is the first control on the user form, I can access its properties as Controls(0).Top and Controls(0).Caption. This means I can have code specific to label X that reference it by name or I can have general code that handles all or selected labels by their position within Controls. For your requirement, I believed general code would be easier so that is what I have provided.
I created a label control and a text box control. I left the default names but changed some properties:
LABEL TEXT BOX
* Name Label1 TextBox1
Caption Prompt/Name
Font Tahoma 10 Tahoma 10
Height 12 18
Left 12 230
* Multiline True
* Scrollbars 2 - frmScrollBarsVertical
TextAlign 3 – frmTextAlighRight 1 – frmTextAlignLegt
Text/Value abcdefghijklmnopqrstuvwyz
* Visible False False
Width 200 400
* Word wrap True True
Properties starting “*” are important. The others are because I like the way they affect the form’s appearance.
In the UK, “Label1” and “TextBox1” are the default names for the first label and textbox. With Excel, default names vary with the local language; I do not know if this is true for Outlook. Within the code, it tells you how to change the default names if necessary.
My code assumes the captions for the labels will fit on a single line but the text entered into the text boxes may require several lines.
Having created my standard label and text box, I selected them, copied them, pasted them and then moved the copies so they were exactly under the first pair. I repeated this with the four controls then the eight controls and finally the sixteen controls. I ended with a column of sixteen labels and a column of sixteen text boxes. I was not concerned with the vertical position of the controls; I handle that later. If either column is not perfectly aligned, you can select a column and set the Left property for the entire group. I have created forms with hundreds of controls with acceptable performance so add more if you wish.
I created a command button. I lined it up with the text boxes but made the font larger. I retained the default name and caption.
By creating the command button last, the controls are in the correct tab order. The form opens with the cursor in the first (top) field and each tab takes the cursor to the next field and then to the button.
Finally, I set the width of the form so it was a little wider than the controls. I set the height so it was close to the screen height which on my laptop is about 560. It is possible to get the screen height from the system but that is beyond the scope of this answer. I set the caption to “Report issue”. I named it P2 which the closest I can get to your name (P.2 is an invalid name for a user form). The result was:
** 2. Part 1 of subroutine SendTicket()**
A macro cannot directly send parameters to a user form or receive values back. It must use global variables. P2Params is the global I use to pass data to the user form and I use P2Values to pass data back.
P2Params = Array("Subject", …) is the statement that loads P2Paramswith parameters. The first three parameters are "Subject", 18, True which specify the first text box. The prompt/name is “Subject”, the height is 18 and it is mandatory. Each further set of three parameters defines another text box.
I could have defined all this information within the form but getting a form like this looking the way you want can be very fussy particularly if you change your mind about the height of a text box so all the lower ones have to be moved down. With this approach you can change a text box’s height or change the sequence or add a new field with no hassle at all. Note: height defines the height allocated to the control. On my laptop and with my choice of font, 54 is enough for four lines. If the user types a fifth line, the scroll bars will appear against the relevant control so the user can see all the lines. You specify height of each text box based on some average or typical ticket but it does not matter if the user wants to enter more text than you expected.
Load P2 loads the form into memory and calls UserForm_Initialize() to initialise the form. .Show vbModal passes control to the form. Control is not returned until the user does something to return control. In this case, clicking the command button returns control providing the entered values pass the validation code.
3. The subroutine UserForm_Initialize()
I do not intend to say too much about this sub-routine. Comments within the code fully explain what the code does and the image below shows the result:
If you look down the parameters in P2Params. You can see where this layout came from. The beauty of this approach is that with a different set of parameters, a very different form can be produced. A requirement to import a list of text values is not uncommon so I have used variations of this code before and will again.
4. The subroutine CommandButton1_Click()
The user can enter values into the text boxes in required. Once they are correct, the user clicks the command button which was been re-captioned “Send” by the first part of subroutine SendTicket().
This routine validates that all mandatory fields have a value. I have implemented permitted ranges and other validation but this is sufficient for your requirement. If the field values are acceptable, the routine loads the entered values into array P2Values. As I said, only by storing values in a global variable can a user form return values to the caller.
5. The second part of the subroutine SendTicket()
This code takes the values from P2Values builds the email and sends it. I have send emails to an experimental Gmail account. You will need to replace the recipient with the address of your IT Department.
Summary
There is a lot here for you to think about. Work through it slower and come back with questions if necessary
SendTicket()
Option Explicit
Public Type FieldDtl
CtrlLabel As Long
CtrlTextBox As Long
Height As Long
Mandatory As Boolean
Prompt As String
End Type
Public P2Params As Variant
Public P2Values() As String
Sub SendTicket()
Dim InxFld As Long
Dim InxPrm As Long
Dim MailItemCrnt As MailItem
P2Params = Array("Subject", 18, True, _
"Can you work around the issue?", 18, True, _
"Reason For Ticketing", 30, True, _
"Department", 18, False, _
"Impact", 18, True, _
"Urgency", 18, True, _
"System/Machine Number", 18, True, _
"Was trying to accomplish", 54, True, _
"Has it occured before?", 18, True, _
"First Noticed", 18, False, _
"Others affected by the issue", 42, True, _
"Additional Comments", 54, True)
' Used to test total height of control exceeding height of screen
'P2Params = Array("Subject", 50, True, _
' "Can you work around the issue?", 50, True, _
' "Reason For Ticketing", 50, True, _
' "Department", 50, False, _
' "Impact", 50, True, _
' "Urgency", 50, True, _
' "System/Machine Number", 50, True, _
' "Was trying to accomplish", 54, True, _
' "Has it occured before?", 50, True, _
' "First Noticed", 50, False, _
' "Others affected by the issue", 54, True, _
' "Additional Comments", 54, True)
Load P2
With P2
.CommandButton1.Caption = "Send"
.Show vbModal
End With
' The bounds of P2Values are 1 to number of fields
' The bounds of P2Params could be 1 to NumberOfFields*3 but is almost
' certainly 0 to NumberOfFields*3-1
Set MailItemCrnt = CreateItem(olMailItem)
With MailItemCrnt
.BodyFormat = olFormatPlain
.Recipients.Add "AbbeyRuins33#gmail.com"
.Subject = P2Values(1) ' Assumes subject is first field
.Body = P2Params(LBound(P2Params) + 3) & ": " & P2Values(2)
InxFld = 3
For InxPrm = LBound(P2Params) + 6 To UBound(P2Params) Step 3
.Body = .Body & vbCrLf & P2Params(InxPrm) & ": " & P2Values(InxFld)
InxFld = InxFld + 1
Next
.Display
' .Send
End With
Set MailItemCrnt = Nothing
End Sub
Code for user form
Option Explicit
' In UK, the default name for a label is "LabelN" and the default name for a text box
' is "TextBoxN". In case the default name is different is non-English speaking
' countries, I use constants for these values. Change the value of these constants
' as necessary.
Const NameLabel As String = "Label"
Const NameTextBox As String = "TextBox"
' This code assumes there are N labels named NameLabel & 1 to NameLabel & N and
' N text boxes named NameTextBox & 1 to NameTextBox & N. NameLabelX is used to
' label TextBoxX which is used to obtain the Xth value from the user.
' User type FieldDtl is defined in the SendTicket module
Dim Fields() As FieldDtl
Private Sub CommandButton1_Click()
Dim ErrMsg As String
Dim InxFld As Long
' Check values have been entered for mandatory fields
ErrMsg = ""
For InxFld = 1 To UBound(Fields)
If Fields(InxFld).Mandatory And Controls(Fields(InxFld).CtrlTextBox).Text = "" Then
If ErrMsg <> "" Then
ErrMsg = ErrMsg & vbLf
End If
ErrMsg = ErrMsg & "Please enter a value for " & Fields(InxFld).Prompt
End If
Next
' No value entered for one or more mandatory fields
If ErrMsg <> "" Then
Call MsgBox(ErrMsg, vbOKOnly)
Exit Sub
End If
' Save values for caller
ReDim P2Values(1 To UBound(Fields))
For InxFld = 1 To UBound(Fields)
P2Values(InxFld) = Controls(Fields(InxFld).CtrlTextBox).Text
Next
Unload Me
End Sub
Private Sub UserForm_Initialize()
Const GapBetweenCtrls As Long = 5
Dim InxCtrl As Long
Dim InxFld As Long
Dim InxPrm As Long
Dim NumFields As Long
Dim NumParams As Long
Dim TopNext As Long
' Note: LBound(P2Params) can be zero or one but will almost certainly be zero.
' This code allows for either possibility.
NumParams = UBound(P2Params) - LBound(P2Params) + 1
Debug.Assert NumParams Mod 3 = 0
NumFields = NumParams / 3
ReDim Fields(1 To NumFields)
' Import values from P2Params
' P2Params must contain 3N paramerers where N is the number of values
' to be obtained from the user. The three values are:
' Prompt/Name for value.
' Height of value (so control can be sized for multi-line values).
' Mandatory? (True is a value must be entered)
InxFld = 1
For InxPrm = LBound(P2Params) To UBound(P2Params) Step 3
Fields(InxFld).Prompt = P2Params(InxPrm)
Fields(InxFld).Height = P2Params(InxPrm + 1)
Fields(InxFld).Mandatory = P2Params(InxPrm + 2)
InxFld = InxFld + 1
Next
' Controls can be accessed by name (for example Label1.Caption) or
' by position within the collection Controls (for example
' Controls(1).Caption). Add control numbers to Fields().
For InxCtrl = 0 To Controls.Count - 1
If Left$(Controls(InxCtrl).Name, Len(NameLabel)) = NameLabel Then
' Extract number at end of name
InxFld = CLng(Mid(Controls(InxCtrl).Name, Len(NameLabel) + 1))
If InxFld <= NumFields Then
' This control will be used
Fields(InxFld).CtrlLabel = InxCtrl
End If
ElseIf Left$(Controls(InxCtrl).Name, Len(NameTextBox)) = NameTextBox Then
InxFld = CLng(Mid(Controls(InxCtrl).Name, Len(NameTextBox) + 1))
If InxFld <= NumFields Then
' This control will be used
Fields(InxFld).CtrlTextBox = InxCtrl
End If
End If
Next
' For InxFld = 1 To NumFields
' Debug.Print Fields(InxFld).Name & " " & Fields(InxFld).Height & " " & _
' Fields(InxFld).Mandatory & " " & Fields(InxFld).CtrlLabel & _
' " " & Fields(InxFld).CtrlTextBox
' Next
' Now have information necessary to build form.
' This code assumes/relies on:
' * All properties of the textbox controls being correct
' except for Top and Height.
' * All properties of the label controls being correct except for Top.
' * The Height of the label controls being less than the Height of any
' Textbox control.
' * The Visible property of the label and textbox controls being false.
' * The Multiline property of the textbox controls being true
' * The Scrollbars property of the textbox controls being
' 2 = frmScrollBarsVertical
' * The Width of the label property being such that all captions fit.
TopNext = GapBetweenCtrls
For InxFld = 1 To NumFields
With Controls(Fields(InxFld).CtrlLabel)
.Top = TopNext
.Caption = Fields(InxFld).Prompt
.Visible = True
End With
With Controls(Fields(InxFld).CtrlTextBox)
.Top = TopNext
.Height = Fields(InxFld).Height
.Text = ""
.Visible = True
End With
TopNext = TopNext + Fields(InxFld).Height + GapBetweenCtrls
Next
With CommandButton1
.Top = TopNext
TopNext = TopNext + .Height + GapBetweenCtrls
End With
' Set scroll height so if total height of controls exceeds height
' of form, user can scroll from top to bottom.
ScrollHeight = TopNext
End Sub

Delete Selected Text in a Text Box

Hey fellow Stackoverflow users,
i'm trying to create a text editor with HTML tag functions (for export) and can't get a solution working. Therefor i created a textbox where the user should be able to insert the text. For this insert function i need the in the title described function to delete the selected text (only the selected text, the text around it stays) inside the textbox. Even SendKeys won't function right.
Please let me know if anyone got an idea, thanks upfront!
EDIT: Here's the corrected code for the bold button with maintextbox as textbox for the user's text:
Private Sub BoldButton_Click()
If maintextbox.SelLength = 0 Then
MsgBox ("Please highlight the text you want to edit!")
Else
SelectionText = maintextbox.SelText MsgBox ("SelText: " & SelectionText)
maintextbox.SelText = "<b>" & _
SelectionText & _
"</b>"
End If
End Sub
Simply:
TextBox.SelText = ""
The .Sel* methods all relate to the text currently selected within the control. SelText = "" replaces the current selection with nothing, thereby deleting it whilst preserving the surrounding unselected text.

Set a different Page footer for each Page in Excel

I have tested the sample code in the corresponding MSDN article:
Sub WorkWithPages()
' Fill random data:
Range("A1", "R100").Formula = "=RANDBETWEEN(1, 100)"
Dim pgs As Pages
Set pgs = PageSetup.Pages
PageSetup.DifferentFirstPageHeaderFooter = True
' Look in the Immediate window for this output:
Debug.Print "The current sheet can be printed on " & _
pgs.Count & " page(s)."
Dim pg As Page
Set pg = pgs(1)
pg.CenterHeader.Text = "This is the first page's header"
Set pg = pgs(2)
pg.CenterFooter.Text = "This is the second page's footer"
Set pg = pgs(pgs.Count)
pg.CenterFooter.Text = "This is the last page's center footer."
pg.LeftHeader.Text = "This is the last page's header"
' Note that Excel supports only distinct headers/footers
' for the first page, so headers and footers on the second
' and other pages are combined--the last value set overwrites
' the header/footer.
' See the values in the Immediate window.
' Note that the code disregards errors that occur--attempting
' to retrieve a header/footer setting that doesn't exist raises an error:
On Error Resume Next
Debug.Print "First page (CenterHeader) : " & pgs(1).CenterHeader.Text
Debug.Print "Second page (CenterHeader): " & pgs(2).CenterHeader.Text
Debug.Print "Second page (CenterFooter): " & pgs(2).CenterFooter.Text
Debug.Print "Third page (CenterFooter) : " & pgs(3).CenterFooter.Text
Debug.Print "Last page (LeftHeader) : " & pgs(pgs.Count).LeftHeader.Text
Debug.Print "Last page (CenterFooter) : " & pgs(pgs.Count).CenterFooter.Text
' In conclusion, use the Page class to retrieve information about headers
' and footers for specific pages. Use the PageSetup object to set the headers
' and footers, as it's clearer to set them there.
End Sub
But the values output by the Debug.Print "Second page (CenterFooter): " & pgs(2).CenterFooter.Text line differ from what is expected:
Second page (CenterFooter): This is the last page's center footer
Instead of the right: Second page (CenterFooter): This is the second page's footer.
I have tried different things but all the CenterFooter keep always the last input value. How can I change this behaviour such that each page gets the exact footer I want?
There are different footers/headers configurations but none of them allows to write a different value for each page. You can write a different text for the first page and for even/uneven pages; also you can add some formatting with certain variations page to page (e.g., page number) but this is it. In Word the rules are equivalent.
Regarding the MSDN code you provided, one of its comments says:
Note that Excel supports only distinct headers/footers for the first
page, so headers and footers on the second and other pages are
combined--the last value set overwrites the header/footer.
And thus this code is actually working as expected; although it is not too clear at first sight.
I know this is resurrecting a thread from the dead, but this is actually do-able in Excel VBA. I had to figure it out as I couldn't find an acceptable solution here, so I'm leaving this for the next poor sod:
The solution is to create a subroutine to set the header and footer, and then call that routine within a loop in a different sub, calling each worksheet one at a time and managing what you want to say by variable.
So something like this:
Sub InsertQuoteHeaderAndFooter(ByVal shtHeader As Worksheet, strText$)
shtHeader.PageSetup.RightFooter = "&""Calibri"" &8 &K434643" & strTxt & " | &P of &N"
End Sub
Then call it in a For loop, modulating shtHeader and strText as needed. Hope this helps the next archaeologist.