Reputation: 2237
I do a lot of work with numbers with two places after the decimal. My adding machine has the nice feature that I can enter a string of numbers like 123456 and it automatically inserts the decimal for me and shows it as 1234.56. Excel has a feature under Advanced Options that automatically enters a decimal but it's a global option so not as helpful as it might be. So, I set up some VBA code for the App_SheetChange event handler that will do it for me only on cells that are formatted to show numbers with two decimals. That way, I don't get decimals where I don't want them. The code is pretty simple. It looks like this:
If InStr(sFormat, "0.00") > 0 Then
If InStr(".", Source.Formula) = 0 Then
If IsNumeric(Source.Formula) Then
s = "00" & Source.Formula
s = Left(s, Len(s) - 2) & "." & Right(s, 2)
App.EnableEvents = False
Source.Formula = CDbl(s)
App.EnableEvents = True
End If
End If
End If
This works well enough when I am entering data, but if I copy data from another cell, it works if there are significant digits after the decimal but not if it's zeroes. Is there a way to tell if data is being typed into a cell or if it is being pasted from the clipboard?
Upvotes: 0
Views: 179
Reputation: 2237
I guess I have to answer my own question so that I can show my code change, but I am going to accept your answer because most of the key elements were there. I got this to work for both editing and copy/paste. The trick was to recognize when you are pasting. I discovered that I can exit when I am pasting with this line:
If Application.CutCopyMode <> 0 Then Exit Sub
Here is the code:
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Source As Range)
Dim s As String
Dim sFormat As String
Dim iPos As Integer
Dim sDate As String
Dim r As Excel.Range
On Error GoTo ErrHandler:
If InStr(Source.Formula, "=") > 0 Then Exit Sub
If Application.CutCopyMode <> 0 Then Exit Sub
sFormat = Source.NumberFormat
iPos = InStr(sFormat, ";")
If iPos > 0 Then sFormat = Left(sFormat, iPos - 1)
If InStr(sFormat, "0.00") > 0 Then
Application.ScreenUpdating = False
Application.EnableEvents = False
For Each r In Source
If (IsNumeric(r.Value)) And (InStr(r.Formula, ".") = 0) Then
If (CDbl(r.Value) = Round(CDbl(r.Value))) Then
r.Value = r.Value / 100
End If
End If
Next r
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
ErrHandler:
App.EnableEvents = True
End Sub
This is an event handler (is it called a listener in Excel?) for the App_SheetChange event. I put this code in a Class Module although I am not sure at this point that it is required to do that. I saved that file and then chose it as an Add-In in Excel Options but I would probably have to work at it a bit to remember how I did that. Then I just selected that Add-In to be active and now, with your help, I got it to work. Thank you, @joseph4tw. In my version, I also have some code to put the slashes in dates so you don't have to do that, but I need to test that code now with these improvements to see if it works.
Upvotes: 1
Reputation: 5160
How about this?
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim r As Excel.Range
Application.ScreenUpdating = False
Application.EnableEvents = False
For Each r In Target
If (IsNumeric(r.Value)) Then
If (CDbl(r.Value) = Round(CDbl(r.Value))) Then
r.Value = r.Value / 100
End If
End If
Next r
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
This checks if the cell is numeric and if so, then check if it's a whole number. And if it is, then make it a fraction by dividing by 100. This should be much faster than doing it with String manipulation, which is what you're doing now.
Works well with Copy and Paste as well (even multiple cells).
By the way, you'll need to add this to each sheet you want this to happen with.
EDIT: updated the code to be at the Workbook level
Upvotes: 1