Excel宏:根据用户输入插入行

时间:2016-02-04 19:17:23

标签: excel vba excel-vba

在一个excel文件中,其中列A填充了不同的日期,按升序排序,宏应生成一个要求输入日期的用户提示。然后,宏应在两个日期之间插入一行,该日期小于和大于用户指定的日期。

到目前为止,我只是提示用户提供一个特定的行,然后宏下面会插入一个新行。任何人都可以帮助我完成下一步吗?

Sub addRow()
    Dim row
    row = InputBox("Maturity date of new bond", "Input maturity date")
    If Not row = vbNullString Then
        ActiveSheet.Range("A" & row + 1).EntireRow.Insert
    End If
End Sub

2 个答案:

答案 0 :(得分:2)

正如我在评论中所说,我只是遍历你的日期栏,直到你找到一个更大的日期(我在评论中说的更小,但如果它按升序排列,则更大的日期将朝向底部)。

Sub addRow()
    Dim givenDate As Date
    givenDate = InputBox("Maturity date of new bond", "Input maturity date")
    If givenDate <> vbNullString Then
        Dim iter As Range
        Set iter = ActiveSheet.Range("A1")
        Do
            Set iter = iter.Offset(1)
        Loop While iter.Value <= givenDate
        iter.EntireRow.Insert xlDown
        Set iter = iter.Offset(-1)
        iter.Value = givenDate
    End If
End Sub

您可能需要进行更多错误检查,但这应该可以解决问题。

答案 1 :(得分:1)

感谢Taelsin的回答,但我确实注意到他的宏存在一些问题(例如,没有考虑用户输入无效日期格式的可能性)。

另外,我想你可能想要实际学习代码究竟发生了什么。所以,我创建了以下子程序,并提供了大量的注释和解释。我希望它能找到你。

祝你好运!

Sub addRow()

' ============================================================================================================
' This is sort of the easy part, taken somewhat from the code you provided. We're going to create some
' variables to use later, and give our user an input field for the maturity date.
' NOTE: You said the date was in column A, but in case that isn't always true, I also use a
'       range-selector input box to allow the user to specify the range / column containing maturity dates.
' ============================================================================================================
Dim d As Date ' Create our maturity date
Dim dateColumn As Range ' Create a variable to store our date column
Dim isAscOrder As Boolean ' Create a variable to store a value that will indicate in what direction the dates are sorted
Dim i As Long, j As Long, k As Long, c As Range, r As Range ' Create a few misc variables (I always do this just in case I need them later on)

On Error GoTo cancel ' We want to assume any errors on the next line are caused by the user pressing the "Cancel" button.
Set dateColumn = Application.InputBox("Column containing maturity dates", "Specify maturity date column", Type:=8) ' Show the range-selector input box and store it in our date-column variable

retryDate: ' this is called a "Line Label". We can send user here to retry the next action
On Error GoTo invalidDate ' If the next line causes an error, we will send user to our "invalidDate" label (see below)
d = InputBox("Maturity date of new bond", "Input maturity date") ' Show the input-box and store the date value specified by the user
On Error GoTo 0 ' Set the error-handling back to its default

' ============================================================================================================
' Here comes the slightly more advanced part. The general idea here is that we want to find the spot in which
' this date should fit, but we don't even know in what direction the dates are currently sorted.
' ---------------------------------------------------------------------------------------------------------
' (1) So, first we'll determine the sort direction by comparing the first cell to the last cell.
'       Also note that I am specifying "Column(1)" in case the user entered a range with multiple
'       columns by mistake.
' (2) Next, I'll loop through each cell in the range using the "For each" statement. Within each
'       of these iterations, I will check if the cell's date is greater/less than (this will
'       depend on the sort direction) the maturity date specified by the user.
' (3) Finally, when I find a cell that is greater/less than our maturity date, I will insert a
'       new row before that row.
' ---------------------------------------------------------------------------------------------------------
' Sound good? Okay, here we go . . .
' ============================================================================================================

isAscOrder = (CDate(dateColumn.Cells(1, 1).Value) < CDate(dateColumn.Columns(1).End(xlDown).Value)) ' compare the first and last cells of the first column to determine the sort direction
For Each c In dateColumn.Columns(1).Cells ' begin the "For Each" loop; this will loop through each cell in the first column of our range
    If c.Row() > dateColumn.Parent.UsedRange.Rows.Count() Then Exit Sub ' Proceed only if we have not reached end of the "Used Range" (i.e., the end of our worksheet)
    If isAscOrder Then ' If this is in ascending order, then ...
        If CDate(c.Value) > d Then ' ... we will check for the first cell greater than our maturity date.
            c.EntireRow.Insert shift:=xlShiftDown ' When/if we find it, then insert the new row above the current one, and then ...
            Exit Sub ' ... exit the sub (because we are done).
        End If
    Else ' If this is not in ascending order, then we will assume descending order (duh), and then ...
        If CDate(c.Value) < d Then ' ... we will check for the first cell less than our maturity date.
            c.EntireRow.Insert shift:=xlShiftDown ' When/if we find it, then insert the new row above the current one, and then ...
            Exit Sub ' ... exit the sub (because we are done).
        End If
    End If
Next c ' No greater/less than date was found; proceed to the next iteration of our "For Each" loop (i.e., the next cell).


' ============================================================================================================
' Our code execution shouldn't come down this far (since we handle all possible scenarios above, and each one
' results in exiting the sub. However, we do need to specify some code to handle our errors.
' ============================================================================================================
Exit Sub ' We shouldn't ever get to this point, but exit the sub just in case.
invalidDate:
If MsgBox("Please enter a valid date (i.e.,""mm/dd/yyyy"")", vbRetryCancel, "Invalid Date") = vbCancel Then ' Display the "invalid date" error, and ask the user if he or she would like to retry. If "Cancel" is clicked, then ...
    Exit Sub ' ... exit the sub.
Else ' If the user clicked "Retry", then ...
    GoTo retryDate ' ... send them back to the date input box (i.e., the "retryDate" label).
End If

cancel:
Exit Sub

End Sub