VB6 Textbox fontweight manipulation - string

I have a VB6 application where I want to manipulate certain parts of a string I am outputting inside a textbox.
txtPhoneNums.Text = "Home: " + strHomeNo + vbCrLf _
+ "Mobile: " + strMobileNo + vbCrLf + "Work: " + strWorkNo + vbCrLf
It's nested inside an if statement that carries out various validations. I want to be able for example, in the above snippet to highlight the word "Work" and the appended string value "strWorkNo" in red and fontweighted bold. Can I do this easily without creating multiple textboxes (and leaving the other two values as default appearance?)
Thanks.
Image added for clarity. I want the two null field strings to be red and bold.

You want to use the RichTextBox. I would recommend that you don't try to mess around with the rich text format (RTF) itself, but instead use the standard methods.
Your code would be changed as follows:
Option Explicit
Private Sub Command1_Click()
WritePhoneNums "01020239", "07749383", "0234394349"
End Sub
Private Sub WritePhoneNums(ByRef strHomeNo As String, ByRef strMobileNo As String, ByRef strWorkNo As String)
Dim nPosBeginningOfWorkNo As Long
Dim nPosCurrent As Long
txtPhoneNums.TextRTF = vbNullString ' Clear existing code.
' Clear style to default.
ApplyNormalStyle txtPhoneNums
' Enter standard text. The selection will be at the end of the text when finished.
txtPhoneNums.SelText = "Home: " + strHomeNo + vbCrLf _
& "Mobile: " + strMobileNo + vbCrLf + "Work: "
' Save the cursor position, write the work number, and then save the cursor position again.
nPosBeginningOfWorkNo = txtPhoneNums.SelStart
txtPhoneNums.SelText = strWorkNo
nPosCurrent = txtPhoneNums.SelStart
' From this information, select the preceding text, and make it "selected".
txtPhoneNums.SelStart = nPosBeginningOfWorkNo
txtPhoneNums.SelLength = nPosCurrent - nPosBeginningOfWorkNo
ApplyHighlightedStyle txtPhoneNums
' Reset the selection to the end, and reset the text style.
txtPhoneNums.SelStart = nPosCurrent
txtPhoneNums.SelLength = 0
ApplyNormalStyle txtPhoneNums
txtPhoneNums.SelText = vbCrLf
End Sub
Private Sub ApplyNormalStyle(ByRef txt As RichTextBox)
txt.SelBold = False
txt.SelColor = vbBlack
End Sub
Private Sub ApplyHighlightedStyle(ByRef txt As RichTextBox)
txt.SelBold = True
txt.SelColor = vbRed
End Sub

Related

Formatting Inputs with Rules in VBA

not sure how do phrase this question but I really dont understand it.
I want to achieve the following:
TextBox = TextVorname
TextBox = TextNachname
For Example I put in the 1. Textbox "Markus"
and put in the 2. Textbox "Neumann"
I want it to display in the Bookmark "Ma.Ne_2022"
I have following Code:
Private Sub OptionButton1_Click()
Dim VornameStr As String
VornameStr = Me.TextVorname.Caption
Dim NachnameStr As String
NachnameStr = Me.TextNachname.Caption
MyStrVorname = Left(VornameStr, 2)
MyStrNachname = Left(NachnameStr, 2)
MyStrFullname = MyStrVorname & "." & MyStrNachname & "_2022"
Call UpdateBookmark("test1", Me.MyStrFullname.Caption)
End Sub
Your question is a little bit vague.. Maybe this is what you're after?
Dim MyVornameStr As String
Dim MyNachnameStr As String
Dim MyStrFullname As String
MyStrVorname = Left(Me.TextVorName.Text, 2)
MyStrNachname = Left(Me.TextNachName.Text, 2)
MyStrFullname = MyStrVorname & "." & MyStrNachname & "_2022"
Call UpdateBookmark("test1", MyStrFullname)

If not contain specific text = TRUE in UDF

I need help to fix this UDF.
I need the result to be "Salentein Malbec" when
Familia is different from "ESPUMOSO" (done)
Marca is equal to "SALENTEIN"(done)
Cepa is equal to "MALBEC" (done)
Formato is equal to "B0750" (done)
Material does not contain the characters "TDF" (pending, i need help with this part)
Function PRODUCTDESCRIPTION(Familia, Marca, Cepa, Formato, Material)
If Familia <> "ESPUMOSO" And Marca = "SALENTEIN" And Cepa = "MALBEC" And Formato = "B0750" And Material <> "*TDF*" Then
PRODUCTDESCRIPTION = "Salentein Malbec"
End If
End Function
You can do it like this because of having a problem in the last part I am showing you that, you can use it in VBA also.
=ISNUMBER(SEARCH("TDF",D7))
Here is how you can do it in VBA, I have created a function for that just for testing, you can implement that in your code.
simply you can use InStr(whereTo, word) and it returns the position where the word is located at
InStr(whereTo, word) // return integer number.
here is a sample I have created for you.
Private Sub CommandButton1_Click()
Call SearchForWord("TDF", Sheet1.Range("D6"))
End Sub
Sub SearchForWord(word As String, whereTo As Range)
Dim foundAt As Integer
foundAt = InStr(whereTo, word)
If foundAt > 0 Then
TextBox1.Text = word + " has found at " + CStr(foundAt)
MsgBox "Cell not contain " + word + " at " + CStr(foundAt)
Else
TextBox1.Text = word + " has not found at " + CStr(foundAt)
MsgBox "Cell not contains " + word
End If
End Sub

Translate formula quotation marks incl. replacements into VBA-readable formulae

Translate formula quotation marks incl. replacements into VBA-readable formulae
I was inspired to write this post by the recent question of
formula substitution using a constant.
At the same time, the frequent problem emerged that quotation marks
within a formula string should be replaced by double quotation marks in order
to make them readable in VBA.
Practical use case
A practical use case is to copy a table formula directly from a SO website
and "translate" it into a string-readable format.
But how is this supposed to be done with VBA means, since the direct input of
such an incomplete formula string in a procedure code without manually
added double quotation marks would immediately lead to an error?
Another feature would be to make replacements at certain points within
a formula template, for example with a constant or even with several
numerically identifiable markers.
I found a quick & dirty solution (without error handling) by analyzing a FormulaContainer procedure containing
exclusively outcommented formulae as these would allow any prior direct code input.
In order to distinguish them from the usual commentaries,
I decided with a heavy heart to use the Rem prefix (i.e. Remark) as an alternative, which we may still be familiar with from ancient Basic times.
My intention is not to show a perfect solution, but to stimulate further solutions
by demonstrating a possible way.
Question
Are there other work arounds allowing to copy tabular formulae with quotation marks directly and as possible replacement pattern into VBA procedures?
///////////////////////////////////
Main function QuickFormula()
References a FormulaContainer procedure containing exclusively formulae with Rem prefixes, such as e.g.
Sub FormulaContainer()
Rem =....
Rem =....
End Sub
This allows formula inputs with quotation marks similar to tabular cell inputs;
furthermore these inputs may contain string identifiers facilitating wanted replacements.
Option Explicit
'Site: https://stackoverflow.com/questions/70399681/how-many-quotes-to-put-around-a-formula-that-is-sending-an-empty-string
'Auth: https://stackoverflow.com/users/6460297/t-m
Function QuickFormula(ByVal no As Long, ParamArray repl() As Variant) As String
'Purp: - change indicated code line in FormulaContainer to code readable string and
' - replace enumerated identifiers with given value(s)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'1) get REMark code line indicated by ordinal argument no
QuickFormula = getCodeLine("modFormula", "FormulaContainer", no)
'2a)replace "#" identifyer(s) with constant repl value
If Not IsArray(repl(0)) Then
QuickFormula = Replace(QuickFormula, "{1}", "#")
QuickFormula = Replace(QuickFormula, "#", repl(0))
If Len(QuickFormula) = 0 Then QuickFormula = "Error NA!"
Debug.Print no & " ~~> " & Chr(34) & QuickFormula & Chr(34)
Exit Function
End If
'2b)replace 1-based "{i}" identifiers by ParamArray values
Dim i As Long
For i = LBound(repl(0)) To UBound(repl(0))
QuickFormula = Replace(QuickFormula, "{" & i + 1 & "}", repl(0)(i))
Next
'3) optional display in immediate window
Debug.Print no & " ~~> " & Chr(34) & QuickFormula & Chr(34)
End Function
Help function getCodeLine()
Gets a given code line of the indicated procedure
Function getCodeLine(ByVal ModuleName As String, ByVal ProcedureName As String, Optional ByVal no As Long = 1) As String
'Purp: return a code line in given procedure containing "Rem "
'Note: assumes no line breaks; needs a library reference to
' "Microsoft Visual Basic for Applications Extensibility 5.3"
Const SEARCH As String = "Rem =", QUOT As String = """"
'1) set project
Dim VBProj As Object
Set VBProj = ThisWorkbook.VBProject
If VBProj.Protection = vbext_pp_locked Then Exit Function ' escape locked projects
'2) set component
Dim VBComp As Object
Set VBComp = VBProj.VBComponents(ModuleName)
Dim pk As vbext_ProcKind
'3) get no + 3 top code line(s)
With VBComp.CodeModule
'a)count procedure header lines
Dim HeaderCount As Long: HeaderCount = .ProcBodyLine(ProcedureName, pk) - .ProcStartLine(ProcedureName, pk)
'b) get procedure code
Dim codelines
'codelines = Split(.Lines(.ProcBodyLine(ProcedureName, pk), .ProcCountLines(ProcedureName, pk) - HeaderCount), vbNewLine)
codelines = Split(.Lines(.ProcBodyLine(ProcedureName, pk), no + 1), vbNewLine)
'c) filter code lines containing "Rem" entries
codelines = Filter(codelines, SEARCH, True)
End With
'4) return (existing) codeline no
If no - 1 > UBound(codelines) Then Exit Function ' check existance
getCodeLine = Replace(Replace(codelines(no - 1), QUOT, String(2, QUOT)), "Rem =", "=")
End Function
Example call
References all three formulae in the FormulaContainer (including an example of a non-existing number):
Sub EnterFormula()
With Sheet1.Range("X1") ' << change to any wanted target range
.Offset(1).Formula2 = QuickFormula(1, 6)
.Offset(2).Formula2 = QuickFormula(2, Array(10, 20, 30))
'two single argument inputs with same result
.Offset(3).Formula2 = QuickFormula(3, Array(17))
.Offset(4).Formula2 = QuickFormula(3, 17)
'not existing formula number in Rem code container
.Offset(5).Formula2 = QuickFormula(333, 17)
End With
End Sub
Example FormulaContainer
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Purp: formula container to be adjusted to code readable strings
'Note: Insert only Formulae starting with "Rem "-prefix!
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' # identifies constant replacement(s)
' {i} stands for enumerated replacements {1},{2}..{n}
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sub FormulaContainer()
Rem =IF($V#>0,IF($G#>$S#,($S#-$H#)*$K#+$Y#,($G#-$H#)*$K#+$Y#),"")
Rem =A{1}*B{3}+C{2}
Rem =A{1}+100
End Sub
Example output in immediate window
1 ~~> "=IF($V6>0,IF($G6>$S6,($S6-$H6)*$K6+$Y6,($G6-$H6)*$K6+$Y6),"""")"
2 ~~> "=A10*B30+C20"
3 ~~> "=A17+100"
3 ~~> "=A17+100"
333 ~~> "Error NA!"
Keep it simple stupid
Assuming either the currently selected cell formula or a textbox input, a simple Userform might act as a formula translator into a line of VBA code:
Basic Userform code
Needed: TextBox1, TextBox2, CommandButton1
Option Explicit
Private Sub CommandButton1_Click()
'Purp: Redouble inside quotation marks
Const Quot As String = """"
Dim assignTo As String
assignTo = "ws.Range(""" & Selection.Address(False, False) & """).Formula2 = "
Me.TextBox2.Text = assignTo & Quot & Replace(Me.TextBox1.Text, Quot, String(2, Quot)) & Quot
End Sub
Private Sub UserForm_Initialize()
'Purp: assume active formula as wanted input
Me.TextBox1 = Selection.Formula2
End Sub
Private Sub UserForm_Layout()
'Purp: example layout textboxes
'a) define textboxes
Dim textboxes() As String
textboxes = Split("Textbox1,Textbox2", ",")
'b) format
Dim i As Long
For i = 0 To UBound(textboxes)
With Me.Controls(textboxes(i))
.Font.Name = "Courier New"
.Font.Size = 12
.MultiLine = True
.EnterKeyBehavior = True
End With
Next i
End Sub
Possible extensions
Of course you might add an insertion routine (inserting e.g. {} brackets) as well as some replacement procedures like in my workaround above.
Just for fun, a basic insertion routine here:
Private Sub CommandButton2_Click()
'Purp: Insert brackets {}
With Me.TextBox1
.SetFocus
If InsertAtCursor("{}", Me.TextBox1) Then
.SelStart = .SelStart - 1
End If
End With
End Sub
Public Function InsertAtCursor(s As String, ctrl As MSForms.Control, Optional ErrMsg As String) As Boolean
'Purpose: Insert the characters at the cursor in the active control.
'Site: http://allenbrowne.com/func-InsertChar.html
'Return: True if characters were inserted.
'Arguments: s = the character(s) you want inserted at the cursor.
' ErrMsg = string to append any error messages to.
'Note: Control must have focus.
On Error GoTo Err_Handler
Dim prior As String 'Text before the cursor.
Dim after As String 'Text after the cursor.
Dim cnt As Long 'Number of characters
Dim iSelStart As Long 'Where cursor is.
Dim txt As String 'text with LineFeeds only
If s <> vbNullString Then
With ctrl ' --> UserForm Control
txt = Replace(.Text, vbCrLf, vbLf) ' LineFeeds only (MultiLine)
If .Enabled And Not .Locked Then
cnt = Len(txt) ' Zählung ohne vbCr's !
'SelStart can't cope with more than 32k characters.
If cnt <= 32767& - Len(s) Then
'Remember characters before cursor.
iSelStart = .SelStart
If iSelStart > 1 Then
prior = Left$(txt, iSelStart)
End If
'Remember characters after selection.
If iSelStart + .SelLength < cnt Then
after = Mid$(txt, iSelStart + .SelLength + 1) ' OP:2
End If
'Assign prior characters, new ones, and later ones.
.value = prior & s & after
'Put the cursor back where it as, after the new ones.
.SelStart = iSelStart + Len(s)
'Return True on success
InsertAtCursor = True
End If
End If
End With
End If
Exit_Handler:
Exit Function
Err_Handler:
Debug.Print Err.Number, Err.Description
Select Case Err.Number
Case 438&, 2135&, 2144& 'Object doesn't support this property. Property is read-only. Wrong data type.
ErrMsg = ErrMsg & "You cannot insert text here." & vbCrLf
Case 2474&, 2185& 'No active control. Control doesn't have focus.
ErrMsg = ErrMsg & "Cannot determine which control to insert the characters into." & vbCrLf
Case Else
ErrMsg = ErrMsg & "Error " & Err.Number & ": " & Err.Description & vbCrLf
End Select
Resume Exit_Handler
End Function

Test several text boxes at once for any blanks

I want to check three different textboxes on a form (but not all) to see if any are left blank. Comparable to "If IsBlank," on the spreadsheet. From what I've read, it seems that IsEmpty can't be used this way? I've been playing with IsNull, but haven't found a proper syntax that would allow it to work. Surely there must be some simple, even standard, way of doing this? Maybe some other function I've never heard of?
(I know I can use If Txtbx1.value = "" Or If... (etc.)
—I'm looking for a shorter and more graceful way to do this.)
Thanks!
Consider using OR:
Sub dural()
If Txtbx1.Value = "" Or Txtbx2.Value = "" Or Txtbx3.Value = "" Then
MsgBox "at least one empty"
End If
End Sub
Match vs Array of Text Boxes feat. IsError, VarType and TypeName
All codes were in a user form code sheet and were run via command buttons on the user form where also the three text boxes were located.
In the first code, the result of Match is passed to the var (variant) variable and further evaluated. If there is at least one text box with no value ("" or vbNullString), var will return the position of the first found empty text box 1-based i.e. the first is 1, the second is 2 etc. unlike the Array which is 0-based i.e. the first element is 0, the second is 1 etc.
The second code is a presentation of the three choices that were studied in the first code.
The third code is a 'bad' code without variables you might be looking for.
Sub TextBoxFun()
Dim vntTB As Variant ' Text Box Array
Dim var As Variant ' Match Variant
Dim strTB As String ' Pass String
Dim lngTB As Long ' Pass Long
' Pass TextBoxes to Text Box Array.
vntTB = Array(TextBox1, TextBox2, TextBox3)
' Either:
var = Application.Match("", vntTB, 0)
' Or:
'var = Application.Match(vbNullString, vntTB, 0)
Debug.Print String(10, "'")
Debug.Print "IsError(var) = " & IsError(var) ' True
Debug.Print "VarType(var) = " & VarType(var) ' 10 or vbError
Debug.Print "TypeName(var) = " & TypeName(var) ' Error
Debug.Print String(10, "'")
' Line of Code / vbNullString Found ? >>> ' True False
Debug.Print var ' 1
' Depending on the first position of ' 2
' the found vbNullString or "". ' 3 Error 2042
lngTB = IsError(var): Debug.Print lngTB ' 0 -1
lngTB = VarType(var): Debug.Print lngTB ' 5 10
'lngTB = TypeName(var): Debug.Print lngTB ' Nope Nope
' TypeName returns always a string.
strTB = IsError(var): Debug.Print strTB ' False True
strTB = VarType(var): Debug.Print strTB ' 5 10
strTB = TypeName(var): Debug.Print strTB ' Double Error
End Sub
Sub TextBoxFunConclusion()
Dim vntTB As Variant ' Text Box Array
' Pass TextBoxes to Text Box Array.
vntTB = Array(TextBox1, TextBox2, TextBox3)
If IsError(Application.Match("", vntTB, 0)) Then
Debug.Print "No 'empty' text boxes (via IsError)."
Else
Debug.Print "At least one 'empty' text box (via IsError)."
End If
If VarType(Application.Match("", vntTB, 0)) = 10 Then
Debug.Print "No 'empty' text boxes (via VarType)."
Else
Debug.Print "At least one 'empty' text box (via VarType)."
End If
If TypeName(Application.Match("", vntTB, 0)) = "Error" Then
Debug.Print "No 'empty' text boxes (via TypeName)."
Else
Debug.Print "At least one 'empty' text box (via TypeName)."
End If
End Sub
Sub TextBoxFunMyChoice()
If IsError(Application.Match("", Array(TextBox1, TextBox2, TextBox3), 0)) _
Then
Debug.Print "No 'empty' text boxes (via IsError)."
Else
Debug.Print "At least one 'empty' text box (via IsError)."
End If
End Sub
Private Sub CommandButton1_Click()
TextBoxFun
End Sub
Private Sub CommandButton2_Click()
TextBoxFunConclusion
End Sub
Private Sub CommandButton3_Click()
TextBoxFunMyChoice
End Sub

VBA Combobox / automatically generate code

I've got a question concerning combobox in Excel.
I've got an excel sheet that by default contains two comboboxes and their number is described by a variable x (x=2 by default). Each combobox is scripted to behave in a particular way in subs, for example I've got: private sub ComboBox1_DropButtonClick().
Nonetheless, sometimes I need to increase the number of these boxes by changing the value of X. I may need up to 10 comboboxes in total. Now the question is whether there's any way in which I can set the behaviour of an infinite number of comboboxes (for example in the event of DropButtonClick). What I did was to write a code for each of those comboboxes, so I've got a sub for ComboBox1_DropButtonClick(), ComboBox2_DropButtonClick(), ComboBox3_DropButtonClick(), etc.. The code varies a bit, but it's repeatable. So it all looks rather dumb and I'm searching for some more ingenious solution. Maybe all those comboboxes can be scripted in one go? If there's any way to do it, please share it with me.
Thanks, Wojciech.
[edit] Location of my code (marked in grey):
Screenshot from VBA editor in VBA
Here is some code to dynamically add controls to an Excel Userform, and add the code behind. The code added will make it display a MessageBox when the ComboBox receives a KeyDown.
The code is somewhat commented, but let me know if you have questions :)
Option Explicit
Sub CreateFormComboBoxes(NumberOfComboBoxes As Long)
Dim frm As Object
Dim ComboBox As Object
Dim Code As String
Dim i As Long
'Make a blank form called 'UserForm1', or any name you want
'make sure it has no controls or any code in it
Set frm = ThisWorkbook.VBProject.VBComponents("UserForm1")
With frm
For i = 1 To NumberOfComboBoxes
Set ComboBox = .designer.Controls.Add("Forms.ComboBox.1")
'Set the properties of the new controls
With ComboBox
.Width = 100
.Height = 20
.Top = 20 + ((i - 1) * 40) 'Move the control down
.Left = 20
.Visible = True
.ZOrder (1)
.Name = "ComboBox" & i
End With
'Add your code for each module, you can add different code, by adding a if statement here
'And write the code depending on the name, index, or something else
Code = Code & vbNewLine & "Private Sub " & "ComboBox" & i & "_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)" & _
vbNewLine & " MsgBox(""hi"")" & vbNewLine & "End Sub"
Next
'Add the code
.CodeModule.InsertLines 2, Code
End With
End Sub
'Run this
Sub Example()
CreateFormComboBoxes 5
End Sub
**Edit**
I figured I might as well add the other approach for adding controls dynamically to an Excel sheet. I'd recommend sticking to UserForms, but, here's a method that should help out when controls are needed in a Sheet.
Sub addCombosToExcelSheet(MySheet As Worksheet, NumberOfComboBoxes As Long, StringRangeForDropDown As String)
Dim i As Long
Dim combo As Shape
Dim yPosition As Long
Dim Module As Object
yPosition = 20
For i = 1 To NumberOfComboBoxes
yPosition = (i - 1) * 50
'Create the shape
Set combo = MySheet.Shapes.AddFormControl(xlDropDown, 20, yPosition, 100, 20)
' Range where the values are stored for the dropDown
combo.ControlFormat.ListFillRange = StringRangeForDropDown
combo.Name = "Combo" & i
Code = "Sub Combo" & i & "_Change()" & vbNewLine & _
" MsgBox(""hi"")" & vbNewLine & _
"End Sub"
'Add the code
With ThisWorkbook
'Make sure Module2 Exits and there is no other code present in it
Set Module = .VBProject.VBComponents("Module2").CodeModule
Module.AddFromString (Code)
End With
'Associate the control with the action, don't include the () at the end!
combo.OnAction = "'" & ActiveWorkbook.Name & "'!Combo" & i & "_Change"
Next
End Sub
Sub Example()
Dim sht As Worksheet: Set sht = ThisWorkbook.Sheets(1)
addCombosToExcelSheet sht, 10, "Sheet1!$A$1:$A$10"
End Sub

Resources