【问题标题】:Return range anlong with worksheet name from a UDF从 UDF 返回范围以及工作表名称
【发布时间】:2020-12-11 19:02:18
【问题描述】:

我想运行一个高级过滤器。所以我想写一个函数作为高级过滤器,它将三个参数作为范围(列表范围,条件范围和复制范围)......但每次我的范围都会不同。所以首先我写一个公式,从工作表返回范围名称和其他参数(为清楚起见,请参见下面的函数)。

Public Function ConvertRange(ByVal sh As Worksheet, ByVal StartingRow As Long, ByVal StartingCol As Long, ByVal TotalCol As Long, ByVal LastRow As Long) 
As Range
With sh

Set ConvertRange = .Range(.Cells(StartingRow, StartingCol), .Cells(LastRow - StartingRow + 1, StartingCol + TotalCol - 1))
End With
End Function

所以这个函数返回范围但 Listrng 在一个工作表中但 Criteriarng 并在另一张表中复制 rng..所以连同范围地址我需要找到工作表的名称..我该怎么做? 高级过滤功能:

Public Sub AdvancedFilter(Listrng As Range, criteriarng As Range, targetrng As Range)

'Set the target range where the unique values will be copied to.
Set targetRange = targetrng
'Calculating last non blank row of column A in Sh1 worksheet.
'Set the collection range from where the values will filter out.
Set rngCollectFrom = Listrng
'Use Advanced Filter
rngCollectFrom.AdvancedFilter Action:=xlFilterCopy, criteriaRange:=criteriarng, CopyToRange:=targetRange, Unique:=False
End Sub

Public Sub M()
Dim sh As Worksheet
Set sh = Worksheets("Logical operation")
Dim sh1 As Worksheet
Set sh1 = Worksheets("Transaction")
Dim Listrng As Range
Dim criteriarng As Range
Dim targetrng As Range
Set Listrng = ConvertRange(sh1, 1, 1, 4, 22)
MsgBox Listrng.Parent.Name & "!" & Listrng.Address
Set criteriarng = ConvertRange(sh, 1, 13, 4, 2)
MsgBox criteriarng.Parent.Name & "!" & criteriarng.Address
Set targetrng = ConvertRange(sh, 2, 21, 1, 3)
MsgBox targetrng.Parent.Name & "!" & targetrng.Address
Call AdvancedFilter(Listrng.Parent.Name & "!" & Listrng.Address, 
criteriarng.Parent.Name & "!" & criteriarng.Address, targetrng.Parent.Name & "!" & targetrng.Address)
End Sub
Call AdvancedFilter(Listrng.Parent.Name & "!" & Listrng.Address, criteriarng.Parent.Name & "!" & criteriarng.Address, targetrng.Parent.Name & "!" & targetrng.Address)

它返回运行时错误 424 我想我搞砸了以下行:

Call AdvancedFilter(Listrng.Parent.Name & "!" & Listrng.Address, criteriarng.Parent.Name & "!" & criteriarng.Address, targetrng.Parent.Name & "!" & targetrng.Address)

【问题讨论】:

  • 如果您传递了对范围 *rng.Parent.Name` 的引用。
  • @ComputerVersteher 你能解释一下吗?
  • 请将代码作为编辑添加到帖子中,而不是在评论中,以便格式正确。
  • @SuperSymmetry 我编辑问题..
  • 我想在高级过滤函数中传递这些参数 Listrng = Transaction!$P$1:$R$19 criteriarng =Logical operation!$M$1:$P$2 targetrng = Logical operation!$U$2跨度>

标签: excel vba user-defined-functions


【解决方案1】:

首先,您不需要ConvertRange 函数来在特定工作表上创建范围引用,因此请摆脱它。请注意,Range 对象指的是特定工作表上特定工作簿中的范围。

相反,只需完全指定所需的范围(这些是您的代码正在创建的范围。不清楚这些是否是您打算的范围,因此如果需要,请更新):

Set ConvertRange = sh1.Range("A1:D22")
Set Criteriarng = sh.Range("M1:P2")
Set Targetrng = sh.Range("U2")

注意:所有这些都隐含地引用了ActiveWorkbook。您也可以(并且应该)明确指定Workbook

Dim wb as Workbook
Set wb = ActiveWorkbook
' or
Set wb = ThisWorkbook
' or
Set wb = Application.Workbooks("NameOfYourBook.xlsm")

并将其包含在工作表引用中

Set sh = wb.Worksheets("Logical operation")
Set sh1 = wb.Worksheets("Transaction")

其次,您已经将AdvancedFilter 的参数指定为Range。这很好!你只需要传递 ranges,而不是 strings

另外,Call 的使用是多余的,你不应该使用它(永远)

所以:

Call AdvancedFilter(Listrng.Parent.Name & "!" & Listrng.Address, criteriarng.Parent.Name & "!" & criteriarng.Address, targetrng.Parent.Name & "!" & targetrng.Address)

变成

AdvancedFilter Listrng, criteriarng, targetrng

AdvancedFilter Sub 中的评论建议您在调用rngCollectFrom.AdvancedFilter 之前操作传递的范围。如果你这样做就好了。否则你可能根本不需要 sub。


你的代码,重构

Public Sub M()
    Dim wb As Workbook
    Set wb = ThisWorkbook
    
    Dim sh As Worksheet
    Set sh = wb.Worksheets("Logical operation")
    
    Dim sh1 As Worksheet
    Set sh1 = wb.Worksheets("Transaction")
    
    Dim Listrng As Range
    Dim Criteriarng As Range
    Dim Targetrng As Range
    
    Set Listrng = sh1.Range("A1:D22")
    Set Criteriarng = sh.Range("M1:P2")
    Set Targetrng = sh.Range("U2")
    
    AdvancedFilter Listrng, Criteriarng, Targetrng
    ' or
    'Listrng.AdvancedFilter Action:=xlFilterCopy, criteriaRange:=Criteriarng, CopyToRange:=Targetrng, Unique:=False

End Sub

【讨论】:

  • 我使用 convertrange 函数,因为范围现在总是 "A1:D22" 。它总是在变化..所以我不能专门写成“A1:D22”..我没有指定工作簿,因为我在活动工作簿中计算它..但是指定工作簿是个好点。谢谢
  • 所以,你需要创建一个动态范围。我明白那个。但是像你的“convertrange”这样的函数是错误的方法。我建议你问一个新问题,描述你需要什么信息来定义你想要的范围。一旦你了解了如何创建范围引用,我对这个问题的回答就会更有意义
  • 我找到了我的解决方案..您的代码很好..我不需要使用高级过滤功能..是的,范围也包含工作表名称...虽然它向我们显示“A1: D22”作为地址,但在执行高级过滤时可以区分“逻辑操作!A1:D22”和“事务!A1:D22”。谢谢您的帮助..
  • @MDIsmailHosen,既然您已经接受了 Puntal 的回答,我猜您对基于字符串的范围引用解决方案感到满意。在我看来,这是一个糟糕的解决方案,只会导致一个受伤的世界。请花时间学习如何正确创建范围引用
  • 我想确认两个分析器,但是当我单击另一个分析器时堆栈溢出丢弃一个......你的回答也解决了我的问题。现在我有三种方法可以做同样的工作......谢谢。 ..你能为我提供一些正确学习范围参考的好资源吗..
【解决方案2】:
Public Sub M()
Dim sh As Worksheet
Set sh = Worksheets("Logical operation")

Dim sh1 As Worksheet
Set sh1 = Worksheets("Transaction")

Dim Listrng As Range
Dim criteriarng As Range
Dim targetrng As Range
Set Listrng = ConvertRange(sh1, 1, 1, 4, 22)

Set criteriarng = ConvertRange(sh, 1, 13, 4, 2)
Set targetrng = ConvertRange(sh, 2, 21, 1, 1)

AdvancedFilter Listrng, criteriarng, targetrng ' removed Call as obsolete

Debug.Print Listrng.Parent.Name ' print name of sh1 "Transaction"
End Sub

因为.Range.Worksheet 的孩子,所以.Worksheet.Parent.Range Range.Parent 返回对工作表的引用,Range.Parent.Parent 返回工作簿引用,因为 WorksheetWorkbook 的子代。

【讨论】:

  • 抱歉,它没有达到我想要的效果..Sh1 中的 Listrang 但criteriarng 和 targetrng 在 sh 表中..所以我也需要指定工作表名称及其范围,,,我想?
  • 您通过将工作表paasing 到ConvertRange 作为第一个参数来指定工作表,并且Listrng 是通过传递sh1 和其他通过传递sh 创建的,这就是你想要的。
【解决方案3】:

答案一:使用List range,Criteria range,paste range as a range,使用UDF AdvancedFilter。

'Calling Sub
 Public Sub CallingSub()
'Declaration of variable as worksheet to contain the worksheet name.
Dim sh As Worksheet, sh1 As Worksheet
'Set the required worksheet
Set sh = Worksheets("Logical operation")
Set sh1 = Worksheets("Transaction")
'Variable declaration for finding the range from ConvertRange sub.
Dim Listrng As Range, criteriarng As Range, targetrng As Range
'Finding the List range from where data will be fetched.
Set Listrng = ConvertRange(sh1, 1, 1, 4, 22)
'Finding the criteria range based on which data will be fetched.
Set criteriarng = ConvertRange(sh, 1, 13, 4, 6)
'Finding the range where data will be copied.
Set targetrng = ConvertRange(sh, 2, 21, 4, 3)
'Calling the AdvancedFitler function.
AdvancedFilter2 Listrng, criteriarng, targetrng
End Sub
'ConvertRange Function
 Public Function ConvertRange(ByVal sh As Worksheet, ByVal StartingRow As Long, ByVal StartingCol As Long, ByVal TotalCol As Long, ByVal LastRow As Long) As Range
'Calculating range based on below worksheet.
With sh
    'Find the range based on provided data.
    Set ConvertRange = .Range(.Cells(StartingRow, StartingCol), .Cells(LastRow, StartingCol + TotalCol - 1))
End With
End Function
'UDF AdvancedFilter
Public Sub AdvancedFilter(Listrng As Range, criteriarng As Range, targetrng As Range)
'Use advanced filter based on data passed on this sub.
Listrng.AdvancedFilter Action:=xlFilterCopy, criteriarange:=criteriarng, copytorange:=targetrng, Unique:=False
End Sub

答案二:在AdvancedFilter中使用List range、Criteria range、paste range as a range以及使用excel。

'Calling Sub
 Public Sub CallingSub()
 'Declaration of variable as worksheet to contain the worksheet name.
Dim sh As Worksheet, sh1 As Worksheet
'Set the required worksheet
Set sh = Worksheets("Logical operation")
Set sh1 = Worksheets("Transaction")
'Variable declaration for finding the range from ConvertRange sub.
Dim Listrng As Range, criteriarng As Range, targetrng As Range
'Finding the List range from where data will be fetched.
Set Listrng = ConvertRange(sh1, 1, 16, 3, 19)
'Finding the criteria range based on which data will be fetched.
Set criteriarng = ConvertRange(sh, 1, 17, 3, 6)
'Finding the range where data will be copied.
Set targetrng = ConvertRange(sh, 2, 25, 3, 3)
'Use advanced filter function in place..No need to use UDF(User Defined Function).
Listrng.AdvancedFilter Action:=xlFilterCopy, criteriarange:=criteriarng, copytorange:=targetrng, Unique:=False
End Sub
'ConvertRange Function
 Public Function ConvertRange(ByVal sh As Worksheet, ByVal StartingRow As Long, ByVal StartingCol As Long, ByVal TotalCol As Long, ByVal LastRow As Long) As Range
'Calculating range based on below worksheet.
With sh
    'Find the range based on provided data.
    Set ConvertRange = .Range(.Cells(StartingRow, StartingCol), .Cells(LastRow, StartingCol + TotalCol - 1))
End With
End Function

答案三:使用列表范围、条件范围、将范围地址粘贴为字符串及其工作表名称并使用 UDF AdvancedFilter

'Calling Sub
 Public Sub CallingSub()
'Declaration of variable as worksheet to contain the worksheet name.
Dim sh As Worksheet, sh1 As Worksheet
'Set the required worksheet
Set sh = Worksheets("Logical operation")
Set sh1 = Worksheets("Transaction")
'Variable declaration for finding the range from ConvertRange sub.
Dim Listrng As Range, criteriarng As Range, targetrng As Range
'Variable declaration for containing the address of range along with sheet name.
Dim a As String, b As String, c As String
'Finding the List range from where data will be fetched.
Set Listrng = ConvertRange(sh1, 1, 1, 4, 22)
'Finding the address of range along with sheet name.
a = "'" & Listrng.Parent.Name & "'!" & Listrng.Address
'Finding the criteria range based on which data will be fetched.
Set criteriarng = ConvertRange(sh, 1, 13, 4, 6)
'Finding the address of range along with sheet name.
b = "'" & criteriarng.Parent.Name & "'!" & criteriarng.Address
'Finding the range where data will be copied.
Set targetrng = ConvertRange(sh, 2, 21, 3, 3)
'Finding the address of range along with sheet name.
c = "'" & targetrng.Parent.Name & "'!" & targetrng.Address
'Calling the AdvancedFitler function.
AdvancedFilter a, b, c
End Sub
'ConvertRange Function
Public Function ConvertRange(ByVal sh As Worksheet, ByVal StartingRow As Long, ByVal StartingCol As Long, ByVal TotalCol As Long, ByVal LastRow As Long) As Range
'Calculating range based on below worksheet.
With sh
    'Find the range based on provided data.
    Set ConvertRange = .Range(.Cells(StartingRow, StartingCol), .Cells(LastRow, StartingCol + TotalCol - 1))
End With
End Function
'UDF AdvancedFilter
 Public Sub AdvancedFilter(Listrng As String, criteriarng As String, targetrng As String)
'Here Listrng,criteriarng and targetrng contain their range address along with sheet name.
'Use advanced filter based on data passed on this sub.
Range(Listrng).AdvancedFilter Action:=xlFilterCopy, criteriarange:=Range(criteriarng), copytorange:=Range(targetrng), Unique:=False
End Sub

【讨论】:

  • 主要的编码原则是KISS,可读性更好的代码更简单。然后去争取声誉,克里斯明确地建议你做什么以及为什么。此外,如果您有工作代码但想改进 SO 是错误的地方,请选择Code Review
【解决方案4】:

在您的code 中,将Range 传递给Public Sub AdvancedFilter() 会造成麻烦。因此,请尝试以String 的形式将Range.Address 传递给Public Sub AdvancedFilter()。请参考以下代码。

Option Explicit

Public Sub M()

    Dim sh As Worksheet, sh1 As Worksheet
    Dim sh_Name As String, sh1_Name As String
    Dim Listrng As Range, criteriarng As Range, targetrng As Range
    Dim a As String, b As String, c As String
    
    Set sh = Worksheets("Logical operation")
    Set sh1 = Worksheets("Transaction")
    
    sh_Name = "Logical operation"
    sh1_Name = "Transaction"
    
    Set Listrng = ConvertRange(sh1, 1, 1, 4, 22)
    'Debug.Print Listrng.Address
    a = Listrng.Address
    
    Set criteriarng = ConvertRange(sh, 1, 13, 4, 2)
    'Debug.Print criteriarng.Address
    b = "'" & sh_Name & "'" & "!" & criteriarng.Address
    'Debug.Print b
    
    Set targetrng = ConvertRange(sh, 2, 21, 1, 3)
    'Debug.Print targetrng.Address
    c = targetrng.Address
    
    Call AdvancedFilter(sh1_Name, a, b, c)

End Sub


'No change in Public Function ConvertRange()
Public Function ConvertRange(ByVal sh As Worksheet, ByVal StartingRow As Long, _
ByVal StartingCol As Long, ByVal TotalCol As Long, ByVal LastRow As Long) As Range

    With sh
        Set ConvertRange = .Range(.Cells(StartingRow, StartingCol), _
        .Cells(LastRow - StartingRow + 1, StartingCol + TotalCol - 1))
    End With

End Function
    
'All variables passed as Strings instead of Range with small modification in Code
Public Sub AdvancedFilter(sh1_Name As String, a As String, _
b As String, c As String)

        Sheets(sh1_Name).Range(a).AdvancedFilter Action:=xlFilterCopy, _
        CriteriaRange:=Range(b), CopyToRange:=Range(c), Unique:=False
        
End Sub

请让我知道您的反馈。


注意:当您将变量从一个 Sub 传递到另一个时,请避免多次重命名变量。

【讨论】:

  • 嘿,它有效,我也不需要传递工作表名称..感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多