如何在 Excel 的 VBA 编辑器中禁用自动格式设置?

How can one disable autoformatting in Excel's VBA editor?

Excel 的内置 VBA 编辑器中最烦人的一个功能是——我的意见——代码的激进自动格式化,它坚持在光标离开该行时立即重写我输入的内容。尤其令人沮丧的是,编辑器折叠了所有空格,从而阻止了任何有意义的代码对齐。例如,如果我尝试用等号对齐一系列赋值,并用小数点分隔符对齐值:

price    = 10.01
quantity =  3.2
vat      =  0.11

编辑器不可避免地通过折叠所有空格来打乱它:

price = 10.01
quantity = 3.2
vat = 0.11

有什么办法可以避免这种不受欢迎的自动格式化?

分配化妆品:-)

There's neither a special VBE property to change the VBE (autoformatting) options directly nor a way to do it programatically. - So afaik VBE irrevocably forces autoformatting upon the user by partial workarounds.

a) Class 方法

为了艺术和乐趣,实际上(非常)基本的class方法给你一个开始的想法;赋值参数作为 strings 传递,允许任何光学格式 - 如果那是你真正想要的:

当前模块中的示例调用

Sub ExampleCall()
    Dim x As New cVars
    
    x.Add "price    =    11.11"           ' wrong assignment
    '...
    x.Add "price    =    10.01"           ' later correction
    x.Add "quantity =  1241.01"
    x.Add "vat      =     0.11"
    
    Debug.Print "The price is $ " & x.Value("price")
End Sub

Class模块cVars

Option Explicit
Private dict As Object

Sub Add(ByVal NewValue As Variant)
    'split string tokens via equal sign
    Dim tmp
    tmp = Split(Replace(Replace(NewValue, vbTab, ""), " ", "") & "=", "=")
    'Identify key and value item
    Dim myKey As String, myVal
    myKey = tmp(0)
    myVal = tmp(1): If IsNumeric(myVal) Then myVal = Val(myVal)
    'Add to dictionary
    If dict.exists(myKey) Then
        dict(myKey) = myVal
    Else
        dict.Add myKey, myVal
    End If
    'Debug.Print "dict(" & myKey & ") =" & dict(myKey)
End Sub

Public Property Get Value(ByVal myVarName As String) As Variant
    'get variable value
    Value = dict(myVarName)
End Property

Private Sub Class_Initialize()
    'set (late bound) dict to memory
    If dict Is Nothing Then Set dict = CreateObject("Scripting.Dictionary")
End Sub

Private Sub Class_Terminate()
    Set dict = Nothing
End Sub


编辑#1截至 2021 年 3 月 3 日

b)Rem评价方法

再一次只是为了艺术的缘故,一种阅读作业的方法进入了注释掉的代码行通过,是的通过Rem 起伏对这种起源于前 Basic 时代 ) 的古老用法深感叹息,因为它允许使用任何想要的空格或制表符来格式化数据,并且不会通过撇号 '.[希望与当前的 outcommentings 混淆。 =33=]

这个 Test 过程只需要通常的声明加上一些赋值调用以及提到的 Rem 部分。两个简单的帮助程序获取代码行,通过字典分析它们 class cVars 并最终分配它们。

注意下面的例子

  • 需要对 Microsoft Visual Basic Extensibility 5.3
  • 的库引用
  • 使用 a) 部分未更改的 class cVars 只是为了避免重写它。
Option Explicit
Private Const THISMODULE As String = "Module1"      ' << change to current code module name

Sub Test()                                          ' procedure name of example call
    'Declare vars
    Dim price    As Double: Assign "price", price
    Dim quantity As Double: Assign "quantity", quantity
    Dim vat      As Double: Assign "vat", vat
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'Enter assignments via Rem(ark)
    '(allowing any user defined formatting therein)
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Rem price    =    10.01
    Rem quantity =  1241.01
    Rem vat      =     0.11
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Debug.Print quantity & " à $" & price & " = " & Format(quantity * price, "$#,##0.00")
    
End Sub

帮助程序 Assign 评估程序 Rem 代码行 Test

Sub Assign(ByVal myVarName As String, ByRef myvar)
    Const MyProc As String = "Test"
    Dim codelines
    getCodelines codelines, THISMODULE, ProcedureName:=MyProc
    'Debug.Print Join(codelines, vbNewLine)
    
    Dim x As New cVars                          ' set class instance to memory
    Dim line As Variant, curAssignment
    For Each line In codelines
        curAssignment = Split(line, "Rem ")(1)  ' remove Rem prefix from codelines
        If curAssignment Like myVarName & "*" Then
            x.Add curAssignment
            myvar = x.Value(myVarName)
        End If
    Next
    
End Sub

帮助程序getCodelines

由上述过程调用Assign。 Returns 来自调用过程 Test 的相关 Rem 代码行。 - 当然可以只过滤一个代码行。

Sub getCodelines(ByRef arr, ByVal ModuleName As String, ByVal ProcedureName As String)
    Const SEARCH As String = "Rem "
    'a) set project
    Dim VBProj As Object
    Set VBProj = ThisWorkbook.VBProject
    If VBProj.Protection = vbext_pp_locked Then Exit Sub    ' escape locked projects
    'b) set component
    Dim VBComp As Object
    Set VBComp = VBProj.VBComponents(ModuleName)
    Dim pk As vbext_ProcKind

    'd) get relevant code lines
    With VBComp.CodeModule
        'count procedure header lines
        Dim HeaderCount As Long:  HeaderCount = .ProcBodyLine(ProcedureName, pk) - .ProcStartLine(ProcedureName, pk)
        'get procedure code
        Dim codelines
        codelines = Split(.lines(.ProcBodyLine(ProcedureName, pk), .ProcCountLines(ProcedureName, pk) - HeaderCount), vbNewLine)
        'filter code lines containing "Rem" entries
        codelines = Filter(codelines, SEARCH, True)
    End With
    'return elements
    arr = codelines
End Sub

不要忘记集成 a) 部分中的 class 模块 CVars