Editing percentage value in Userform TextBox - excel

I am attempting to create a textbox which allows users to input a percentage between 1-5% in my Excel-VBA Userform. I have created the textbox and added code to restrict the formatting to always show as a percentage. My problem is that when I attempt to edit the default percentage in the textbox by pressing backspace the decimal moves two spaces to the right instead of deleting any present values. Below is a copy of my code. Please note that the Textbox is not locked.
Private Sub PV_change()
PV.Text = Format(PV.Value, "Percent")
End Sub

You could do your code in the PV_Exit procedure rather than the _Change procedure, but I still think you're asking for trouble this way :)
Private Sub PV_Exit(ByVal Cancel As MSForms.ReturnBoolean)
PV.Value = Format(PV.Value, "Percent")
End Sub

I agree with the objections made previously, but to show a simple solution without error trapping try this:
Private Sub tbPV_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim dblPV As Double
' don't allow backspace
If KeyCode = Asc(vbBack) Then Exit Sub
' Change string to Double value (without percent sign)
dblPV = CDbl(Replace(Me.tbPV.Text, "%", ""))
' Show the formatted result
Me.tbPV.Text = Format(dblPV, "0.00") & "%"
End Sub
Further Remark Naming a text box 'PV' only doesn' t seem to be state of the art. Adding a prefix - e.g. 'tb' or 'txt'- to all your text boxes gives a hint to to control's original type and could give your code a comprehensible structure.
There are number of naming conventions and divergent opinions, but just to give you an impression have a look at
Hungarian in VBA okay? or search within the Stack Overflow's "naming-conventions" tag.
Best Regards

Related

How do you make the value in a control box update live in VBA?

I have a bare minimum of VBA experience, and I have to edit a tool someone else made a while ago. The values in the textbox for the form control will not update in real time. There are multiple textboxes (I think form control, not sure how to check.) where the user inputs values. However, the box does not update the value inside until a cell is selected.
I don't see anything in the code for this that would affect this. Here's an example from one of the Textboxes.
Private Sub SysA_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
With Sheets("SysA")
If KeyCode = 13 Then
If Len(.SysA.Value) = 5 Then
.SysANum.Activate
Else
MsgBox "Enter in a valid number!"
.SysANum.Value = ""
.SysANum.Activate
End If
End If
End With
End Sub
I've also looked in the properties for the textbox and don't see anything that might affect it. (AutoLoad is set to False and Enabled is set to True)

Is there a why a userform _change procedureal event not be recursive?

I have data in a textbox (call it info) on a userform that I would like the user to be able to change so I set up a info_change() subroutine. Problems are:
(1) as I load initial data into info.text from VBA, the info_change() subroutine is called.
(2) when I go into the info field to change the value INSIDE the info field, it call the info_change() subroutine again and continues to call the routine until the last entry I put in info field = value in info field before changing in (seems recursive)
Any thoughts? Maybe instead of calling it info_change(), call it another procedural event?
Thanks, Marty
Easy example using _AfterUpdate event
Instead of reacting each time a single part of the info textbox got changed by the control's _Change event, it's more efficient to use the _AfterUpdate event pausing till you changed to another control (btw could be easily augmented by a CommandButton procedure).
In order to prevent unnecessary calls a comparison is made between old and current info text using a type definition in the code module's declaration head. Furthermore I added a boolean IsTest variable to this definition to allow a test display of changes made triggering some other stuff in code (see b).
Additional hint: there's no recursion, the Change event or AfterUpdate event are only firing as reaction to each single change or update, i.e. making no difference if triggered via Userform_Initialize settings or an eventual user input, however the condition check prevents the Init from getting active.
Declaration head of Userform code module
Option Explicit ' declaration head of code module
'User defined type
Private Type TThis
cnt As Long
oldTxt As String
IsTest As Boolean
End Type
Dim this As TThis
Private Sub UserForm_Initialize()
'[1]assign text to Info-Control
Me.TextBox1.Text = "bla bla"
'[2]remember text
this.oldTxt = Me.TextBox1.Text
'[3]optional choice of test modus
this.IsTest = True
If this.IsTest Then Debug.Print " #", "Change history", "(new) text" & vbNewLine; 0, Now, this.oldTxt
End Sub
Private Sub TextBox1_AfterUpdate()
'~~~~~~~~~~~~~~~
'~> Example call
'~~~~~~~~~~~~~~~
check Me.TextBox1
End Sub
Sub check(myTextbox As MSForms.TextBox)
' Purp.: compare current text with old text
If this.oldTxt <> myTextbox.Text Then
'a) optional test display
If this.IsTest Then this.cnt = this.cnt + 1: Debug.Print this.cnt, Now, myTextbox.Text
'b) do other stuff
' ...
'c) remember old text
this.oldTxt = myTextbox.Text
End If
End Sub

How to call a macro from a button and pass arguments

I want to add a button to my excel worksheet which should call a macro that can handle one agument (an integer value). Sadly when creating the button, I cannot link any macro that has arguments. Also just typing the macro and the argument does not work.
Is there any simple solution to pass an argument to a macro when a button is pressed?
Yes, you can assign a macro to a button (or other excel controls/menu actions) and pass constant OR variable arguments to it.
In the 'Assign Macro' window (right-click on object and select 'Assign Macro'):
Enclose the macro name in single quotes
e.g. to pass 2 constants: 'Button1_Click("A string!", 7)'
Select 'This Workbook' for the 'Macros in' field
If you wish to pass a variable (like the value of a cell), enclose the parameter in Evaluate()
For example, to pass the value of Sheet1!$A$1 to a button function, you would have the following text in the 'Macro name:' field:
Button1_Click(Evaluate("Sheet1!$A$1"))
If you don't enclose your variable argument with an 'Evaluate' function, excel returns the error 'Formula is too complex to be assigned to an object.'.
I would have included an image if this were allowed on my first post.
Suppose you have a public sub take 1 argument like below (just for explanation purposes.)
And you insert a button on Worksheet like below, and you can not find the macro name when you want to assign your sub to this button.
Now, you can type in your sub name + space + argument manually in single quotes, like below, click ok.
Then you see, problem solved.
Sub ert()
Call ert2(Cells(1,1).Value)
End Sub
Use an activeX control command button and in the button click method, call the sub and pass the argument:
Private Sub CommandButton_Click()
Dim x as Integer
x = 1
Call SomeSub(x)
End Sub
To call this Sub from a button :
Public Sub TestButton(strMessage As String)
MsgBox strMessage
End Sub
... be aware that the Sub won't be listed in the available macros, because it has a parameter. Just type in the call in single quotes : 'TestButton "Hello"'
Called from a regular "forms" button on a worksheet you can do something like this:
Sub TestMe()
Dim c, arr
c = Application.Caller
arr = Split(c, "_")
If UBound(arr) > 0 Then MsgBox "Got " & arr(1)
End Sub
Where the calling button is named (eg) "Button_3"
Or (simpler) right-click the button and enter 'TestMe2 5' (Including the single-quotes)
Sub TestMe2(i)
MsgBox "Got " & i
End Sub
See also: Excel 2010 - Error: Cannot run the macro SelectCell using .onAction
I had trouble with my version of Personal.xlsb!'testForXXXX("Test Test")'. I got an error when clicking the button containing the Macro.
However, I was able to fix it by removing the "(" and ")". So, Personal.xlsb!'testForXXXX "Test Test"' worked (notice the space between testForXXXX and "Test...").
In fact, I didn't need Personal.xlsb! and was just able to use 'testForXXXX "Test Test"'.
I hit the same issue with the assign button not being very useful until I realised that all the potential macros displayed were only the ones in my Personal.xlsb file that took no arguments. Then I typed Personal.xlsb!'macroNameWhichTakesArguments("arg1", ...)' and the sheet picked it up.
I.E. Personal.xlsb!'testForXXXX("Test Test")'
Where the macro testForXXXX take a string as input, then the sheet worked ok.
When you use the assign macro route for a button in excel 2007 at least testForXXXX will not show up in the list of potential macros if it takes args.
I suspect Aaron C got tripped up by this too. Maybe its best not to use a Personal.xlsb file?
I would have liked to comment the answer by QA Collective but I do not have enough reputation point yet. Previous solutions did not work for me, as my macros are in named modules in my VBA project.
With Excel 2013, the way to pass a parameter to a macro using a button that worked in my context is :
'<module name>.<macro name> <parameter>'
e.g
'DataProcessor.disle "myText"'
or
'DataProcessor.editWSProcess True'
(boolean do not need double quotes when passed as parameters)
Please note that single quotes are around the whole expression.

OnKey "Delete" clear combobox

I have a userform with multiple comboboxes. User can type in a new item or pick one from the list.
He can start typing first letters of wanted item but when he makes a mistake and starts with e.g. "b" instead of "n" he has to clear the combobox manually or find the item on the list using mouse or arrows.
I would like to quickly clear the box using the delete key so the user can start typing again. But I don't know where to put this line of code if correct (enter event, change event, some other maybe?).
Application.OnKey "{Delete}", "WyczyscPole"
First Excel needs to know which box the user is in, and then clear it.
I tried to create separate module with a variable that finds out the current combobox name and clear it in next step. But I don't know whether called sub below is even correct.
Sub WyczyscPole()
Dim NazwaPola As ComboBox
NazwaPola = frmZakupy.ActiveControl.Name
NazwaPola.Clear
End Sub
You can use the KeyDown event to capture the Delete key (KeyCode = 46) when the user is in the combobox.
Private Sub NazwaPola_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 46 Then
Me.NazwaPola.Value = vbNullString
End If
End Sub
Please try: frmZakupy.value=''
It's a good practice to don't use special characters like 'ś','ć' in any names.

Lock Select Box Size In Excel

This seems like a simple thing, but I cannot figure it out, or find it online.
If I select 5 cells in a column(say A1:A5), and I would like to move this selection shape(column 1:5) over (to B1:B5); Is there shortcut to do this? Currently I hit the left arrow, and the select box changes size to just B1, and I have to hit shift and select B2:B5. Ideally I would like to discover a hot key that "locks" the shape of the select box.
It has been suggested by colleagues to write a macro, but this is ineffective in many cases. For example what if instead of a column I wanted to do the same thing with a row, or with a different sized shape. It seems likely that excel has this feature built in.
I'm not sure how a macro would be ineffective. I would write procedures similar to what's below, then assign them to hotkeys. Let me know if it works for you.
Option Explicit
Public rowDim As Long
Public colDim As Long
Public putSel as Boolean
Sub togglePutSel()
putSel = Not putSel
End Sub
Sub GetSelShape()
rowDim = Selection.Rows.Count
colDim = Selection.Columns.Count
putSel = True
End Sub
Sub PutSelShape()
Selection.Resize(rowDim, colDim).Select
End Sub
If you want to make it work for whenever you hit the arrow keys, then in your Sheet code, you can use this. You may want to do a quick check that rowDim and colDim aren't 0. The only issue with this is that you'd be stuck with that behavior unless you create a trigger to stop calling PutSelShape. So, I'd suggest one macro (hotkeyed to GetSelShape) to toggle it, and another hotkey for togglePutSel.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If putSel Then
Call PutSelShape
End If
End Sub

Resources