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.
Related
i need advice about vba scripting, macros.
So, i have excel table with 3 sheets named: Predujam, OSTATAK NAKNADE, vlookup
Predujam and OSTATAK NAKNADE contains vlookup/xlookup formula which are pulling data from vlookup sheet.
All 3 sheets contain like 4000 lines of data, columns range is A:Q.
For sheet Predujam i use this code (this code is supposed to do calculation only in the rows where the changes occurred):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = ThisWorkbook.Sheets("PREDUJAM").Range("A2:O5000")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
Range("A" & Range(Target.Address).Row & ": O" & Range(Target.Address).Row).Calculate
End If
End Sub
For sheet OSTATAK NAKNADE use same code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = ThisWorkbook.Sheets("OSTATAK NAKNADE").Range("A2:O5000")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
Range("A" & Range(Target.Address).Row & ": O" & Range(Target.Address).Row).Calculate
End If
End Sub
In sheet vlookup
I am using only this code to calculate that sheet only when it is opened:
Private Sub Worksheet_Activate()
Worksheets("vlookup").Calculate
End Sub
And in ThisWorkbook i inserted code that stops automatically calculation:
Private Sub Workbook_Open()
Application.Calculation = xlManual
Application.CalculateBeforeSave = False
End Sub
So basically i wanted to stop all calculations and to calculation only in the rows where the changes occurred.
Problem is: table is still laggy, saving still takes like 20-30 sec to save, and calculation in rows where the changes occurred is also doing with some delay.
My Question: Do i have some mistakes in the codes which could cause lagginess? If there is any better way to write this, can you please tell me how to rewrite it?
I am just beginner in vba scripting so i need some advices.
Thanks! :D
This isn't a proper answer, but a comment doesn't afford me enough space to write all of this...
As someone using VBA you probably appreciate the value of variables, i.e.
calculate something once,
'remember' it in a variable, and then
you can reference that variable efficiently multiple times, rather than, inefficiently, recalculating the something afresh every time you need to use it
Helper cells in the user-interface, while much maligned, are the equivalent of variables in this regard, i.e.
something is calculated once,
'remembered' in a designated cell, and then
that cell can be referenced whenever the result is required, rather than having every formula that needs the result recalculate it from first principles.
Why am I rambling about this ? Given that you are setting Workbook calculation to manual, your file is obviously spending a lot of time calculating: if you audit the formulae in the workbook then you will likely find at least some calculations common to several formulae - if you extract these calculations to designated helper cells, then you can improve performance by having those results calculated only once, and then just referenced from the 'old formulae' rather than having the calculations repeated in each formula in which they currently occur.
In order to avoid the user typing = before they enter an arithmetic operation in a cell (i.e. 5+2, 8*8, etc) I have this code:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Not Intersect(Target, Range("C4:C303")) Is Nothing Then
If Target = "" Then Exit Sub
Application.EnableEvents = False
TempTarget = Target
Target = "=" & TempTarget
If IsError(Target) Then Target = TempTarget
Application.EnableEvents = True
End If
On Error GoTo 0
End Sub
It works perfectly for additions (5+5) and multiplications (9*55), but doesn't work well for divisions and subtractions with small numbers (5-2, 8/9) because Excel treats them as dates. It works well for subtractions and divisions with bigger numbers (that couldn't be dates). I want to have in the cell the arithmetic formula but displaying the result. How can I fix the code so that it always work the way I want?
This isn't as straight-forward to solve as it might appear. If you enter values like 5-2 or 8/9 there's no way to intercept the change taking place to the cell before Excel changes it into a Date format.
However there is a solution, although it may not suit your purpose.
Set the Format of each of the cells you want to apply this to (presumably C4:C303) to "Text" or "#".
Change your code to include the addition of Target.NumberFormat = "General" before setting the value of the cell.
The code to achieve that would look like this:
...
Application.EnableEvents = False
TempTarget = Target
' Add this line to change the format back to General
Target.NumberFormat = "General"
Target = "=" & TempTarget
...
This will then correctly handle cases like 5-2 or 8/9 that would otherwise become dates automatically.
Side Effect
This creates an undesired side effect that if one of the existing calculated cells is edited again later it will now be in "General" format instead of text.
This could be resolved by using the SelectionChange event and by setting the format of the cell to "Text" or "#" again if it's inside the range you are working in, but you'd want to undo that if the user doesn't edit the value of the cell.
It's a bit messy. Excel clearly doesn't lend itself to this type of approach.
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
I have some complicated Excel formatting to do, but I have no idea where to begin.
There are few criteria that need to be met:
When there are cell values in F3 and H3, the time at cell N4 should automatically be the time in N3 plus three hours.
If system time is exceeds the value in N4, and the value in F4 and H4 is still empty, it will trigger a message or format highlighting to inform user that the time is over.
If there is new bath being created in column B, the time in column N will stop adding the time and just left blank for user to key in the new time.
For 1. & 3., you'd simply use an if formula:
=IF(AND(F3<>"",H3<>"",B3=B4),N3+3/24,"")
This is assuming the value in N3 is a time value, otherwise it gets a bit trickier - but hardly impossible.
Your problem statement no. 2 is somewhat trickier, I don't think you can it without VBA, and the code isn't entirely straightforward. However, I'll give it a go. In a similar-ish workbook, I have a line which moves forward to indicate when different tasks needs to be completed. To have the "line" move, I color in a column of cells using conditional formatting, comparing the column of cells to a timestamp I have in Y29. The code I use to update the timestamp is the following, it updates the cells every minute:
In a standard module
Option Explicit
Public setDate As Date
Public Const nameToIgnore = "OAA0006Monitor"
Sub UpdateTime()
If currentUser() = nameToIgnore Then
Else
setDate = Now() + TimeValue("00:01:00")
Application.OnTime setDate, "TimeUp"
End If
End Sub
Sub TimeUp()
If currentUser() = nameToIgnore Then
Else
ThisWorkbook.Worksheets("ArbPlan 2011 (5)").Range("Y29") = Time
UpdateTime
End If
End Sub
Sub KillOnTime()
If currentUser() = nameToIgnore Then
Else
On Error Resume Next
Application.OnTime setDate, "TimeUp", , False
On Error GoTo 0
End If
End Sub
In the ThisWorkbook-module
Option Explicit
Private Sub Workbook_Activate()
UpdateTime
End Sub
Private Sub Workbook_Deactivate()
KillOnTime
End Sub
I don't think this should be very hard to convert to the purpose you want it for, instead of using conditional formatting, you can even have the code do all the formatting for you! :)
Anyway, I hope this gives you a good starting point, feel free to comment if you feel anything is unclear, or if you have trouble understanding any of the logic of the code.
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...