将表单控件按钮固定到多个工作表

时间:2016-11-01 17:30:21

标签: excel vba excel-vba

我有一个包含多个工作表的工作簿,每个工作表都有一系列按钮。我想将按钮固定到每个工作表的特定位置,以便每次用户打开工作簿时按钮都会找到正确的位置。问题是所使用的代码仅在置于“ThisWorkbook”中时才有效。我希望能够逐页编码按钮。我已经尝试将代码放入工作表区域,但它不起作用,我无法弄清楚我在这里缺少什么来使其正常工作。

编辑 - 工作簿中的每个工作表都是独一无二的,每个按钮分配不同的宏,每个按钮位于每个工作表的不同位置。工作表本身共享按钮名称("按钮1","按钮2"等),所以我认为按钮需要固定'对于每个单独的工作表,允许这种位置和使用的变化,因为表1上的按钮1与表2上的按钮1完全不同。

下面的代码操作工作簿,而不是我已经被识别为搞砸#1的工作表。

VBE screenshot

Private Sub Workbook_Open()
Dim rng As Range
Set rng = ActiveSheet.Range("D5")
With ActiveSheet.Shapes("Button 1")
    .Top = rng.Top
    .Left = rng.Left
    .Width = rng.Width
    .Height = rng.RowHeight
End With
End Sub

编辑#2使用Mat的建议我试图识别表格中的每个按钮,但我不知道如何使用public property get并识别机器人"按钮名称"和#34;范围"每个按钮,以便我可以在每张纸上找到多个按钮

    Option Explicit
Public Property Get ButtonName() As String
ButtonName = "Button 1"
End Property
Public Property Get ButtonAnchor() As Range
Set ButtonAnchor = Me.Range("B2")
End Property

3 个答案:

答案 0 :(得分:2)

迭代工作簿的工作表集合:

Private Sub Workbook_Open()
    Dim rng As Range
    Dim sht As Worksheet

    For Each sht In Worksheets
        With sht
            Set rng = .Range("D5")
            With .Shapes("Button 1")
                .Top = rng.Top
                .Left = rng.Left
                .Width = rng.Width
                .Height = rng.RowHeight
            End With
        End With
    Next sht
End Sub

当然这假设每张纸都有一个名为“按钮1”的按钮

答案 1 :(得分:2)

user3598756有正确答案(正如Mat's Mug指出的那样)。如果您希望在用户打开工作簿时发生某些事情,它将进入workbook_open事件处理程序,该处理程序位于ThisWorkbook代码模块中。这就是Excel VBA的工作方式。如果我想让我的车开始工作,但拒绝将气体放入油箱并要求将气体放入轮胎中,那么猜猜会发生什么?

但是,您仍然可以使用Thisworkbook代码模块中的单个工作表。略微调整user3597856的代码:

Private Sub Workbook_Open()
Dim rng As Range
Dim sht As Worksheet

For Each sht In Worksheets
    With sht
        Select Case .Name
            Case "Sheet 1"
                Set rng = .Range("D5")
                With .Shapes("Button 1")
                    .Top = rng.Top
                    .Left = rng.Left
                    .Width = rng.Width
                    .Height = rng.RowHeight
                End With
            Case "Sheet 2"
                Set rng = .Range("G425")
                With .Shapes("Button 1")
                    .Top = rng.Top
                    .Left = rng.Left
                    .Width = rng.Width
                    .Height = rng.RowHeight
                End With
            Case Else
                'What to do when its not a sheet we care about? Nothing.
        End Select
    End With
Next sht
End Sub

这样做的好处是,设置所有按钮位置的所有代码都位于一个不错的位置,因此当您添加或删除工作表时,您只需要到一个位置来更新代码。另一个好处是此代码只执行一次:工作簿打开时。它确实有一个缺点,就是不能满足你的要求,即代码无法循环遍历每个工作表。

另一个(不太有用)选项不涉及在工作表中循环以设置按钮位置是使用Worksheet_Activate事件。它驻留在每个单独的工作表代码模块中,因此每次代码更改时都可以使用无限数量的子例程进行更新。每次用户单击工作表的选项卡时,都会触发此事件。稍微调整一下你的代码:

Private Sub Worksheet_Activate()
Dim rng As Range
Set rng = ActiveSheet.Range("D5")
With ActiveSheet.Shapes("Button 1")
    .Top = rng.Top
    .Left = rng.Left
    .Width = rng.Width
    .Height = rng.RowHeight
End With
End Sub

这个想法太可怕了,它确实有两个好处。首先,如果用户在工作表上移动按钮,则每次他们离开并切换回来时它都会自动重置。另一个好处是它符合您的要求,即代码必须放在单个工作表代码模块中,而不是在工作表中循环。

答案 2 :(得分:2)

在每个工作表上添加一个Property Get成员,其中包含一个此类按钮;例如,这里将是一个工作表,其按钮位于A1:

Option Explicit

Public Property Get ButtonAnchor() As Range
    Set ButtonAnchor = Me.Range("A1")
End Property

这将是按钮在单元格D5中的另一个:

Option Explicit

Public Property Get ButtonAnchor() As Range
    Set ButtonAnchor = Me.Range("D5")
End Property

继续为每个有按钮的工作表添加该成员,每次指定Range对象代表您希望按钮所在的位置。

然后,在ThisWorkbook文档类模块中,您将迭代所有工作表并对ButtonAnchor成员进行后期绑定访问;因为这会在具有该属性的工作表中引发错误,所以你将用On Error语句包装它:

Private Sub Workbook_Open()

    Dim sheet As Object
    Dim anchor As Range
    For Each sheet In ThisWorkbook.Worksheets
        On Error Resume Next
            Set anchor = sheet.ButtonAnchor
            Err.Clear
        On Error GoTo 0
        If Not anchor Is Nothing Then
            With sheet.Shapes("Button 1")
                .Top = anchor.Top
                .Left = anchor.Left
                .Width = anchor.Width
                .Height = anchor.RowHeight
            End With
        End If
    Next

End Sub

对于没有anchor属性的工作表,Nothing范围为ButtonAnchor,因此我们通过测试anchor Is Nothing来跳过这些工作表。另一个假设是,按钮在每个具有该按钮的工作表上都被命名为Button 1

您可以通过添加其他属性来删除该假设:

Public Property Get ButtonName() As String
    ButtonName = "Button 1"
End Property

然后另一张表可以:

Public Property Get ButtonName() As String
    ButtonName = "Button 42"
End Property

然后转而使用With sheet.Shapes("Button 1")而不是For Each中的ThisWorkbook.Workbook_Open循环内部:

    If Not anchor Is Nothing Then
        With sheet.Shapes(sheet.ButtonName)
            .Top = anchor.Top
            .Left = anchor.Left
            .Width = anchor.Width
            .Height = anchor.RowHeight
        End With
    End If