【问题标题】:New to VBA: Compile Error Invalid Qualifier.VBA 的新功能:编译错误无效的限定符。
【发布时间】:2014-01-05 03:35:20
【问题描述】:

此代码旨在获取原始数据的电子表格,省略几列,然后重新格式化剩余部分。我欢迎对代码的任何和所有批评,因为我是 VBA 新手并且一无所知。关键问题在下面用 astriscs 指示的行的代码末尾。这是“编译错误:无效的限定符”出现的地方。我正在尝试将格式应用于 B 列和 F 列,但我只希望它一直到日期的最后一行。最后一行数据会因一张纸而异。

当错误被触发时,调试器会突出显示单词“count”。

提前感谢您的帮助。

Sub Macro2()
'
' Macro2 Macro
'
Union(Range("A:A"), Range("F:F"), Range("K:Q"), Range("S:V")).Delete
Range("A1").Select
ActiveCell.FormulaR1C1 = "FIRST"
Range("B1").Select
ActiveCell.FormulaR1C1 = "LAST"
Range("C1").Select
ActiveCell.FormulaR1C1 = "G"
Range("D1").Select
ActiveCell.FormulaR1C1 = "PHONE"
Range("E1").Select
ActiveCell.FormulaR1C1 = "ADDRESS"
Range("F1").Select
ActiveCell.FormulaR1C1 = "CITY"
Range("G1").Select
ActiveCell.FormulaR1C1 = "STATE"
Range("H1").Select
ActiveCell.FormulaR1C1 = "ZIP"
Range("I1").Select
ActiveCell.FormulaR1C1 = "MONTH"
Range("J1").Select
ActiveCell.FormulaR1C1 = "YEAR"
Columns("e:h").Insert Shift:=xlToRight
Columns("A:B").ColumnWidth = 12
Columns("C:C").ColumnWidth = 2
Columns("D:d").ColumnWidth = 13
Columns("e:e").ColumnWidth = 0.38
Columns("F:F").ColumnWidth = 5
Columns("G:G").ColumnWidth = 11
Columns("H:H").ColumnWidth = 0.38
Columns("I:N").ColumnWidth = 14
**Union(Range("B:B"),Range("F:F")).Rows.Count.End(xlUp).Row**
Range("B1").Activate
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent5
.TintAndShade = 0.599993896298105
.PatternTintAndShade = 0
End With


End Sub 

【问题讨论】:

标签: excel vba


【解决方案1】:

当我对通过字符串属性创建的对象类型感到困惑时,我会使用此技术。

在 Excel 的 Visual Basic 编辑器中,如果您没有希望以这种方式使用的现有模块,请创建一个新模块。如果您在 Project Explorer 中选择模块并单击 F4,则可以将模块的名称更改为“Experiments”。

输入或复制:

Option Explicit
Sub TestA()

End Sub

总是Option Explicit 开始我的模块。在 VBA 帮助中查看 Option Explicit,它会告诉您为什么这是一个好主意。

我还创建了一个空子例程,我将在其中键入一些语句。

开始输入一个新语句,这样你就有了:

Sub TestA()

  Debug.Print Range("B:B").

End Sub

当您在新行末尾键入句点时,弹出窗口将显示可用的方法和属性。正如预期的那样,此列表将显示 Range 的所有方法和属性。键入“地址”或从列表中选择地址以获取:

Sub TestA()

  Debug.Print Range("B:B").Address

End Sub

点击 F5 运行此宏,立即窗口中会出现以下内容:

$B:$B

这是 B 列中所有行的地址,这是您所期望的。

现在向宏添加两条语句:

  Debug.Print Range("F:F").Address
  Debug.Print Union(Range("B:B"), Range("F:F")).Address

再次运行这个宏,你会得到:

$B:$B
$F:$F
$B:$B,$F:$F

这又是预期的结果。

现在添加:

  Debug.Print Union(Range("B:B"), Range("F:F")).Rows.

出现的弹窗不会改变,因为Range.Rows仍然是一个范围。

添加或选择“地址”完成语句,再次运行宏得到:

$B:$B
$F:$F
$B:$B,$F:$F
$B:$B,$F:$F

这可能不是您所期望的,但请考虑一下。 $B:$B,$F:$F 是 B 列和 F 列中的所有行,因此添加属性 Rows 不会更改地址。

现在将以下语句添加到宏中:​​

  Debug.Print Union(Range("B:B"), Range("F:F")).Count
  Debug.Print Union(Range("B:B"), Range("F:F")).Rows.Count

运行宏,这些语句将分别输出一个整数。我正在使用 Excel 2003,所以我得到:

 131072 
 65536 

如果您使用的是更高版本的 Excel,您将获得更大的整数。第二个整数是您的 Excel 版本的工作表中的行数。第一个整数是您的 Excel 版本的工作表的两列中的单元格数。

现在添加:

  Debug.Print Union(Range("B:B"), Range("F:F")).Rows.Count.

当您键入最后一个句点时,不会出现弹出窗口,因为整数没有您可以通过这种方式选择的方法或属性。方法.End(xlUp) 对范围进行操作;它不是 Count 的属性,这就是为什么你会得到“无效的限定符”。

将属性串在一起时很容易混淆。就我个人而言,我避免使用字符串属性,因为即使运行速度更快,我也需要更长的时间来理解和调试。在某些情况下,最小化运行时间是重中之重,但这是其中一种情况吗?您在这种方法上浪费了多少小时?

考虑:

  Dim Rng1 As Range
  Dim Rng2 As Range
  Dim Rng3 As Range
  Dim RowMax As Long

  Set Rng1 = Range("B:B")
  Set Rng2 = Range("F:F")
  Set Rng3 = Union(Rng1, Rng2)
  RowMax = Rng3.Count

  Debug.Print RowMax

  Debug.Print Rng3.Find("*", Range("B1"), xlValues, xlWhole, xlByRows, xlPrevious).Row

您不需要RowMax,但我已将其包含在内,因此您绝对清楚Rng3.Count 返回的内容。我也用范围去了OTT。我很乐意输入:Set Rng3 = Union(Range("B:B"), Range("F:F")),因为我觉得它很容易理解。

方法.End(xlUp) 对单元格进行操作。 MultiCellRange.End(xlUp).Row 是有效的语法,但我无法让它返回有用的信息。如果您想使用.End(xlUp),请考虑:

  Dim RowMaxColB As Long
  Dim RowMaxColF As Long

  RowMaxColB = Cells(Rows.Count, "B").End(xlUp).Row
  RowMaxColF = Cells(Rows.Count, "F").End(xlUp).Row

我同意 Siddharth 的观点,Find 似乎是这种情况下的最佳方法。但是,你应该看看我的这个答案,https://stackoverflow.com/a/20849875/973283,来回答一个不同的问题。它包含一个宏,该宏演示了一系列查找最后一行和最后一列的方法,并显示了它们失败的情况。

【讨论】:

  • @L42。谢谢。自从我第一次学习 Excel VBA 以来可能已经 10 多年了,但我仍然记得我对对象模型有多么困惑。
  • 感谢大家在这里的贡献。托尼,我非常感谢您花时间分享您的知识。糟糕的代码确实......哈哈,我有很多东西要学。谢谢你的帮助!这里有很多东西要吸收。
  • @Thomas。我怀疑我的第一个宏有这么雄心勃勃或这么好,所以不要难过。
【解决方案2】:

你还没有问过这个问题的答案。请参阅Requested answer 以获得您要求的答案。您的代码有效,所以我怀疑您是否知道它是错误的 VBA。

从顶部的评论中,我假设这段代码是由宏记录器创建的。宏记录器输出语法正确的代码,但代码很差。代码不佳的至少部分原因是在您键入时正在记录语句。记录器不知道您的目标。如果光标在单元格 A1 中并且您按 Right,则记录器将选择 B1,因为这是屏幕上发生的情况。在 VBA 中可能存在Select 是一种有用的方法但很少见的情况。

记录器也在活动工作表上运行,这很少是一个好主意。如果启动此宏时错误的工作表处于活动状态,它将被销毁并删除 13 列。

我假设您只打开了一个工作簿,因此我可以假设活动工作簿是必需的工作簿。处理多个工作簿只是稍微复杂一点,但我宁愿忽略这种复杂性。

考虑:

Sub TestB()

  With Worksheets("Sheet1")
    .Range("A1").Value = "FIRST"
  End With

End Sub

With Worksheets("Sheet1") 声明此代码将在活动工作簿的名为“Sheet1”的工作表上进行操作。 End With 终止 With 语句。

你可以嵌套With语句:

  With Worksheets("Sheet1")
    With .Range("A1")
      .Value = "FIRST"
      .Font.Bold = True
      .Font.Color = RGB(0, 255, 255)
    End With
  End With

.Range("A1") 开头的时间段表示.Range("A1") 是在当前With 为Worksheets("Sheet1") 内运行。如果我省略了那个句号,Range("A1") 在活动工作表上运行。

.Value 开头的句号表示它是在Worksheets("Sheet1") 内的Range("A1") 上运行的。如果我省略该句点,Value 将在活动单元格上运行。

With 语句的使用使您的代码更紧凑、更清晰。但是,您必须包含句点。考虑:

  Dim Rng1 As Range

  With Worksheets("Sheet2")
    Set Rng1 = Union(Range("A:A"), Range("C:D"), Range("F:G"))
    Debug.Print Rng1.Address
    Debug.Print Rng1.Worksheet.Name
    Set Rng1 = Union(.Range("A:A"), .Range("C:D"), .Range("F:G"))
    Debug.Print Rng1.Address
    Debug.Print Rng1.Worksheet.Name
  End With

如果活动工作表是“Sheet1”,则输出为:

$A:$A,$C:$D,$F:$G
Sheet1
$A:$A,$C:$D,$F:$G
Sheet2

范围地址看起来相同,但它们适用于不同的工作表。

您可以将很多代码替换为:

  With Worksheets("Sheet1")
    .Range("A1").Value = "FIRST"
    .Range("B1").Value = "LAST"
    .Range("C1").Value = "G"
    .Range("D1").Value = "PHONE"
    .Range("E1").Value = "ADDRESS"
    .Range("F1").Value = "CITY"
    .Range("G1").Value = "STATE"
    .Range("H1").Value = "ZIP"
    .Range("I1").Value = "MONTH"
    .Range("J1").Value = "YEAR"
  End With

你也可以写:

  With Worksheets("Sheet1")
    .Range("A1:J1").Value = Array("FIRST", "LAST", "G", "PHONE", "ADDRESS", _
                                  "CITY", "STATE", "ZIP", "MONTH", "YEAR")
 End With

这个 VBA 更高级。您可以将值从工作表区域复制到数组或从数组复制到工作表区域。有许多问题的答案可以探索这种能力,我不会在这里重复这些答案。这只是一个演示,供您稍后探索。

我不喜欢你的所作所为。在您的第一个语句中,您删除了一些列,因此 B 列成为 A 列,R 列成为 I 列。然后您将列标题更改为新位置。既然你只是移动数据,为什么你需要改变列标题呢?更重要的是,在九个月内,有人将添加一列或重新排列现有列。你的代码将继续运行,你的名字将是泥巴。

我更喜欢这样的:

  With Worksheets("Sheet1")
    If .Range("B1").Value = "FIRST" And .Range("C1").Value = "LAST" And _
       .Range("D1").Value = "G" And .Range("E1").Value = "PHONE" And _
       .Range("G1").Value = "ADDRESS" And .Range("H1").Value = "CITY" And _
       .Range("I1").Value = "STATE" And .Range("J1").Value = "ZIP" And _
       .Range("R1").Value = "MONTH" And .Range("W1").Value = "YEAR" Then
      ' Column headings as expected.  Continue with macro.
    Else
      Call MsgBox("I am sorry but I cannot proceed because the column " & _
                  "headings are not as I expected.", vbOKOnly)
      Exit Sub
    End If
  End With

如果您的代码要求工作表采用特定格式并且该格式可能会随着时间而改变,请检查该格式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 2021-12-22
    相关资源
    最近更新 更多