所以,现在我有这个excel表,其中有一个最后修订日期。我将此列命名为“LastRevisionDate”。然后我有一个名为“RevisionFrequency”的列。 “RevisionFrequency”包含一个下拉菜单,包括术语“每年”,“双年度”(一年2次),“半年度”和“季度”。然后我有一个列,其中声明了“NextRevisionDate”。所以我想创建一个VBA代码,用于从LastRevisionDate和RevisionFrequency计算NextRevisionDate。
例如。在“A”栏中说我的版本频率为“每年两次”而最后修订日期是“B”栏中的3月14日,那么我希望列“C”中的NextRevisionDate表示Mar,Sep .Thats基本上说该项目每年修订两次。所以我想创建一个宏,其中Column“C”基于RevisionFrequency和LastRevisionDate。我意识到我可以用公式做到这一点,但我不断添加新项目,所以我不想继续将公式复制到每个单元格中。对于某些项目,它们不需要修改,如果没有LastRevisionDate,我还希望有一个空白单元格。
到目前为止,我有更新的代码:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = Sheets(1)
If Not Intersect(Target, ws.Range("LastCalDate").Value) Is Nothing Then
Dim Lastdate As Date
Dim DueDate As Variant
Dim Frequency As String
Dim R As Variant
Dim C As Variant
Dim R1 As Variant
Dim C1 As Variant
Dim R2 As Variant
Dim C2 As Variant
R = Range("LastCalDate").Row
C = Range("LastCalDate").Column
R1 = Range("CalDueDate").Row
C1 = Range("CalDueDate").Column
R2 = Range("CalFrequency").Row
C2 = Range("CalFrequency").Column
Lastdate = Cells(R, C).Value 'Last Cal Date
DueDate = Cells(R1, C1).Value 'Cal Due Date
Frequency = Cells(R2, C2)
If Frequency = "Annually" Then
DueDate = DateAdd("mmm", 12, Lastdate)
End If
If Frequency = "Semi-Annually" Then
DueDate = DateAdd("mmm", 6, Lastdate)
End If
If Frequency = "Quarterly" Then
DueDate = DateAdd("mmm", 3, Lastdate)
End If
End Sub
答案 0 :(得分:1)
“我的代码过于复杂吗?”
这是错误的问题。第一个问题不是“我能做什么?”而是“我的用户想要什么?”
如果你开始说“我可以生产木制木底鞋”,你可能永远都不会知道他们想要柔软的拖鞋。您可能无法生产柔软的拖鞋,但如果知道需要,您可能会生产比木质木桶好得多的东西。从理想产品的设计开始,然后将其切割为实用的产品。
根据您的描述,我想象出这样的事情:
您可能有许多其他列,这三列可能位于不同的位置;没关系,我们暂时限制自己这些专栏。
听起来好像你有两个要求和一个问题:
您有一个工作表,其中“下一版本日期”列中的值可能不可靠或缺失。您需要一个将在现有工作表中运行的宏,并在“下一版本日期”列中输入正确的值。
您需要在添加现有修订频率和修订最后修订日期的新行时自动设置下一版本日期列中的值。这可以通过运行宏1或使用Worksheet Change事件来实现,如您所建议的那样。可能还有其他方法,但我不会解决这个问题。
如果查看我的示例工作表的最后三行,您会注意到“下一版本日期”列中的月份日期与“上次修订日期”中的日期不同。这是因为我将频率列中的值转换为3,6或12,并将该月数添加到上次修订日期。在最后三行中,新月没有旧日和VBA功能的天数,例如,2月30日转换为3月2日。这是你需要的效果吗?我已经包含了将日期带回“正确”月份的代码。通常,宏观设计中最困难的任务是确定所有这些例外并指定如何处理它们。
我将首先考虑宏1,因为在设计和实现宏2时可以将它用于这两个要求。如果遇到宏2的问题,请提出一个新问题。你可以问多少问题 - 只要问题很好 - 但每个问题只能是一个问题。
您需要一个宏,它将逐步降低工作表的每一行。如果您正在使用在线教程或者您已经在Excel VBA上购买了一本书,那么您可以在那里找到一个合适的例子。如果您既不使用在线教程也不使用书籍,请开始。掌握Excel VBA的基础知识并不需要很长时间,学习基础知识所花费的时间将很快得到回报。当你不了解基础知识时,试图在网上搜索代码非常困难。
如果您的教程/书籍没有告诉您如何降低工作表的每一行,请尝试搜索“[excel-vba]查找工作表的最后一行”。这个问题有很多变化,所以你应该没有困难找到合适的东西。你不必在这个场合这样做,因为我告诉你如何在下面,但我相信这是使用这个网站的最佳方式。将您的需求分解为小步骤,然后搜索与每个步骤相关的问题。
下面是一个简单的宏1.研究我的代码并在必要时回答问题。但是,你越了解自己,你的发展就越快。
欢迎来到编程的乐趣。
Option Explicit
' Using constants for values that may change makes your code easier to
' understand and easier to maintain.
Const ColFrequency As Long = 1
Const ColLastRevisionDate As Long = 2
Const ColNextRevisionDate As Long = 3
Const RowDataFirst As Long = 2
Sub FixNextRevisionDate()
Dim DateLastCrnt As Date
Dim DateNextCrnt As Date
Dim NumMonthsToStep As Long
Dim RowCrnt As Long
Dim RowLast As Long
' Replace "Data" with the name of your worksheet
With Worksheets("Data")
' This is the most popular method of finding the last row but it will
' not work in every situation. I believe it is appropriate for your
' current requirement but suggest you look for questions that describe
' other methods and which explain why they might be better.
RowLast = .Cells(Rows.Count, ColFrequency).End(xlUp).Row
For RowCrnt = RowDataFirst To RowLast
' Convert Frequency to 3, 6 or 12
' I have used the LCase function to allow for inconsistent use of
' upper and lower case
Select Case LCase(.Cells(RowCrnt, ColFrequency).Value)
Case "annually"
NumMonthsToStep = 12
Case "bi-annually"
NumMonthsToStep = 6
Case "semi-annually"
NumMonthsToStep = 6
Case "quarterly"
NumMonthsToStep = 3
Case Else
' Unknown frequency. never assume the worksheet is correct
' if an error will cause your macro to fail.
' This is an easy way to highlight faulty values for user
' attention.
With .Cells(RowCrnt, ColFrequency)
.Interior.Color = RGB(255, 0, 0)
NumMonthsToStep = 0
End With
End Select
If NumMonthsToStep <> 0 Then
' Had valid frequency
If IsDate(.Cells(RowCrnt, ColLastRevisionDate).Value) Then
' Value in Last Revision Date column is a date
DateLastCrnt = .Cells(RowCrnt, ColLastRevisionDate).Value
' Calculate next date by adding NumMonthsToStep
DateNextCrnt = DateSerial(Year(DateLastCrnt), _
Month(DateLastCrnt) + NumMonthsToStep, _
Day(DateLastCrnt))
' You may not want this but it shows how to do it if you do
If Day(DateNextCrnt) < Day(DateLastCrnt) Then
DateNextCrnt = DateSerial(Year(DateNextCrnt), _
Month(DateNextCrnt), _
0)
End If
With .Cells(RowCrnt, ColNextRevisionDate)
.Value = DateNextCrnt
' Replace with date format of your choice
.NumberFormat = "d mmm yy"
End With
Else
' The Last Revision Date is not a date
With .Cells(RowCrnt, ColLastRevisionDate)
.Interior.Color = RGB(255, 0, 0)
End With
End If
End If
Next
End With
End Sub