Press a button to sum a range of cells - excel

In column (T2) going down I have the category "money spent". In the next column (U2) I have the date "mm/dd/yy". I want to take the money spent between two dates, sum them up and display it in a message box. How do I do this?
My code so far is:
Sub Button()
Dim myRange
Dim Results
Dim Run As Long
myRange = Worksheet("sheet1").Range ("T2", "5")
Results = WorksheetFunction.Sum(myrange)
MsgBox (Results)
End Sub

This will prompt you for two single cell date selections, and then offset to get the total. This is assuming the dates you select are in Column U so it can add up values in Column T. If you are planning on entering dates into another cell you will need to use find or something to do get the range.
If you want to use a button just assign the Sub.
Option Explicit
Sub CalculateTotal()
Dim startrange As Range
Dim endrange As Range
On Error GoTo errhandler
Dim dateselected As Boolean
dateselected = False
'Make sure one date per range is selected
Do Until dateselected = True
Set startrange = Application.InputBox("Please Enter Single Cell Starting Date Range", , , , , , , 8)
Set endrange = Application.InputBox("Please Enter Single Cell Ending Date Range", , , , , , , 8)
If IsDate(startrange.Value) And IsDate(endrange.Value) Then
dateselected = True
End If
Loop
With ActiveSheet
Dim daterange As Range
Set daterange = .Range(startrange, endrange) 'Combine Ranges
Dim cell As Range
Dim total As Double
total = 0
For Each cell In daterange.Offset(0, -1)
total = total + cell.Value ' Get Total
Next cell
MsgBox "Total value of daterange: " & total
End With
Exit Sub
errhandler:
Select Case Err.Number
Case 424 ' Add in other cases as needed
MsgBox "Range selection cancelled, Exiting"
Exit Sub
Case Else
MsgBox "Unhandled error: " & Err.Number & vbNewLine & Err.Description
Exit Sub
End Select
End Sub

Related

How to add blank rows below selected cell and keep formatting and formulas of above

Sub addRows()
' Adds new blank lines based on user input, keeping formatting and formulas of above.
Dim numRows As Long
Dim raSource As Range
Dim bResult As Boolean
Set raSource = ActiveCell.EntireRow
numRows = InputBox("Enter number of rows to insert. Rows will be added above the highlighted row.")
On Error Resume Next
raSource.Copy
bResult = Range(raSource.Offset(1, 0), raSource.Offset(numRows,
0)).EntireRow.Insert(Shift:=xlShiftDown, CopyOrigin:=xlFormatFromLeftOrAbove)
Application.CutCopyMode = False
If Not bResult Then
MsgBox "Inserting rows failed!", vbExclamation
End If
End Sub
The code works how I want it to except it keeps all the data from the selected row and pastes it to new rows. I want to only keep the formatting and formulas of the selected row and insert the new row below.
Try this code. I have linkedan example workbook as well. Let me know if this works.
Download example workbook here
Sub insertXRows()
Dim cell As Range
Dim lngRows As Long
Application.ScreenUpdating = False
'ERROR HANDLER
On Error GoTo ErrMsg
'#CHECK IF ACTIVE CELL IS IN A TABLE
'SOURCE: https://stackoverflow.com/a/34077874/10807836
Dim r As Range
Dim lo As ListObject
Set r = ActiveCell
Set lo = r.ListObject
If Not lo Is Nothing Then
Select Case lo.Name
Case "Table1"
If r.Row = lo.Range.Row Then
MsgBox "In Table1 Header"
Else
MsgBox "In Table1 Body"
End If
Case "SomeOtherTable"
'...
End Select
Else
MsgBox "Active cell is not in any table. Please select a cell in an active table and retry."
Exit Sub
End If
'MSGBOX to enter #rows to insert
lngRows = InputBox("Enter number of rows to insert. Rows will be added above the highlighted row.")
'CODE TO INSERT X Rows
Selection.Resize(lngRows).EntireRow.Insert
For Each cell In Intersect(ActiveSheet.UsedRange, Selection.Offset(-1, 0).EntireRow)
If cell.HasFormula Then
cell.Copy cell.Offset(1, 0)
End If
Next
Application.ScreenUpdating = True
'ERROR MSG
On Error GoTo 0
Exit Sub
ErrMsg: MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure insertX, line " & Erl & "."
End Sub

Print multiple copies of the same sheet, but replace one cell with the data from a list (range) from another sheet

I am trying to print a few months worth of time sheets. So print 20 copies of the same sheet, and change the date on one cell (cell "C1" on "Timesheets" sheet) using a list of fortnightly dates on the "Pay Periods" sheet.
Have tried multiple methods but can't get close for varying reasons...
Would be interested to learn why am getting errors or stuck on each method I have tried below.
Sub PrintAllDates()
Dim printDate As Date
Dim startDate As Date
Dim endDate As Date
startDate = Worksheets("Pay Periods").Range("A2")
endDate = Worksheets("Pay Periods").Range("A10")
For printDate = startDate To endDate
Sheets("Timesheet").Range("C1") = printDate
Sheets("Timesheet").PrintOut
Next
This works but I can't figure out how to get it to use the list.
It prints out 9 consecutive days instead, whereas my list is 9 consecutive "fortnights".
Sub PrintCopies()
Dim i As Integer
Dim VList As Variant
VList = Sheets("Pay Periods").Range("H2:H3").Value
For i = LBound(VList) To UBound(VList)
Range("C1") = VList(i)
ActiveSheet.PrintOut
Next
With the above, I get runtime error 9 "Subscript out of range" on Range("C1") = VList(i)
Sub PrintCopies()
Dim i As Date
Dim VList As Variant
VList = Array(Worksheets("Pay Periods").Range("A2:A10"))
For i = LBound(VList) To UBound(VList)
Sheets("Timesheet").Range("C1") = VList(i)
Sheets("Timesheet").PrintOut
Next
This also works, but only 1 page gets printed out.
Date also gets converted to "13 Jan 1900".
The first code does not work because it is not considering the whole range of dates; instead it takes only the value inside the first and last cell, treating them as dates. The code basically takes those dates and covers each day between them. It does not even akwnoledge the others cells between A2 and A10. This one should work:
Sub PrintAllDates()
'Declaring variables.
Dim RngDate As Range
Dim RngDates As Range
Dim RngTarget As Range
'Setting variables.
Set RngDates = Sheets("Pay Periods").Range("A2:A10")
Set RngTarget = Sheets("Timesheet").Range("C1")
'Covering each cell in RngDates.
For Each RngDate In RngDates
'Changing RngTarget.
RngTarget = RngDate.Value
'Printing RngTarget's sheet.
RngTarget.Parent.PrintOut
Next
End Sub
I've also added a feature to check if the given value is a date in this version:
Sub PrintAllDates()
'Declaring variables.
Dim RngDate As Range
Dim RngDates As Range
Dim RngTarget As Range
'Setting variables.
Set RngDates = Sheets("Pay Periods").Range("A2:A10")
Set RngTarget = Sheets("Timesheet").Range("C1")
'Covering each cell in RngDates.
For Each RngDate In RngDates
'Checking if RngDate does not contain a date value.
If Not VBA.Information.IsDate(RngDate.Value) Then
'Asking what to do in case RngDate does not contain a date value.
Select Case MsgBox("Range " & RngDate.Address(False, False) & " in sheet " & RngDate.Parent.Name & " contains the value """ & RngDate.Value & """, which is a non-date value." & vbCrLf & _
vbCrLf & _
vbCrLf & _
"Do you wish to use it and print anyway?" & vbCrLf & _
vbCrLf & _
"Press ""Yes"" to print it anyway." & vbCrLf & _
vbCrLf & _
"Press ""No"" to not print it and proceed to the next value." & vbCrLf & _
vbCrLf & _
"Press ""Cancel"" to stop the macro and print no more.", _
vbYesNoCancel, _
"Non-date value detected" _
)
'If "Cancel" is pressed, the macro is terminated.
Case Is = 2
Exit Sub
'If "Yes" is pressed, the macro goes on.
Case Is = 6
'If "No" is pressed, the macro goes to NextRngDate
Case Is = 7
GoTo NextRngDate
End Select
End If
'Changing RngTarget.
RngTarget = RngDate.Value
'Printing RngTarget's sheet.
RngTarget.Parent.PrintOut
'Checkpoint.
NextRngDate:
Next
End Sub
Your code can be something like this:
Sub PrintAllDates()
Dim listRange As Range ' Your range A2:A10 in "Pay Periods" sheet '
Dim oCurrentCell As Range ' Single cell from this range '
Dim printedSheet As Worksheet ' Target sheet - "Timesheet" '
Dim oTargetCell As Range ' C1 - target cell (to set next date from list) '
Set listRange = Worksheets("Pay Periods").Range("A2:A10")
Set printedSheet = Worksheets("Timesheet")
Set oTargetCell = printedSheet.Range("C1")
For Each oCurrentCell In listRange.Cells
oTargetCell = oCurrentCell
Rem If some cells in "Timesheet" has formulas which reffered to C1,
Rem we need recalc it before printing
printedSheet.Calculate
printedSheet.PrintOut
Next oCurrentCell
End Sub

Match Textbox entry with cells to populate column with Userform data

I currently have multiple spreadsheets with a row of dates for each employee.
Within the userform that pops up modified for each employee, there is a place for the date at the top, and they fill out the rest of the information and then submit.
Is there a way to match up the date on the sheet with the one on the userform to populate the column underneath?
Assuming you have a textbox on your form that you type the date into.
This first bit of code is ensuring you have a date in the textbox rather than anything else.
Paste this into a normal module. You can place it in the form, but in a module allows it to be used by any other forms you may have that contain a date.
Public Sub FormatDate(ctrl As Control)
Dim dDate As Date
Dim IsDate As Boolean
On Error GoTo ERR_HANDLE
If Replace(ctrl.Value, " ", "") <> "" Then
On Error Resume Next
dDate = CDate(ctrl.Value)
IsDate = (Err.Number = 0)
On Error GoTo -1
On Error GoTo ERR_HANDLE
If IsDate Then
ctrl.Value = Format(ctrl.Value, "dd-mmm-yyyy")
ctrl.BackColor = RGB(255, 255, 255)
Else
ctrl.BackColor = RGB(255, 0, 0)
End If
End If
EXIT_PROC:
On Error GoTo 0
Exit Sub
ERR_HANDLE:
MsgBox Err.Number & ": " & Err.Description, vbOKOnly, "FormatDate()"
Resume EXIT_PROC
End Sub
Place this on the form as the AfterUpdate event for your textbox:
Private Sub txtDate_AfterUpdate()
On Error GoTo ERR_HANDLE
With Me
FormatDate .txtDate
End With
EXIT_PROC:
On Error GoTo 0
Exit Sub
ERR_HANDLE:
MsgBox Err.Number & ": " & Err.Description, vbOKOnly, "txtDate_AfterUpdate()"
Resume EXIT_PROC
End Sub
Any valid date will be formatted as dd-mmm-yyyy, any invalid date will turn the background of the control red.
Next you need to find the date on row 1 of your sheet. Again this can be kept in a normal module so you can use it outside of the form:
Public Function FindDate(DateValue As Date) As Range
Dim rFound As Range
With Sheet2
Set rFound = .Rows(1).Find(DateValue, .Cells(1, 1), xlValues, xlWhole)
If rFound Is Nothing Then
Set rFound = .Cells(1, .Columns.Count).End(xlToLeft).Offset(, 1)
End If
End With
Set FindDate = rFound
End Function
This will return the cell that the date is in or the last blank cell on row 1 if the date isn't found.
I'm not sure if you want this bit, but this then finds the last cell containing data in a specified column number:
Public Function LastCell(wrksht As Worksheet, Col As Long) As Range
Dim lLastRow As Long
On Error Resume Next
lLastRow = wrksht.Columns(Col).Find("*", , , , xlByColumns, xlPrevious).Row
On Error GoTo 0
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrksht.Cells(lLastRow, Col)
End Function
Now you just need to attach the code to your find button to return the first blank cell beneath the date you specify:
Private Sub btnFind_Click()
Dim rFoundCell As Range
'First blank cell beneath date.
Set rFoundCell = LastCell(Sheet1, FindDate(CDate(Me.txtDate)).Column).Offset(1)
End Sub
If you just wanted to find the date you can just use:
Set rFoundCell = FindDate(CDate(Me.txtDate))
The help file on Find is here.
Finding dates can be problematic in Excel:
excel-vba-range-find-date-that-is-a-formula
DateTimeVBA

Identifying cells that are empty or showing #REF! error in a given range

My code is not working properly. It's only showing the first empty cell T10 but cells from T10 to T15 are all empty. I would also like to identify cells that are showing #REF! in them. I don't need the address of empty cells (as there could be quite a few on bigger scale) but would like to know the address of cells with #REF! Thank you!
Sub Identiycells()
Dim Cancel As Boolean
Dim cell As Range
Dim sh As Worksheet
For Each sh In ThisWorkbook.Worksheets(Array("a", "b"))
For Each cell In sh.Range("T6:T18")
If IsEmpty(cell) 'Or showing #REF! Then
MsgBox "Data Missing or Formula error" & cell.Address
Application.Goto cell, True
Cancel = True
Exit For
End If
Next cell
Next sh
End Sub
You could collect the errors in a String and only report once at the end. For checking #REF or other errors you can test with IsError(cell.value).
As you are going through different sheets, it might be good to specify which sheet the cells are on. You can get a cell reference including its sheet with Split(cell.address(External:=True), "]")(1).
Suggested code:
Sub Identiycells()
Dim Cancel As Boolean
Dim cell As Range
Dim sh As Worksheet
Dim report as String ' collect all errors
Dim errorMsg as String ' error for current cell
Dim errorCell as Range ' cell to focus at the end
For Each sh In ThisWorkbook.Worksheets(Array("a", "b"))
For Each cell In sh.Range("T6:T18")
errorMsg = ""
If IsEmpty(cell) Then
errorMsg = "Data Missing"
If errorCell Is Nothing Then Set errorCell = cell
ElseIf IsError(cell.value) Then
errorMsg = "Invalid Reference"
Set errorCell = cell
End If
If errorMsg <> "" Then
report = report & errorMsg & " in " & _
Split(cell.address(External:=True), "]")(1) & vbCrLf
End If
Next cell
Next sh
If Not errorCell Is Nothing Then
MsgBox report
Application.Goto errorCell, True
Cancel = True
End If
End Sub

vba#excel_highlight the empty cells

I'm creating an excel file with column A to H are mandatory cells.
This excel file will be passing around for input.
So, I would like to highlight the empty cells as a reminder.
I have written the following code...
Sub Highlight_Cell()
Dim Rng As Range
For Each Rng In Range("A2:H20")
If Rng.Value = "" Then
Rng.Interior.ColorIndex = 6 ‘yellow
Else
Rng.Interior.ColorIndex = 0 'blank
End If
Next Rng
MsgBox "Please fill in all mandatory fields highlighted in yellow."
End Sub
However, I would like to set the range from A2 to the last row that contains data within column A to H.
Also, display the message box only when empty cell exist.
Could you please advise how should I amend?
Million Thanks!!!
This is a VBA solution that prevents the user from saving until the desired range is filled (acknowledging Gserg's comment that that the last row is one that has at least one cell entered)
In the second portion you can either add your sheet index directly, Set ws = Sheets(x) for position x, or Set ws = Sheets("YourSheet") for a specific sheet name
The code will only highlight truly blank cells within A to H of this sheet till the last entered cell (using SpecialCells as a shortcut). Any such cells will be selected by the code on exit
Put this code in the ThisWorkbook module (so it fires whenever the user tries to close the file)
Private Sub Workbook_BeforeClose(Cancel As Boolean)
bCheck = False
Call CheckCode
If bCheck Then Cancel = True
End Sub
Put this code in a standard module
Public bCheck As Boolean
Sub CheckCode()
Dim ws As Worksheet
Dim rng1 As Range
Dim rng2 As Range
bCheck = False
'works on sheet 1, change as needed
Set ws = Sheets(1)
Set rng1 = ws.Columns("A:H").Find("*", ws.[a1], xlValues, xlWhole, xlByRows)
If rng1 Is Nothing Then
MsgBox "No Cells in columns A:H on " & ws.Name & " file will now close", vbCritical
Exit Sub
End If
Set rng2 = ws.Range(ws.[a1], ws.Cells(rng1.Row, "H"))
On Error Resume Next
Set rng2 = rng2.SpecialCells(xlBlanks)
On Error GoTo 0
If rng2 Is Nothing Then Exit Sub
bCheck = True
rng2.Interior.Color = vbYellow
MsgBox "Please fill in all mandatory fields on " & ws.Name & " highlighted in yellow", vbCritical, "Save Cancelled!"
Application.Goto rng2.Cells(1)
End Sub

Resources