VBA Excel Function to Set the Calling Cell .NumberFormat Property - excel

I created this function and it works to put the value into the cell but it doesnt work to set the .NumberFormat property.
Public Function NewYears(year As Integer)
'Determine the cell that called the function
Dim rng As range
Set rng = ThisWorkbook.Sheets("How-To").range(Application.Caller.Address)
MsgBox rng.Address
fxFormat = "[$" & holidayName & "]"
NewYears = DateSerial(year, 1, 1)
rng.NumberFormat = fxFormat
End Function
Update For more information:
I will be having functions like =NewYears() that returns a date.
I will do this for any number of holidays. I would like to format the field where it still stores the date but the .NumberFormat property has the name of the holiday
So =NewYears() would return "01/01/2014" but in the sheet it would appear as "New Years"

Use the Worksheet_Change event:
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Interior.ColorIndex = 39
Target.NumberFormat = "mm/dd/yyyy"
End Sub
Put this code in the Sheets("How-To") code module. Modify to whatever color/etc that you want to format.
When you initially enter the function in the cell, it will trigger the change event and this subroutine will execute.
Per Gary's comments (below), recalculation of existing formula will not trigger this event.

Functions can only return values or manipulate Comments, they can't modify formats directly.

How many calculations are in your sheet/book?
Are the cells in a particular arranged column or everywhere or Random?
If answer is Yes to first question I wouldn't suggest a volatile function triggers, well no one should. And things you do next depends on the answer to 2nd question.
Why dont you try "conditional formatting" though it could be a bit costly. Else if the Year cell should be in an organized column or cell make sure its format is ready-made to date.... if none of these apply, you may give us a better picture if your sheet's structure/design...

Related

VBA Excel: Write timestamp to cell on change of another cell

I want to insert a timestamp (E3) when the status (B3) changes. This should happen for at least 30 more such examples in the worksheet. The code currently works only for one example (Country1). Do you have an idea how this can be implemented?
I already tried different types but it just worked for example "Country 1" not for "Country 1", "Country 2", "Country 3" etc.
When I adjust the code for the range "B3:I3" then I received an adjustment in every 3rd column, example: I add a comment in D3 then a timestamp will be created in H3. That is not what I want. :(
Is there a way to adjust the code so that as soon as a change is made in the Status column (B3;F3;J3etc.), the Timestamp column (E3;I3 etc.) will reflect the time stamp?
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("B3:B5"))
Is Nothing Then Exit Sub
Application.EnableEvents = False
Target.Offset(0,3).Value = Now
Application.EnableEvents = True
Please, try the next adapted event. It will calculate how many groups of four columns exists and set a range of their first column intersected with rows 3 to 5. Only for this range the event will be triggered:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lastCol As Long, rngCols As Range
lastCol = Me.cells(2, Me.Columns.count).End(xlToLeft).column 'last column on the second row
Set rngCols = Me.Range(trigData(Me.Range("B2", Me.cells(2, lastCol)))) 'create the range of the columns for what the event to be triggered
Set rngCols = Intersect(Me.rows("3:5"), rngCols) 'create the range inside which the change to trigger the event
If Not Intersect(rngCols, Target) Is Nothing Then
Application.EnableEvents = False
Target.Offset(0, 3).Value = Now
Application.EnableEvents = True
End If
End Sub
Function trigData(rngCols As Range) As String
Dim i As Long, strCols As String
For i = 1 To rngCols.Columns.count Step 4 'iterate from four to four and create the necessary columns string address
strCols = strCols & "," & rngCols.cells(i).EntireColumn.address
Next i
trigData = Mid(strCols, 2) 'Mid eliminates the first (unnecessary) comma...
End Function
The code will be confused if you place on the second row data after the necessary groups of four columns. If necessary, one or two such columns, the code can be adapted to work for a fix number extracting the divided integer (without decimals).
The code assumes that you need to be triggered for the mentioned rows (3 to 5). If you need something different in terms of rows to be affected, you should change Me.rows("3:5") according to your need.
Please, send some feedback after testing it.
Your request is a little unclear, and your table format may not have come across correctly in your post. Your code is written to add the current time to a cell 3 columns away from the target cell. It is dynamic, so if you set
If Intersect(Target, Range("B2:I3"))
You are going to get the value in cell 3 columns offset from the changed cell. If you always want it to update column E, then you can use the target.row property...
Cells(Target.Row,5).Value = Now
...to make the row dynamic, and the column static. Clarify your question if this is not what you're looking for. If country2 is in cell F2, where do you want to write the timestamp?
You can use this simple function:
Public Function TimeStamp(Status As Range) As Double
TimeStamp = Now
End Function
So, in Cell E3 will be the formula =TimeStamp(B3). (Format cell E3 appropriately as Time Format)

Why the VBA UDF "Range.Formula =" don't work?

I want to copy the formula from one cell/cells to another cell/cells by Range.Formula = .
But it not work as expected.
If I run the VBA step by step, the function will ended at Range.Formula = without error.
Function test1(sOURCE As Range, tARGET As Range)
tARGET.Formula = sOURCE.Formula
test1 = tARGET.Formula
End Function
You are trying to change another cell's formula with a UDF. According to the Microsoft documentation this cannot be done, but Ryan Wells has actually found a nice workaround. See: How to change another cell with a VBA function UDF. Compare also: VBA: How to change the value of another cell via a function?
We need to use Evaluate on a "helper" sub. I have slightly adjusted the first example provided by Wells to suit your needs:
Function copyFormula(copyFrom As Range, copyTo As Range)
copyFrom.Parent.Evaluate "copyOver(" & copyFrom.Address() _
& "," & copyTo.Address() & ")"
copyFormula = "Formula " & copyFrom.Address() & " -> " & copyTo.Address()
End Function
Private Sub copyOver(copyFrom As Range, copyTo As Range)
copyTo.Formula = copyFrom.Formula
End Sub
This works, but please bear in mind that (intriguingly) the formula will not automatically calculate after insertion, even with calculation set to automatic. Implementation:
Result:
One way to overcome this problem is to include a Worksheet_Change sub for the worksheet where you are using the formula. E.g. simply:
Private Sub Worksheet_Change(ByVal Target As Range)
Calculate
End Sub
But any subsequent action in the sheet seems to trigger the calculation. Also, please be aware that you won't be able to overwrite the target cell while you have a copyFormula in use with this cell. Since it will just keep overwriting it immediately with the formula (with 0 as output, if the above trick isn't applied). This might be confusing to your users.
This is a restriction by design.
Because a UDF cannot change any other cells/formulas. A UDF can only return a value to the cell the UDF was used in. Therefore tARGET.Formula = sOURCE.Formula is not possible.
Also test1 = tARGET.Formula will return the formula of tARGET as text. It will not replace the formula used in the cell nor will it evaluate the formula.

Excel VBA : cells change values depending on specific groups (expanded or collapsed)

I'd like to modify values on specific cells depending on a specific group if it's expanded or collapsed.
I found a way, but it's a manual way (image1 image2) (the macro needs to be launched on each run).
Is there a way to use a function (i.e. worksheet_change), so that will be on real time ?
P.S. Sorry for my bad English and be kind, I'm kinda new on VBA (first code).
Thank you.
Private Sub groups()
If Worksheets("Feuil1").Columns("F").ShowDetail = True Then
Range("K2:K7").Value = "YES"
Else
Range("K2:K7").Value = "NO"
End If
End Sub
Thank you Luuklag for your solution, but as I said in my comment, in your code I have to update manually the placeholder cell which is not what I'm looking for.
But, I found something where my cells get updated by expanding or collapsing my group. And for this, as you said, I need a placeholder cell that gets updated on each calculation.
I use the formula =NOW on cell A1, because it's always useful to know the time and date.
Here is the (combined) code, for those who are looking a solution :
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
'Where F is the column having the group button
If Columns("F").ShowDetail = True Then
'This is where you choose the cells that are dependent to the group and attribute something
Range("G10:G19").Value = "YES"
Else
'Same here. It could be other cells too
Range("G10:G19").Value = "NO"
End If
Application.EnableEvents = True
End Sub
There is a simple solution to this. Every time you expand or collapse a group you trigger the worksheet_calculate event. This can be used to your advantage.
All you need is a placeholder cell, which you populate with a volatile function (a function that changes its value on each calculation). You can use =randbetween(1,10) or =NOW() for example.
You then have your worksheet change event to look for your placeholder cell, AA1 in this example.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AA1")) Is Nothing Then
Call groups
End If
End Sub

Autofill date by referring only one number with excel VBA

What if we could fill a date by only referring a number ? This type of feature would improve user-friendliness in some excel scenarios.
For instance : In March sheet, when I type "7" in a given dates column, the cell in which I inserted the value would return "07/03/19" (or 03/07/19).
If possible, this means I need to specify in the VBA code the month and year for this sheet, and change this variable for every single sheet (february etc.). If the sheet names are months names (Eg "March"), there could even be a way to do it with a one solution VBA code. The following formula takes advantages of it, so I guess VBA could do it to.
=MONTH(DATEVALUE(MID(CELL("filename";$A$1);FIND("]";CELL("filename";$A$1))+1;255)&" 1"))
Enter this formula in a sheet named "March" and it will return "3".
I have been looking for a simple way to do this, but there is none to my knowledge (until you bring your light :)). Data validation feature won't help as far as I know. Also, it's important that the cell in which the number is inserted autofill itself (not another cell).
Is this at least possible ? I bet yes. I've been told to look at event function, but I know too little with VBA.
This may need modified to fit your needs, but maybe a solution like this using the Worksheet_Change event.
Worksheet Change portion:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo SafeExit:
Application.EnableEvents = False
If Target.Cells.Count = 1 Then '
If Not Intersect(Target, Me.Columns("A")) Is Nothing Then 'change as needed
Target.Value = DateFromDay(Me.Name, Target.Value)
End If
End If
SafeExit:
Application.EnableEvents = True
End Sub
Main Function
Public Function DateFromDay(monthName As String, dayNum As Integer) As Date
On Error Resume Next
DateFromDay = DateValue(dayNum & " " & monthName & " " & Year(Now()))
End Function
You might consider the Workbook_SheetChange event as well to add this functionality to multiple sheets.

Excel VBA - Convert string entered in user form to number

I have an excel user form into which the user enters numbers, when those numbers are entered into the spreadsheet they appear with the notification that this is a number stored as text. =SUM(H6:H13) shows a zero result.
I have tried NumCrtn = cLng(NumCrtn) - doesn't change the cell to a number, formula still shows zero.
I have tried NumCrtn = Val(NumCrtn) - doesn't change the cell to a number, formula still shows zero.
I have tried copy and paste.special to a value and that doesn't change it to a number either.
Don't know what to do.
Help!
Try this one:
With Range("H6:H13")
.NumberFormat = "0"
.Value = .Value
End With
Edit:
Another solution. Building on Pradeep Kumar's suggestion which deals with preparing your range before you enter the data, Change your code to something like this
Private Sub UserForm_Initialize()
Dim aCell As Range
Range("H6:H13").NumberFormat = "0"
'This is to cater for any previous values if filled in
For Each aCell In Range("H6:H13")
aCell.Formula = aCell.Value
Next
End Sub
Private Sub CommandButton1_Click()
'Entering value for H6
Range("H6").Value = TextBox1.Value
End Sub
Range("H6:H13").NumberFormat = "#,##0"
It is not a VBA solution, but an ordinary Excel solution.
Do like this
Select the column
Select Data - Text to columns
Quite often the default settings will do and you can click Finish. Otherwise you
will have to make sure that the result is just a "General" column
A macro doing just this would look something like this:
Columns("A:A").TextToColumns
There's a lot of parameters to the TextToColumns method, but it should work fine with default values only (i.e. no parameters).

Resources