Default values for fields in a new row of a data table - vba

When you have a data table in Excel, part of the standard functionality is that pressing tab in the last cell adds a new row at the bottom of the table. I want to auto-populate that new row with useful default values. In particular I want to put current date-time in one cell, and copy values into some other cells from the previous row of the table.
It is not workable to do that using formulae -- e.g. using =now() for the date-time stamp is inadequate because it will be auto-updated every time the spreadsheet recalculates, whereas I want it to retain the date-time at the moment when the row was added.
So I am trying to write VBA to be triggered by the event of the row being added, and in that code to write values into the cells of the new row. From MS documentation I thought DataTable.TableNewRow would be the appropriate event. But when I try to write any code for that event it is not being executed. When I look up DataTable in the VBA object browser the TableNewRow event is not listed.
Versions:
VBA for Applications 7.1
Excel 2013
So my questions:
Is the direction of my thinking right, or can you suggest a better approach?
Can you offer any working code that does something like this?
Is DataTable.TableNewRow the event I should be working with?
What do I need to do to get that event accessible in my VBA code?

You can try this:
Write this code in Thisworkbook.
Private Sub Workbook_Open()
Set ref_tbl = Sheet1.ListObjects(1).DataBodyRange
End Sub
Then below code in a Worsksheet Object.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo halt
Application.EnableEvents = False
Dim tbl_rng As Range
Set tbl_rng = Me.ListObjects(1).DataBodyRange
If Not Intersect(Target, tbl_rng) Is Nothing Then
If tbl_rng.Rows.Count > ref_tbl.Rows.Count Then
MsgBox "Table increase in size"
'~~> Do your stuff here
Set ref_tbl = tbl_rng
End If
End If
forward:
Application.EnableEvents = True
Exit Sub
halt:
MsgBox Err.Number & ": " & Err.Description
Resume forward
End Sub
You will also need a Module to declare the public variable
Public ref_tbl As Range
So basically, this will tell you when your table increase in size.
If we're able to capture that, then you can do your stuff when that condition is met.
This works in the situation you describe in your question.
It will not work though when you insert row between entries in the table. Anyways, HTH.

Related

Run macro when linked cell changes value (Excel VBA)

I am currently trying to obtain historical information about how the backlog is developing.
My Excel file is based on queries from an Access Database which can give me a view of the current situation.
I would like to automatically run a macro every time the week number changes. I am currently using the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("D3")) Is Nothing Then
Call KPIupdate
End If
End Sub
The macro that should fire is called KPIupdate
My problem is that the Macro only fires if I click the cell. I would like it to just fire when the number changes. The cell "D3" is linked to another cell with the formula =Weeknum(Today();21)
I hope you can help me
According to the MSDN entry for Worksheet_Change:
This event does not occur when cells change during a recalculation. Use the Calculate event to trap a sheet recalculation.
To use Worksheet_Calculate to trap the change in a cell that is set by a formula looking at another cell, you need to set a variable to hold the value of the 'Target' and then check if it has changed after the Calculate event fires.
Here is a simple example:
Option Explicit
Private strCurrentWeek As String
Private Sub Worksheet_Calculate()
If Me.Range("A1").Value <> strCurrentWeek Then
'the linked cell changed
Debug.Print "Sheet1!A1 was changed"
'call another macro
End If
'update the new current week
strCurrentWeek = Me.Range("A1").Value
End Sub
To test this, just set the formula in A1 to be =B1 and then change the value of B1 and check the output in the Immediate window.
You can adapt this code to call KPIupdate where my Debug.Print... statement is.

VB, excel macro pause and resume working if possible

I cannot figure out the best way to do the following problem. Basically my macro (excel, VB) is checking several (100+) worksheets for correct values, if wrong value is found, I want it to stop, give me a warning, then I could have a look into the reason why the value is wrong, correct it manually and then I want to resume the macro, or remember the last value checked so if I return, it remembers where to continue (resume).
My current problem is that it finds the wrong value, then I can either make it stop so I check the problem, or it goes through all the sheets and then I have to remember which sheets had the wrong value.
What I thought of is make a list where the name of sheet is added every time a wrong value is found. The problem is that usually there is more than 1 wrong value in the same sheet if there is a wrong value at all and this added the same sheet name several times to the list. Another problem with that is that I cannot correct the values straight away.
I'm very inexperienced with programming and so would appreciate your idea on how to best approach this problem (I don't want to spend a long time on coding something which wouldn't be efficient for such a "simple" problem).
When the error is found (I'm assuming you've already been able to identify this), you can use the Application.InputBox function to prompt you for a new value.
For example, if rng is a Range variable that represents the cell being checked, and you have some logic to determine where the error happens, then you can just do:
rng.Value = Application.InputBox("Please update the value in " & rng.Address, "Error!", rng.Value)
The inputbox function effectively halts execution of the procedure, while waiting for input from the user.
If InputBox isn't robust enough, then you can create a custom UserForm to do the same sort of thing. But for modifying single range values, one at a time, the InputBox is probably the easiest to implement.
I believe you can handle this task by using one or two static local variables in your macro. A variable declared with "static" rather than "dim" will remember its value from the last time that procedure was run. This can hold where you left off so you can resume from there.
One thing that could be a problem with this solution would be if the macro gets recompiled. That would probably cause VBA to clear the value that the static variable was holding. Just doing a data edit in Excel should not cause a recompile, but you will want to watch for this case, just to make sure it doesn't come up. It almost certainly will if you edit any code between executions.
Create a public variable that stores the cell address of the last checked cell and use a conditional statement to see if it's "mid-macro" for want of a better phrase. here is a very crude example...
Public lastCellChecked As String
Sub Check_Someting()
Dim cell As Excel.Range
Dim WS As Excel.Worksheet
If Not lastCellChecked = vbNullString Then Set cell = Evaluate(lastCellChecked)
'// Rest of code...
'// Some loop here I'm assuming...
lastCellChecked = "'" & WS.Name & "'!" & cell.Address
If cell.Value > 10 Then Exit Sub '// Lets assume this is classed as an error
'// Rest of loop here...
lastCellChecked = vbNullString
End Sub
The best way to do this is to create a userform and as mentioned by prior users create a public variable. When the program finds an error store the cell and initiate the userform. Your code will stop on the userform. When you're done checking the problem have a button on the userform that you can click to continue checking. Your loop can be something like the below.
public y as integer
sub temp1 ()
rw1= range("a500000").end(xlup).row 'any method to create a range will do
if y = null then y=1
for x = y to rw1
cells(x,1).select
'check for the problem your looking for
if errorX=true then
userform1.show
y = activecell.row
exit sub
end if
next x
end sub
What about inserting a button (on the sheet or in a menubar) for stopping?
Insert the code below:
'This at the top of the module
Public mStop As Boolean
'This in the module
Sub MyBreak()
mStop = True
End Sub
'This is your macro
Sub YourMacro()
'This at the top of your code
mStop = False
'Your code
'...
'This code where you want to break
DoEvents '<<<< This makes possible the stop
If mStop Then
mCont = MsgBox("Do you want to continue?", vbYesNo)
If mCont = vbNo Then
Exit Sub
Else
mStop = False
End If
End If
'Your code
'...
End Sub
Now you need to create a button and link it to the macro called "MyBreak".

Need to run a VBA Macro on data refresh in excel

I am attempting to prompt a macro to run on a data refresh. I have the macro that needs to be run build, but I am having an issue with the new values not being used since the macros embedded in the sheet are called using ActiveX ComboBoxs.
I am finding several instances where people refer to AfterRefresh and BeforeRefresh, but I think I am misunderstanding how this would take effect and call a macro.
I currently am running ComboBoxs so I have multiple instances of
Private Sub ComboBox22_Change()
'do stuff
End Sub.
but I need the 'do stuff' to occur upon a data refresh, including refreshes that happen automatically and upon sheet open.
I don't want to tie the refresh to a specific box because the items that are refreshed are not dependent on any one instance of data change.
Any help is greatly appreciated.
Thank you.
Maybe a worksheet change event would help in this situation.
Right Click the sheet tab, select "View Code", Select "Worksheet" then "Change."
Code will automatically kick in when a specific range of cells has been changed.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub ' this stops code error if more than one cell is changed at once
If Not Application.Intersect(Target, Me.Range("A1:C10")) Is Nothing Then ' indicates the Target range
MsgBox "You have changed " & Target.Address & " to " & Target
End If
End Sub
You could also use Worksheet_pivottableupdate event to run the macro. You set it up in a similar way to davesexcel answer above.
The connection in question may not be a pivot table but you can use a small and fast pivot table as a trigger.
Set the pivot table to update at the same time as your connection (e.g. set to self refresh every 5 minutes or on workbook open).

Turning off a worksheet change-based event macro in Excel

I've been stuck on this for awhile. I have a macro that runs every time a change is made and creates a data table that updates after each change with information like : Old Value, New Value, Data Changes, etc.
I am trying to kind of pause the worksheet change macro when I don't want it to be run anymore. Ex: If I am plugging in blank information, I don't need to document the fact that it used to be blank, and now it has data, etc.
I made some specifications for if I deleted an entire row as shown here:
If Target.Address = Target.EntireRow.Address Then Exit Sub
but that only dealt with one case. I just now thought of a very simple solution that I will post as the answer, so I hope this will help other people as much as it helped me
It's actually a very simple solution.
To begin pick a cell that has no information in but can be clearly located. For the purpose of this lets say A1.
Now pick key words that you will use to turn the macro on and off. Ex: I just chose True and False (capitals need to be consistent so pick what you want)
At this point, go to the beginning of your worksheet change macro and type in this right after the sub starts:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("A1").Value = "False" Then
Exit Sub
End If
Now, before your macro starts, it will always verify that the cell doesn't contain False, so if you want it on, put anything else but False, and if you want it off, keep the cell as False. Hope this helps someone.
You want to disable events while ensuring that you enable them later. To do this, use an error handler to catch all errors and set the state back at the end.
Public Sub example()
On Error GoTo errHandler
Application.EnableEvents = False ' => disable events
'The code ...
errHandler:
Application.EnableEvents = True ' => enable events
End Sub

Excel macro select two ranges and compare

This is a question that was asked to me in an interview. I have a excel list. It is copied to another location and then by mistake a row in the new location gets deleted.
Now I need to write a macro to compare the old and new ranges and then provide the missing data as result.
I can perhaps perform the comparison part. But the problem is I don't know how to get the selected range as input in a macro.
For eg. as soon as I select a range, it should be sent as input to the macro, then the macro should wait for another selection. As soon as I select the new range, the macro should compare and find the missing lines in new range.
Regarding the selection per mouse click you could look at the link I sent in the comments of the other answer. Selection_Change is an event which gets triggered when you change the selection of a worksheet (not only mouseclick but move-by-keys as well). The target coming in is the cell which you have selected. You can pass this as a range on to a function.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
showMsg Target
End Sub
Private Function showMsg(r As Range)
MsgBox r.Address
End Function
You can just as well use another event like BeforeDoubleClick or BeforeRightClick. Check out the events of Excel and choose the one you feel fits best.
If you only want the function to be triggered for a certain range you can filter it.
If target.column <> 1 then exit function
If you don't want the event to trigger your function each time you change a selection you can choose one cell to be the switch which gets triggered by the same event.
If target.address = "$A$1" Then Call toggleSearch()
with toggleSearch being the switching function.
This is a classical diff (and a simple one at that), you shouldn't select by hand or anything. Just sort the two lists in an identical way, then run a Sub which loops over the number of rows in the source sheet comparing each row with the same row in the target sheet. The first mismatch you get is the missing line.
This example assumes both sheets are in the same workbook but you can easily adapt it
Public Sub diffThem()
Dim src as Worksheet, trg as Worksheet
Dim r as Range, i as Integer
Set src = ThisWorkbook.Sheets("Source")
Set trg = ThisWorkbook.Sheets("Destination")
Set r = src.Range("A1")
For i = 1 to ThisWorkbook.Sheets("Source").UsedRange.Rows.Count
If r.EntireRow <> trg.Range("A" & r.Row).EntireRow Then
MsgBox("The missing row is " & r.Row)
Exit Sub
End if
Set r = r.Offset(1,0)
Next i
End Sub
If EntireRow cannot be run due to different layouts or whatever then loop the columns at that point.