Excel - 如何记住整个工作簿中按钮的点击状态? (例如显示隐藏数据或加入另一个按钮的状态)

Excel - how to memorize click-state of a button workbook-wide? (e.g. to show-hide data or join with another button's state)

(TLDR:问题直到 "use-case:")

我试图在第二次按下按钮时擦除 excel 列中的值。

在这个阶段,我有一个带有以下代码的按钮,如果按下它会显示来自另一个 sheet 的值。数据仅显示在当前 sheet 中,它永远不会超过列数,比如最多 10 列,它们将根据按钮状态被复制/删除。

(通过开发者工具实现为 ActiveX 按钮):

Private Sub Button_Click()

Worksheets("myworksheet.xlsx").Columns("E").Copy Destination:=Sheets(1).Columns("S")

End Sub

我想在会话期间全局存储某些值,这样如果按下另一个按钮,它也可以获得该按钮的状态(以便加入两个按钮引用的数据)。

存储和检索这些值的最佳方式是什么?

PS 这是我第一次涉足 Excel vba。主要目标是最小的开销,但仍然可以扩展到更多的逻辑。所以任何丑陋但快速的解决方案,最多可以说 20 个参数,对我来说也很好......"time to market" 很关键。

非常感谢您的宝贵时间和帮助。


用例:

显示数据加载过程中涉及的所有表或对象,从输入文件到报告域 - 但仅显示按下相关按钮的那些对象。例如。在域 "A" 中显示所有目标表,或在源源 "X".

中显示所有使用源文件的报告

按钮 1 有标签 "Domain A"。如果按下,它将获取另一个 sheet 中 "Domain A" 列中列出的所有作业并显示它们。

按钮 2 有标签 "CORE Database"。如果自己按下,它将显示数据库 Sheet 中 "tables" 列中在另一列中具有值 "CORE" 的所有值。

如果同时按下两个按钮,我想显示域 A 中的所有作业,以及它们作为目标的 "CORE Database" 中的所有表。

然后,如果再次按下按钮 "CORE Database",即 "toggled off",显示应该返回到仅显示域 A 的所有作业。

现在,如果按下标记为 "VIEW Layer" 的第三个按钮,域 A 中所有作业的所有视图的组合应该会显示。

组合所有三个按钮应该会显示所有三个按钮的组合。

这背后的逻辑,我想可以在很多地方实现,我会看看我能走多远。起点是有一个合适的位置来存储这些状态,如果事情变得非常疯狂,可能会有多达 30 个按钮。

每个按钮本质上都添加了自己的列 ("Dimension"),无论显示什么,都将是所有这些的横截面。所以重要的是,随时知道按下了什么按钮。

更新 2:
数据中的一些示例(警告,这超出了原始问题):
Jobs sheet 包含作业及其表。
Views sheet 包含视图及其源表。

如果只选择"Jobs"按钮,显示:
源数据:工作,去重

如果只按下"View"按钮,显示数据库中的所有视图,去重。
例如:

如果只选择"CORE"按钮,则显示核心数据库中的所有表,例如: JOINED 数据:表,取自作业 sheet 和视图 sheet,已删除重复数据 (编辑:这是不一致的,因为表格 X 和 Y 突然出现,它们可能被遗漏或显示更多工作)

如果按下 Jobs and Core 按钮,显示(这直接来自 Jobs sheet):
源数据:作业及其目标表

如果按下表和视图按钮:
(在本示例中,视图 B 未由任何作业交付)
源数据:视图及其源表

(所以 ViewA 使用两个表作为源)

如果按下 "Job" 和 "View" 按钮:
加入的数据:视图和相关工作,通过它们的匹配表加入

最后,如果按下所有三个按钮,实际上会显示更多的列和更多的行,因为重复数据删除较少:
加入的数据:视图和相关工作,通过它们的匹配表加入,显示所有

(尽管名称令人困惑 "B",ViewB 未由 jobB 加载。回想起来应该选择不同的名称)

-edit:我在塞缪尔的回答之前写了这篇文章,所以这显然是无关紧要的:)
现在我将采用以下解决方案,它对我有用,现在美丽不是那么重要

-更新:我现在使用全局变量,当然我的程序员告诉我这是有风险和危险的,但我现在只需要结果,它们只是状态的布尔值。任何建议仍然非常受欢迎。 这是我现在拥有的一些代码:

Public CORE_Pressed As Boolean

Sub clearCol(colLabel As String)
  Columns(colLabel).ClearFormats
  Columns(colLabel).ClearComments
  Columns(colLabel).ClearHyperlinks
  Columns(colLabel).Clear
End Sub

Private Sub Workbook_Open()
  SLJM_Pressed = False

End Sub      

Private Sub CORE_Button_Click()
CORE_Pressed = Not CORE_Pressed
If CORE_Pressed = True Then
  Worksheets("CORE.xlsx").Columns("E").Copy Destination:=Sheets(1).Columns("S")
Else
  clearCol ("S")
End If

End Sub

我可能会将按钮处理移到中央函数中,但这只是为了展示当前的方法。

也非常感谢 Samuel Everson 发表的评论,当事情需要更多时,他们提供了一个非常有趣的选择 "professional"。我知道全局变量很丑。

此解决方案基于一项新作品sheet,其中包含 3 个 activeX 切换按钮(均具有默认名称)。

我首先将一个单元格绑定到每个切换按钮 - A1ToggleButton1B1ToggleButton2C1ToggleButton3.这 returns TRUEFALSE 到基于 ToggleButton.
状态的单元格 ToggleButton control MS documentation

对于视觉效果,这里是源数据:

注意:由于不是一眼就能看出点进去的,可以更改背景色ToggleButton_Click 事件中的按钮。
像这样:

With Sheet1.ToggleButton1
    If .Value = True Then
        .BackColor = &HFF00&
    ElseIf .Value = False Then
        .BackColor = &H8000000F
    End If
End With
End Sub

Private Sub ToggleButton2_Click()
With Sheet1.ToggleButton2
    If .Value = True Then
        .BackColor = &HFF00&
    ElseIf .Value = False Then
        .BackColor = &H8000000F
    End If
End With
End Sub

Private Sub ToggleButton3_Click()
With Sheet1.ToggleButton3
    If .Value = True Then
        .BackColor = &HFF00&
    ElseIf .Value = False Then
        .BackColor = &H8000000F
    End If
End With
End Sub

我首先根据第一行值动态定义最后一列。
Info about finding the last row/column

注意: 我为 SourceLastCol 添加了 2 个语句 - 根据 sheet 的设置方式使用一个或另一个 - 如果你保持原样,它将使用第二条语句中的值。

使用找到的最后一列,然后我将第 1 行范围内的每个单元格从 A 列循环到最后一列。

如果该值为 True,则使用 TempArray 将该列值输出到另一项工作中 sheet(在本例中为 Sheet2)到 TempDestinationRange。 (有关此方法的更多信息,请参阅 http://www.cpearson.com/Excel/ArraysAndRanges.aspx)。

最好有一个 Submit 命令按钮来触发子程序,而不是每次单击切换按钮时 运行 它(就好像你有 30 个并且有人将它们全部更改一样这是很多多余的工作 sheet 更改)。

Sheet2 输出:

Sub CheckToggleAndJoinData()

Dim SourceLastCol As Long
Dim SourceLastRow As Long
Dim SourceRange As Range
Dim CellToCheck As Range
Dim TrueRange As Range
Dim DestinationRange As Range
Dim DestinationLastRow As Long
Dim DestinationLastCol As Long
Dim TempArray As Variant

With Sheet1
    SourceLastRow = .Cells(Rows.Count, "S").End(xlUp).Row
    .Range("S1:S" & SourceLastRow).ClearContents
    SourceLastRow = 0

    SourceLastCol = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column 'Use this one if there is no data to the right of your source columns.
    SourceLastCol = Sheet1.Cells(1, 1).End(xlToRight).Column 'Use this if there is data to the right of your source columns (note this will not work if there are blank gaps in your source columns)

    Set SourceRange = .Range(.Cells(1, 1), .Cells(1, SourceLastCol))
End With

Dim TrueColumnArray As Variant
Dim ColumnToCheck As Long
Dim ColumnCounter As Long

ColumnCounter = 0
For ColumnToCheck = 1 To SourceLastCol
    With Sheet1
        If .Cells(1, ColumnToCheck).Value = True Then
            ColumnCounter = ColumnCounter + 1
            SourceLastRow = .Cells(Rows.Count, ColumnToCheck).End(xlUp).Row
            Set TrueRange = .Range(.Cells(2, ColumnToCheck), .Cells(SourceLastRow, ColumnToCheck))

            DestinationLastCol = Sheet2.Cells(1, Columns.Count).End(xlToLeft).Column
            If ColumnCounter = 1 Then
                Set DestinationRange = Sheet2.Cells(1, DestinationLastCol)
            Else
                 Set DestinationRange = Sheet2.Cells(1, DestinationLastCol + 1)
            End If

            TempArray = TrueRange
            DestinationRange.Resize(UBound(TempArray, 1), 1).Value = TempArray
        End If
    End With
Next ColumnToCheck

End Sub

要删除重复数据(如某些 comments/edits/chat 中所述),您可能需要考虑使用 Dictionary object,因为这会将每个输入值存储为键 - 忽略后续出现的这个值。