textbox will display the string depending on which checkbox is checked - excel

I have a UserForm with 3 checkbox and 1 textbox..I want to display a string in textbox depending on which checkbox is tick.
chkProcessor is tick = Processor is the brain of computer...
chkRam is tick = RAM stick usually we call it memory
chkCmos is tick = It's like a coin type battery..
if 2 or more checkbox is tick then it will display their respective string.
this is the form
Here's my code:
Private Sub chkCmos_Click()
If chkCmos.Value = True Then
txtVerbiage.Text = txtVerbiage.Text & "It's like a coin type battery.." & Chr(10)
Else
' I WANT THE ABOVE TEXT TO BE NOT DISPLAYED THEN
End If
End Sub
Private Sub chkProcessor_Click()
If chkProcessor.Value = True Then
txtVerbiage.Text = txtVerbiage.Text & "Processor is the brain of computer..." & Chr(10)
'I WANT TO HAVE A LINE BREAK HERE.
txtVerbiage.Text = txtVerbiage.Text & "Normally sets below the heat sink..." & Chr(10)
Else
' I WANT THE ABOVE TEXT TO BE NOT DISPLAYED THEN
End If
End Sub
Private Sub chkRam_Click()
If chkRam.Value = True Then
txtVerbiage.Text = txtVerbiage.Text & "RAM stick usually we call it memory" & Chr(10)
Else
' I WANT THE ABOVE TEXT TO BE NOT DISPLAYED THEN
End If
End Sub
Private Sub cmdErase_Click()
txtComment.Text = ""
txtVerbiage.Text = ""
chkProcessor.Value = False
chkRam.Value = False
chkCmos.Value = False
End Sub

Try this:
Private Sub chkProcessor_Click()
DisplayManager
End Sub
Private Sub chkRAM_Click()
DisplayManager
End Sub
Private Sub chkCmos_Click()
DisplayManager
End Sub
Sub DisplayManager()
Dim cb As MSForms.Control, txt As String
txt = vbNullString
Me.txtVerbiage.Value = txt
For Each ctrl In UserForm1.Controls
If TypeName(ctrl) = "CheckBox" Then
If ctrl.Value Then
txt = txt & GetMessage(ctrl.Name) & vbCrLf
End If
End If
Next ctrl
Me.txtVerbiage.Value = txt
End Sub
Function GetMessage(cbName As String) As String
Dim str As String
If cbName = "chkProcessor" Then
str = "Processor is the brain of computer..."
ElseIf cbName = "chkRam" Then
str = "RAM stick usually we call it memory"
ElseIf cbName = "chkCmos" Then
str = "It's like a coin type battery..."
End If
GetMessage = str
End Function
For txtVerbiage set Multiline to True (in VB editor properties)
Each chkXXX calls DisplayManager to manage text display
The text will appear in the order of the chkXXX on the Userform

Related

BeforeUpdate event validation control

Dears,
I want to make a simple userform to record some serial numbers into excel, it contains a textbox_serialNo., a command button “enter” and another command button “cancel”.
I made a validation control in that serialNo textbox so that only number can be entered. However, when I run the program and input some numbers into the textbox, both command buttons (the "enter" button named as label_enter,the "cancel" button named as label_cancel) have no reactions (e.g. the "cancel" button doesn't unload the form when press) , how should I correct the program? Below are the relevant codes, Thanks.
Private Sub TextBox_SerialNo_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If Not IsNumeric(TextBox_SerialNo.Value) Then
TextBox_SerialNo.BackColor = rgbYellow
End If
Cancel = True
End Sub
Private Sub TextBox_SerialNo_AfterUpdate()
If TextBox_SerialNo.Value <> "" Then
TextBox_SerialNo.BackColor = rgbWhite
End If
End Sub
Private sub label_enter_click()
sheet1.Select
Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Select
ActiveCell.Value = ActiveCell.Offset(-1, 0).Value + 1
ActiveCell.Offset(0, 1) = TextBox_SerialNo.Value
TextBox_SerialNo.Value = ""
End Sub
Private Sub Label_Cancel_Click()
Unload Me
End Sub
Sorry to be posting as an answer, not enough rep.
Shouldn't Cancel=True be inside the if statement? You are locking it up regardless of entry being numeric or not as is.
Edit:
Actually upon further testing still not working proper. However, change event works better and you can get instant feedback for any non numerics.
Updated code would look like this, control names differ. I am used to working with .Text, same thing as .Value. Also, since I am not sure what you would do with an empty string, assumed it to be yellow background as well.
One concern would be, can you allow comma or period in there? Depending on locale settings, a decimal would also be considered a numeric.
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdEnter_Click()
If TextBox1.BackColor = rgbYellow Then Exit Sub
test4.Range("A1").Value = TextBox1.Text
End Sub
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1.Text) Or TextBox1.Text = "" Then
TextBox1.BackColor = rgbYellow
Else
If TextBox1.Text <> "" Then
TextBox1.BackColor = rgbWhite
End If
End If
End Sub
Edit 2: I use this piece of code to check for only numbers (assuming number Ascii codes are standard). Maybe it can help.
Public Function isnumber(ByVal strValue As Variant) As Boolean
On Error Resume Next
Dim i As Long
isnumber = True
If Not strValue = "" Then
For i = 1 To Len(CStr(strValue))
If Asc(Mid(strValue, i, 1)) > 57 Or Asc(Mid(strValue, i, 1)) < 48 Then
isnumber = False
Exit For
End If
Next i
Else
isnumber = False
End If
On Error GoTo 0
Err.Clear
End Function
Edit 3: I have revised the TextBox1_Change event code so all invalid characters are stripped right away. However, in this state if you copy paste a serial no with a non-allowed char, it will strip them leaving only the numbers. Not sure if it is acceptable.
Private Sub TextBox1_Change()
If Not isnumber(TextBox1.Text) Or TextBox1.Text = "" Then
TextBox1.BackColor = rgbYellow
Dim i As Long
Dim strValue As String
strValue = ""
If Not TextBox1.Text = "" Then
For i = 1 To Len(CStr(TextBox1.Text))
If Not (Asc(Mid(TextBox1.Text, i, 1)) > 57 Or Asc(Mid(TextBox1.Text, i, 1)) < 48) Then
strValue = strValue & Mid(TextBox1.Text, i, 1)
End If
Next i
End If
TextBox1.Text = strValue
Else
If TextBox1.Text <> "" Then
TextBox1.BackColor = rgbWhite
End If
End If
End Sub

Before_save event excel vb

Excel VB newbie. I know I must be missing something very simple. How do I get before_save event to work with more than one worksheet? Only one needs code. I have it in ThisWorkbook. It works if I only have one sheet in my workbook.
After seeing the comment that it doesn't matter if there's more than one worksheet I looked again at my code. I fixed the code and now the BeforeSave event will trigger and not save until all conditions are met like it's supposed to.
The BeforeSave event triggers if I put it in ThisWorkbook. But if I put it in Sheet1 and call the sub in ThisWorkbook, it still runs the sub like it's supposed to but doesn't prevent it from saving. Hoping this makes sense. I know the code is messy so please bear with me.
Sheet1:
Sub checkSheet1()
Dim cellCount As Variant, findEmpty As String, Counter%
allYellowCellsArray = Array(Range("C6"), Range("C7"), Range("C8"), Range("C9"), Range("C18"), Range("C19"), Range("C20"), Range("C21"), Range("C22"), Range("C29"), Range("C30"), Range("C31"), Range("C32"), Range("C33"), Range("C42"), Range("C62"))
noDateYellowCellsArray = Array(Range("C6"), Range("C7"), Range("C8"), Range("C9"), Range("C18"), Range("C19"), Range("C20"), Range("C21"), Range("C22"), Range("C29"), Range("C30"), Range("C31"), Range("C32"), Range("C33"), Range("C42"))
emptyCell = ""
Counter = 0
Debug.Print vbNewLine & "List the values of each cell in the array:"
'count number of yellow/empty cells
For Each cellCount In allYellowCellsArray
Debug.Print cellCount.Address() & " value is " & cellCount & " and color is " & cellCount.DisplayFormat.Interior.Color
If cellCount = emptyCell Then
Counter = Counter + 1
End If
Next
'If-Then statements to alert how many yellow cells are still empty.
If Counter >= 1 Then
MsgBox "(" & Counter & ") Mandatory Cells Have Not Been Completed", vbExclamation, "Missing Information"
'cellCount = "Enter Missing Information"
End If
For Each cellCount In noDateYellowCellsArray
If cellCount.Value = "" Then
cellCount.Value = "Enter Missing Information"
End If
Next
'Evaluate all yellow cells to prevent empty cells and make sure the set values have been changed ----
Dim cellValue As Variant
Dim fieldsAreYellow As Boolean
fieldsAreYellow = True
Dim redCellColor As Boolean
redCellColor = True
Dim cellCellColor As Variant
Debug.Print vbNewLine & "List cells that are red:"
For Each cellCellColor In allYellowCellsArray 'check for red cells
If cellCellColor.DisplayFormat.Interior.Color = 255 Then 'if cell background color is red
redCellColor = True
Debug.Print cellCellColor.Address() & " is " & cellCellColor.DisplayFormat.Interior.Color
Cancel = True
End If
If redCellColor = False Then
MsgBox "There are no more red cells."
Cancel = True
End If
Next cellCellColor
Dim cellCountRedCells As Variant, redCellCounter%
redCellCounter = 0
For Each cellCountRedCells In allYellowCellsArray
If cellCountRedCells.DisplayFormat.Interior.Color = 255 Then 'red
redCellCounter = redCellCounter + 1
Debug.Print "redCellCounter is " & redCellCounter
'MsgBox "redCellCounter is " & redCellCounter
End If
Next
Debug.Print "redCellCounter is " & redCellCounter
'Check to see if cells in array have been changed
Debug.Print vbNewLine & "List the current background color of the first non-numeric cell that stopped the loop:"
For Each cellValue In allYellowCellsArray
If cellValue = "Enter Missing Information" Then
Debug.Print vbNewLine & cellValue
fieldsAreYellow = False
Debug.Print cellValue.Address() & " color is " & cellValue.DisplayFormat.Interior.Color
MsgBox "Check all of your cells for correct information." & vbNewLine & "There are still (" & redCellCounter & ") red cells.", vbCritical, "SAVE CANCELLED"
Cancel = True ' ** prevent the file from being saved **
Exit For
End If
Next cellValue
'Final check
If (fieldsAreYellow = True) And (redCellCounter = 0) Then
MsgBox "The document will be saved." & vbNewLine & "Remember the naming convention." & vbNewLine & "Customer_PIP Seal Calculator_Part Number rev#_Part Name_DDMMYY", vbInformation, "Good to Go!"
Cancel = False 'allow save
Else:
MsgBox "This file will not save until all of the cells have correct information.", vbCritical, "SAVE CANCELLED"
Cancel = True 'cancel save
End If
End Sub
ThisWorkbook:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Call Sheet1.checkSheet1
End Sub
I created a new excel file and tested this event. It works perfectly on both sheets.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
MsgBox "OK"
End Sub
I suggest to try this on a new file and then copy your code to the new file.
In order to make the event was as you need, the called Sub must be transformed in a Function returning Boolean.
The event code should look like this:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Cancel = Sheet1.checkSheet1
End Sub
And the called function, like this:
Public Function checkSheet1() As Boolean
If 1 = 1 Then
MsgBox "The saving cannot take place..."
checkSheet1 = True 'instead of Cancel = True in the Sub
Else
checkSheet1 = False
End If
End Function
You must adapt your code to finally return something like checkSheet1 = Cancel. But take care to properly declare Dim Cancel as Boolean...
If something unclear, please, do not hesitate to ask for clarifications. If you need me to transform your existing Sub, I can do it, but I think it is better for you do do that, in order to understand the meaning and learn...
Loop Through Worksheets In BeforeSave
Option Explicit
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
' Create a list of worksheet names.
Const wsList As String = "Sheet1,Sheet2,Sheet3"
Dim nms() As String ' Declare an array of type 'String'.
nms = Split(wsList, ",") ' Write the list to the array.
Dim ws As Worksheet ' Declare a worksheet variable.
Dim n As Long ' Declare a 'counter' variable of type 'Long'.
' Loop through the elements (names) in the array.
For n = 0 To UBound(nms)
' Define current worksheet.
Set ws = ThisWorkbook.Worksheets(nms(n))
' Do something, e.g. write some text to cell 'A1' and autofit column 'A'.
ws.Range("A1").Value = "Testing worksheet '" & ws.Name & "'."
ws.Columns("A").AutoFit
Next n
End Sub

Excel VBA function to return a working link to paperwork

I'm trying to error-proof a spreadsheet at work. One thing we've had trouble with is people copy-pasting links then just changing the RMA number. This would work in theory if all the links had the same extension, but some are .xls and some are .xlsx.
I've made it so that when a cell in the RMA column is changed, the cell offset 53 to the right of it gets a hyperlink generated by the public function GetCRRLink() inserted into it.
Private Sub Worksheet_Change(ByVal ChangedCells As Range)
'Some code omitted here, RMA is defined
If Not Intersect(CurrentCell, RMA) Is Nothing Then
Set CurrentCell.Offset(0, 53).Formula = GetCRRLink(CurrentCell.Value)
End If
'Some code omitted here
End Sub
'Meanwhile, in Module 1
Public Function GetCRRLink(RMA As String) As Hyperlink
On Error Resume Next
Dim TryLink As Hyperlink
Set TryLink.TextToDisplay = "CRR Form"
Set TryLink.Address = "redacted" & RMA & ".xls"
TryLink.Follow
If Err.Number = 0 Then
GetCRRLink = TryLink
Exit Function
End If
Err.Clear
Set TryLink.Address = "redacted" & RMA & ".xlsx"
TryLink.Follow
If Err.Number = 0 Then
GetCRRLink = TryLink
Exit Function
End If
Set TryLink.TextToDisplay = "Error"
GetCRRLink = TryLink
End Function
When trying to set the TextToDisplay or Address properties of TryLink, I get "Compile error: Wrong number of arguments or invalid property assignment".
TextToDisplay and Address are String properties. So just remove the Set, which is only used for object assignments. This should do the trick.
TryLink.TextToDisplay = "CRR Form"
TryLink.Address = "redacted" & RMA & ".xls"
...
By the way, you will need the Set when assigning TryLink as the function result.
Thanks TimWilliams!
Private Sub Worksheet_Change(ByVal ChangedCells As Range)
'Some code omitted here, RMARange is defined, events disabled
For Each CurrentCell In ChangedCells.Cells
If Not Intersect(CurrentCell, RMARange) Is Nothing Then
If CurrentCell.Value = 0 Or CurrentCell.Value = "" Then
Call CurrentCell.Offset(0, 53).Hyperlinks.Delete
CurrentCell.Offset(0, 53).Formula = ""
Else
LinkAddress = GetCRRLink(CurrentCell)
Call ThisSheet.Hyperlinks.Add(CurrentCell.Offset(0, 53), LinkAddress, "", "", CurrentCell.Value)
End If
End If
Next
'Some code omitted here, events enabled
End Sub
'Meanwhile in Module 1...
Public Function GetCRRLink(ReadCell As Range) As String
Dim TryUrl As String
Dim RMA As String
RMA = ReadCell.Value
TryUrl = "redacted" & RMA & ".xls"
If HttpTest(TryUrl) = "OK" Then
GetCRRLink = TryUrl
Exit Function
End If
TryUrl = "" & RMA & ".xlsx"
If HttpTest(TryUrl) = "OK" Then
GetCRRLink = TryUrl
Exit Function
End If
GetCRRLink = "Error"
End Function
'Thanks TimWilliams!
Public Function HttpTest(TryUrl As String) As String
Dim FileChecker As Object
Set FileChecker = CreateObject("WinHttp.WinHttpRequest.5.1")
Call FileChecker.SetAutoLogonPolicy(0)
With FileChecker
.Open "GET", TryUrl, False
.Send
HttpTest = .statusText
End With
End Function

Problems with calling function and sub in modular format

I am going to integrate few structure-like sub as follows:
Private Sub txtToNextLVEXP_Recheck()
If txtToNextLVEXP.Value Like "ABC" Then
txtToNextLVEXP.Value = txtToNextLVEXP_Min & " AND " & txtToNextLVEXP_Max
txtToNextLVEXP_check
End If
End Sub
And
Private Sub txtTargetLV_Recheck()
If txtTargetLV.Value Like "ABC" Then
txtTargetLV.Value = txtTargetLV_Min & " And " & txtTargetLV_Max
txtTargetLV_check
End If
End Sub
txtToNextLVEXP_Min, txtToNextLVEXP_Max, txtTargetLV_Min and txtTargetLV_Max are functions;
txtTargetLV and txtTargetLV are MSForms.Control;
txtToNextLVEXP_check and txtTargetLV_check are Sub(s).
It is possible to merge them to be something as follows?
Private Sub Recheck(target as MSForms.Control)
If target.Value Like "ABC" Then
target.Value = (target & "_Min") & " AND " & (target & "_Max")
target & "_check"
End If
End Sub
I stuck with the renaming of target_Min, target_max and target_check, please advice, Thanks a lot.
I would go with something similar to this:
Private Sub Recheck(target As MSForms.Control)
Dim strTarget As String
strTarget = "txtTargetLV" 'or the bellow?
'strTarget = target.Name
With yourFormName 'if you are not on userform, you can access controls via userform name, otherwise "Me" will do
If target.Value Like "ABC" Then
target.Value = .Controls(strTarget & "_Min").Value & " AND " & .Controls(strTarget & "_Max").Value
Application.Run (strTarget & "_check") 'If you are trying to call a function based on the name of your control...
End If
End With
End Sub
I`m not 100% sure I understand what you are trying to achieve, but hope this helps.
If your functions are in the userform code module you can do this:
Private Sub cmCheck_Click()
Recheck Me.txtA
Recheck Me.txtB
End Sub
Private Sub Recheck(target As MSForms.Control)
If target.Value Like "*ABC*" Then
'Use CallByName to run the functions...
target.Value = CallByName(Me, target.Name & "_Min", VbMethod) & " AND " & _
CallByName(Me, target.Name & "_Max", VbMethod) & " (check)"
CallByName Me, target.Name & "_check", VbMethod
End If
End Sub
'functions being called start here....
Function txtA_Min()
txtA_Min = 1
End Function
Function txtA_Max()
txtA_Max = 10
End Function
Function txtB_Min()
txtB_Min = 11
End Function
Function txtB_Max()
txtB_Max = 20
End Function
Sorry for bothering again, the callbyname function is excellent, my program works fine with a structure similar with the following program:
Public Function InputCorr(Target As MSForms.Control) As Boolean
If FrmAddRecord1Shown Then
Target.Value = CallByName(frmAddRecord1, Target.Name & "_Min", VbMethod)
ElseIf FrmAddRecord2Shown Then
Target.Value = CallByName(frmAddRecord2, Target.Name & "_Min", VbMethod)
End If
End Function
But I want to further slim it to be something like this:
Public Function InputCorr(Target As MSForms.Control) As Boolean
Dim UF As UserForm
If FrmAddRecord1Shown Then
set UF = frmAddRecord1
ElseIf FrmAddRecord2Shown Then
set UF = frmAddRecord2
EndIf
Target.Value = CallByName(UF, Target.Name & "_Min", VbMethod)
End Function
FrmAddRecord1Shown and FrmAddRecord2Shown are boolean, indicating which userform (frmAddRecord1 or frmAddRecord2)is active.
I was stuck at the "UF" part. Thank you very much for all yours sincere help.

Excel VBA: Why does event trigger twice?

I'm trying to avoid Event loops by disabling Events at crucial points. However, it doesn't always work. For instance, this code for a Combo box:
Private Sub TempComboS_Change()
Dim e
e = Application.EnableEvents
Application.EnableEvents = False
'
Application.EnableEvents = e
End Sub
The blank line is where the useful code goes; as it stands it obviously doesn't do anything. However, when I run it this way (with the blank line), it reaches "End Sub", then it goes back to the beginning and runs again. (This would make the useful code run twice).
Why is this happening?
EDIT: To clarify for the folks who've been helping me.
I have a macro that opens the dropdown list of the Combo box, activates it, then ends. It works properly. When I select an item from the open list, the Change event runs. This is the current version of the change event:
Private Sub TempComboS_Change()
End Sub
I put a breakpoint on the Private Sub line. It shows that this Change event runs, then runs again. I suspect that it has been doing this all along, and I noticed it now because I need to add code here.
I have no class modules or userforms. The controls are on a worksheet.
I'm going to try the "Run Once" suggestion, and I'll let you know if it works.
I tried the "Run Once" code you suggested. It sort of works, but I seem to have a bigger issue. When I select a drop-down list from a data-validated cell, the TempComboS_Change event triggers -- but not only didn't I touch this combo box, the cell isn't the LinkedCell for the combo box. In other words, it seems to be triggering by actions unconnected to the combo box!
Got to find out about that Call Stack thing...
Here is a bit of code to help investigate "sequence of events" issues
In a Standard Module
Public Enum eNewLine
No
Before
After
Both
End Enum
Public Function timeStamp(Optional d As Double = 0, Optional newLine As eNewLine = No, Optional Indent As Long = 0, _
Optional Caller As String, Optional Context As String, Optional message As String) As String
Dim errorMessage As String
If Err.number <> 0 Then
errorMessage = "ERROR: " & Err.number & ": " & Err.Description
Err.Clear
End If
If d = 0 Then d = Time
With Application.WorksheetFunction
timeStamp = .Text(Hour(d), "00") & ":" & .Text(Minute(d), "00") & ":" & .Text(Second(d), "00") & ":" & .rept(Chr(9), Indent)
End With
If Len(Caller) <> 0 Then timeStamp = timeStamp & Chr(9) & Caller
If Len(Context) <> 0 Then timeStamp = timeStamp & ": " & Chr(9) & Context
If Len(message) <> 0 Then timeStamp = timeStamp & ": " & Chr(9) & message
Select Case newLine
Case Before
timeStamp = Chr(10) & timeStamp
Case After
timeStamp = timeStamp & Chr(10)
Case Both
timeStamp = Chr(10) & timeStamp & Chr(10)
Case Else
End Select
If Len(errorMessage) <> 0 Then
timeStamp = timeStamp & Chr(9) & errorMessage
End If
End Function
At the top of each Module
'Module level Trace Hearder
Const debugEvents as Boolean = True
Const cModuleName As String = "myModuleName"
Const cModuleIndent As Long = 1
You can assign a module level indent for each module to organise the hierarchy an make it easy to understand.
In each Sub or Function (or property if you need)...
sub mySubName()
Const cMyName As String = "mySubName"
If debugEvents Then Debug.Print timeStamp(NewLine:=Before,Indent:=cModuleIndent, Caller:=cModuleName, Context:=cMyName, Message:="Start")
'Do stuff
If debugEvents Then Debug.Print timeStamp(NewLine:=After,Indent:=cModuleIndent, Caller:=cModuleName, Context:=cMyName, Message:="End")
End Sub
...Or you can use Me.Name for the Context if its a form or a sheet etc. and you can put whatever message or variable values you like in the Message.
You can also use a Timer (eg MicroTimer) and put the result in the Message section.
Here is an example output:
15:54:07: Roll-Up Select: Worksheet_Activate: Start: 3.24591834214516E-03
15:54:07: cDataViewSheet: Class_Initialize: Start
15:54:07: cRevealTarget: Class_Initialize: START
15:54:07: cRevealTarget: Class_Initialize: END
15:54:09: cDataViewSheet: startTimer: : START
15:54:09: cDataViewSheet: startTimer: init Timer
15:54:09: cOnTime: Class_Initialize
15:54:09: cOnTime: Let PulseTime: Inheret PulseTime from host sheet
15:54:09: cDataViewSheet: startTimer: : END
15:54:09: Roll-Up Select: Worksheet_Activate: END: 1.38736216780671
Private Sub cmbOrder_Change()
If cmbOrder = "" Then Exit Sub
Dim arr As Variant, maxorder As Integer
arr = Range("rngOrder")
maxorder = WorksheetFunction.Max(arr)
Dim errmsg As String, err As Boolean
err = False
errmsg = "This value must be a whole number between 1 and " & maxorder + 1
Dim v As Variant
v = cmbOrder.Value
If IsNumeric(v) = False Or (IsNumeric(v) = True And (v > maxorder + 1) Or v < 1)
Then
MsgBox errmsg
cmbOrder = ""
err = False
Else
txtOrder.Value = cmbOrder.Value
End If
End Sub
A bit late to the party but the problem of code repetition can be shown here in similar circumstances. Remove the first line of code and any error messages are dished out twice. This is because of the line that clears the ComboBox that is regarded as a change and picks up another error as null input is an error! May help someone with similar issue.
The Combobox_Change() will fire whenever there is a change in the combobox. For example
Option Explicit
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Bah Blah"
End Sub
Private Sub CommandButton1_Click()
'~~> If something is selected in the combo then
'~~> this line will cause ComboBox1_Change to fire
ComboBox1.Clear
End Sub
Private Sub ComboBox1_Change()
MsgBox "A"
End Sub
So if you load the userform and select an item ComboBox1_Change will fire. You then use the commanbutton to clear the combo the ComboBox1_Change will again fire.
There is one more scenario when the change will again fire. When you change the combobox from the ComboBox1_Change event itself. Here is an example. And I believe this is what is happening in your case.
Scenario 1
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Bah Blah"
End Sub
Private Sub ComboBox1_Change()
MsgBox "A"
ComboBox1.Clear
End Sub
Scenario 2
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Bah Blah"
ComboBox1.AddItem "Bah Blah Blah"
End Sub
Private Sub ComboBox1_Change()
MsgBox "A"
ComboBox1.ListIndex = 1
End Sub
In the first scenario you can getaway with
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Bah Blah"
End Sub
Private Sub ComboBox1_Change()
If ComboBox1 <> "" Then
MsgBox "A"
End If
End Sub
In the 2nd Scenario, you can use something like this
Dim boolRunOnce As Boolean
Private Sub UserForm_Initialize()
ComboBox1.AddItem "Bah Blah"
ComboBox1.AddItem "Bah Blah Blah"
End Sub
Private Sub ComboBox1_Change()
If boolRunOnce = False Then
MsgBox "A"
boolRunOnce = True
ComboBox1.ListIndex = 1
Else
boolRunOnce = False
End If
End Sub

Resources