【问题标题】:Follow-Up to VBA inheritance via construction, constructor not working?通过构造跟进VBA继承,构造函数不起作用?
【发布时间】:2017-02-16 02:29:00
【问题描述】:

这是this问题的后续。

这是我的用例:我想逐个单元格比较两个 Excel 文件并突出显示不同的单元格。每个文件将有几张纸,每张纸将有几列,每列都有一个标题和一些值(通常)。这是我的比较代码的草稿活动图:

Activity Diagram

这是我的草稿类图:

Class Diagram

我的目标是让 VBA 对于我经常做的事情(例如比较新旧版本的电子表格)变得不那么繁琐。也就是说,我希望它更像 Python 一样工作......特别是,我想编写这样的代码:

For Each Sheet1 In File1
    Name1 = Sheet1.Name
    If File2.sheet_dict.Exists(Name1) Then
        Sheet2 = File1.Sheets(File2.sheet_dict(Name1))
        Sheet2.Checked = True
        For Each Col1 In Sheet1.cols
            hdr = Col1.Header
            If Sheet2.header_dict.Exists(hdr) Then
                Col2 = Sheet2.cols(Sheet2.header_dict(hdr))
                Col2.Checked = True
                For Each Val1 In Col1.Vals
                    Val2 = Col2.Vals(Val1.row_number)
                    Val2.Checked = True
                    If Not Val1.Match(Val2) Then
                        Val1.formatBad()
                        Val2.formatBad()
                    End If
                Next Val1
                For Each Val2 In Col2.Vals
                    If Not Val2.Checked Then
                        Val2.formatBad
                    End If
                Next Val2
            Else
                Col1.formatBad()
            End If
        Next Col1
        For Each Col2 In File2.cols
            If Not Col2.Checked Then
                Col2.formatBad
            End If
        Next Col2
    Else
        Sheet1.formatBad()
    End If
Next Sheet1

For Each Sheet2 In File2
    If Not Sheet2.Checked Then
        Sheet2.formatBad()
    End If
Next Sheet2

当然,我会先将所有数据加载到对象中,但你明白了。尝试在 VBA 中做这样的事情是不是很疯狂?

【问题讨论】:

  • 再次嗨 :)。在我看来,您以某种方式以自己的方式重写 Excel 的 COM 类模型,这还不够合理。如果您想简化或添加一些模型中没有充分存在的操作,例如Sheet_Exists(..), Header_Exists(..) 等,我会用我自己的额外例程集来丰富模型,但不重写类模型。
  • 你知道Excel的COM类模型的好图吗?我试图避免必须使用通常用于迭代一个范围内的单元格的复杂方式(对我来说,通常是在列上,然后在列中的值上)。我永远不记得如何获得一列中的最后一行、一行中的最后一列等。我已经为这些编写了函数,但这太不直观了。我认为将该代码包装在一个类中会简化该过程。我做错了吗?
  • 我没有图形或 UML 格式。 This 是 Excel 对象模型的指南。我找到了模型的一小部分的图形here
  • 对于你问题的另一部分,是的,我认为你走错了路。将您自己的例程包装在实用程序类中很好,但是包装和封装 Excel 对象模型的全部或大部分是不合理的IMO
  • 仅供参考 - Excel 2016(至少我使用的两个版本)带有“电子表格比较”工具。

标签: vba excel class oop


【解决方案1】:

想要使用面向对象的语言并不疯狂 VBA 的功能,但您提供的用例不是 与擅长的内置对象相去甚远 已经提供了,所以不清楚你会提供多少 从您为获得它而增加的复杂性中获益。有 在 excel vba 中可以利用相当多的力量,但它是 尽可能发挥它的优势。

您可以更轻松地为不同的单元格着色 有效率的 通过使用本文末尾的代码 - 显然不这样做 所有你想要但显然不需要的东西 对单列和单行诉诸 OO。

Excel 和 vba 与程序员完​​全不同 习惯于来自提供完整的python之类的东西 类继承。使用 VBA,您只能拥有 接口继承,这将允许您重用代码。但 如果你不小心,你很容易得到很多 您必须从一个类复制到另一个类的存根代码 能够满足您希望类实现的接口。

还有另一件事你肯定要包装你的 来自传统的OO语言,这就是多少 您在内存对象中复制的数据,而不是仅仅保留 工作表并根据需要访问它们。有一种自然 想要将所有内容加载到对象中并进行操作的倾向 从那里开始 - 但这是一个你真的应该三思而后行的冲动 在这种环境下。

如果您有一个现有的服务器后端来验证 然后至少在工作表和数据库之间移动的数据 您有一种方法可以分离正常的 MVC 关注点。实际上你会 将 excel 用作一种具有附加功能的网页 电子表格用户喜欢的。如果你没有后端,那么你 真的必须非常小心地验证你的模型和数据 环境。你应该得到 习惯于保护工作表的想法,除了那些单元格 用户必须输入数据(假设您正在编写代码 使他人受益,而不仅仅是自己)。事实上这是一个很好的 想法为输入单元格和计算单元格着色 颜色来突出这种差异。后者应该受到保护 而前者在需要的地方可以触发将验证的事件 输入并更新模型状态(如果 你有一个)。

保护单元格还允许您将状态信息隐藏在一个 工作表中定义明确的部分,可用于参考 回到工作对象。事实上,好的用例是那些 将定义明确的单元块作为用户界面隔离到特定的 类实例。

您应该尽可能使用范围来引用 相同的工作表和其他人。命名范围是您的朋友。数据 验证列表对连续数据也很有帮助,应该 尽可能使用它们,因为它们的工作效率很高。为了 大小有限的非连续数据集,您可以使用 ActiveX 可以引用内存中对象实例的组合框,如果它们 事件处理程序被传递一个对后者唯一的 id。

检查事件更改时,应注意 Worksheet_Change 投票,你会在网上看到很多例子。这个可以 如果您不小心,请花点时间。

总而言之:使用您可以从 excel 和 不要重新发明轮子。

' Compares the sheet 1 of the workbook you're in
' with sheet1 of the workbook file in 'Filename'
' and colors the cells that differ between the two.
Sub compare_workbooks_sheet1()
    Dim Filename As String
    Filename = "C:\MyBook.xlsm"

    Dim wrkbk1 As Workbook
    Set wrkbk1 = Workbooks.Open(Filename:=Filename)

    Dim sht1 As Worksheet ' worksheet you're in
    Dim sht2 As Worksheet ' worksheet you've opened to compare
    Set sht1 = wrkbk1.Worksheets("Sheet1")
    Set sht2 = ThisWorkbook.Worksheets("Sheet1")

    Dim row As Long, col As Long
    With sht2
      For row = 1 To sht1.UsedRange.Rows.Count
          For col = 1 To sht1.UsedRange.Columns.Count
              If sht1.Cells(row, col) <> sht2.Cells(row, col) Then
                  .Cells(row, col).Interior.ColorIndex = 5
              End If
          Next
      Next
    End With

    wrkbk1.Close

End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 2013-06-01
    • 2023-04-03
    • 2015-11-11
    相关资源
    最近更新 更多