我正在学习VBA,正在努力创建一个模型,提示用户提供一种风险和地理区域(通过下拉菜单完成)和一年(使用输入框),然后拉动来自与用户输入相对应的不同工作表的数据。例如,如果用户选择风险x,区域y和年份2025,则模型将从与风险x,区域y和2025年相对应的工作表中提取数据。
除了使用long if / then语句之外,还有什么更优雅(并且对新人来说有点学习)的方法呢?我不想写出20-30行if / then语句,并且想知道编码器会有多好。有任何想法吗?我的代码的示例部分如下所示。
Sub TryTwo()
'For me to keep track of time complexity
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
'Declare main variables
Dim riskType As String
Dim region As String
Dim year As Integer
Dim yearCurrent As Integer: yearCurrent = 2015
Dim currentVulnerabilityScore As Integer
'Declare the different sheets
Dim ws1, ws2, ws3, ws4, ws5, ws6, ws7, ws8, ws9 As Worksheet
'Declare variables used in vlookup function for cells D3:D7
Dim riskLookUpValue As Integer
Dim regionLookUpValue As Integer
'Set the different sheets in workbook
Set ws1 = ThisWorkbook.Sheets("LMC_Model")
Set ws2 = ThisWorkbook.Sheets("Water_Risk")
Set ws3 = ThisWorkbook.Sheets("Fire_Risk")
Set ws4 = ThisWorkbook.Sheets("Drought_Risk")
Set ws5 = ThisWorkbook.Sheets("Flood_Risk")
Set ws6 = ThisWorkbook.Sheets("Sea Level Rise Risk")
Set ws7 = ThisWorkbook.Sheets("Facility_Supplier Tab")
Set ws8 = ThisWorkbook.Sheets("Risks")
Set ws9 = ThisWorkbook.Sheets("Other")
'Assign value to regionLookUpValue and input risk type into cell D3
regionLookUpValue = Cells(2, 3).Value
region = Application.WorksheetFunction.VLookup(regionLookUpValue, ws9.Range("b3:c12"), 2)
Cells(3, 4).Value = region
'Assign value to riskLookUpValue and input risk type into cell D4
riskLookUpValue = Cells(2, 4).Value
riskType = Application.WorksheetFunction.VLookup(riskLookUpValue, ws9.Range("b20:c24"), 2)
Cells(4, 4).Value = riskType
'assign year value in a loop that has user enter until right option found
'Provide sentinal value of 0 to 'year' to ensure that user enters if statement and possibly do until loop
year = 0
If year = 0 Then
year = InputBox("Please enter year (between 2016 and 2045)")
End If
Do
If year < 2016 Or year > 2045 Then
year = InputBox("Invalid year entry. Please enter year between 2016 and 2045")
End If
Loop Until year > 2015 And year < 2046
Cells(5, 4).Value = year
答案 0 :(得分:1)
我得到了你对里弗斯的看法。我将回答您的具体问题,然后再提出一种处理此问题的不同方法。
就您的问题而言,您可以将代码置于Workbook_SheetChange
事件中。这样,您可以测试活动工作表中的风险或区域单元格是否已更改,并根据需要进行更改。您不需要使用任何If
语句,因为每个激活的工作表将在其工作表上运行相同的代码段。当然,如果每张纸的范围不同,则需要一些额外的编码。下面的代码向您展示了如何执行此操作,但请继续阅读,因为我不认为您以最佳方式处理任务:
Option Explicit
Private mRiskSheets As Collection
Private Sub Workbook_Open()
Dim ws As Worksheet
Set mRiskSheets = New Collection
Set ws = ThisWorkbook.Worksheets("Water_Risk")
mRiskSheets.Add ws, ws.Name
Set ws = ThisWorkbook.Worksheets("Fire_Risk")
mRiskSheets.Add ws, ws.Name
Set ws = ThisWorkbook.Worksheets("Drought_Risk")
mRiskSheets.Add ws, ws.Name
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim ws As Worksheet
Dim v(1 To 3, 1 To 1) As Variant
'Test if activated sheet is a risk sheet
On Error Resume Next
Set ws = mRiskSheets(Sh.Name)
On Error GoTo 0
If Not ws Is Nothing Then
'Check if the risk type or region cells were changed
If Not Intersect(Target, ws.Range("C2,D2")) Is Nothing Then
'It's a change we're interested in so set the year question
If Len(ws.Range("D5").Text) = 0 Then
v(3, 1) = InputBox("Please enter year (between 2016 and 2045)")
Else
v(3, 1) = ws.Range("D5").Value2
End If
Do
If v(3, 1) < 2016 Or v(3, 1) > 2045 Then
v(3, 1) = InputBox("Invalid year entry. Please enter year between 2016 and 2045")
End If
Loop Until v(3, 1) > 2015 And v(3, 1) < 2046
' Acquire the values
v(1, 1) = Application.WorksheetFunction.VLookup(ws.Range("C2"), ws.Range("B3:C12"), 2)
v(2, 1) = Application.WorksheetFunction.VLookup(ws.Range("D2"), ws.Range("B20:C24"), 2)
'Write the values
ws.Range("D3:D5").Value = v
End If
End If
End Sub
但是,我不会以你的方式处理这个问题。有几个困难:
InputBox
中键入整数,例如2016.5或2019 *,那么您的代码将会出错。InputBox
只会像一个单元格一样,所以您也可以让用户直接将年份键入&#34; D5&#34;并且只是有一些条件格式。InputBox
,您至少可以测试三个单元格中的任何一个的变化&#34; C2&#34;,&#34; D2&#34;或&#34; D5&#34;。虽然很难知道何时想要处理变更事件。如果是我,我有一个UserForm
可以控制所有这些问题。您可以拥有4个ComboBoxes
:风险类别,风险类型,地区和年份。一旦根据需要添加了所有内容,用户只需点击“获取数据”即可。 Button
并写入数据。它可以减轻错误并允许重复输入。像这样:
在UserForm设计器中添加4 Comboboxes
,将它们重命名为cboxRiskCat,cboxRiskType,cboxRegion和cboxYear,将其ColumnCount
属性更改为&#39; 2&#39;,然后更改{{1属性为&#39; 2 - fmStyleDropDownList&#39;。添加Style
并将其重命名为btnFetch。
然后添加以下代码:
CommandButton
您可以通过在Option Explicit
Private mRiskValues As Collection
Private mRegionValues As Collection
Private Sub btnFetch_Click()
Dim v(1 To 3, 1 To 1) As Variant
v(1, 1) = cboxRegion.Column(1)
v(2, 1) = cboxRiskType.Column(1)
v(3, 1) = cboxYear.Value
ThisWorkbook.Worksheets(cboxRiskCat.Column(1)).Range("D3:D5").Value = v
End Sub
Private Sub cboxRiskCat_Change()
If cboxRiskCat.ListIndex <> -1 Then
ThisWorkbook.Worksheets(cboxRiskCat.Column(1)).Activate
cboxRegion.List = mRegionValues(cboxRiskCat.Column(1))
cboxRegion.ListIndex = 0
cboxRiskType.List = mRiskValues(cboxRiskCat.Column(1))
cboxRiskType.ListIndex = 0
End If
End Sub
Private Sub UserForm_Initialize()
Dim ws As Worksheet
Dim riskCat(1 To 3, 1 To 2) As String
Dim v As Variant
Dim i As Integer
Set mRegionValues = New Collection
Set mRiskValues = New Collection
'Populate the risk categories
riskCat(1, 1) = "Water": riskCat(1, 2) = "Water_Risk"
riskCat(2, 1) = "Fire": riskCat(2, 2) = "Fire_Risk"
riskCat(3, 1) = "Drought": riskCat(3, 2) = "Drought_Risk"
cboxRiskCat.List = riskCat
' Populate the risk types and regions
For i = 1 To UBound(riskCat, 1)
Set ws = ThisWorkbook.Worksheets(riskCat(i, 2))
v = ws.Range("B3:C12")
mRegionValues.Add v, riskCat(i, 2)
v = ws.Range("B20:C24")
mRiskValues.Add v, riskCat(i, 2)
Next
'Populate the years in userform
For i = 2016 To 2024
cboxYear.AddItem i
Next
cboxYear.ListIndex = 0
cboxRiskCat.ListIndex = 0
End Sub
所需的任何地方输入UserForm1.Show
来显示此UserForm。可能在Workbook_Open
事件中。
我这里只放了三张风险单。如果您想要更多,请更改&#39; 3&#39;在这一行中,您可以使用多个工作表:Dim riskCat(1 To 3, 1 To 2) As String
,并添加更多工作表,如此行下方的代码所示。