当目标单元格通过表单控件选项按钮更改时,VBA宏不会触发

时间:2017-09-29 05:06:24

标签: excel vba excel-vba

我确实刚刚用VBA弄湿了,因为这是我的第一个宏。经过几个小时的搜索,我似乎无法找到一个解决方案,这个解决方案对我有用,所以我在这里。

在Sheet3上我在组合框中有3个选项按钮,这些按钮链接到Sheet4上的单元格“B18”(Sheet4对用户是隐藏的,如果你愿意,则是后台)。当选择三个选项按钮中的任何一个时,“Sheet4!B18”会更新(例如1,2或3)。我想要发生的是根据'Sheet4!B18'中的值更改'Sheet3!B17',或者有效地:IF('Sheet4!B18'=2,SET('Sheet3!B17'="Some Text Here:"),SET('Sheet3!B17'="0%")),但仍允许用户输入'Sheet3!B17'。我在Sheet4上有一个VBA宏,代码如下:

Private Sub Worksheet_Change(ByVal Target As Range)

    If Target.Worksheet.Range("B18") = 2 Then
        Worksheets("Sheet3").Range("B17") = "Some Text Here:"

    Else
        Worksheets("Sheet3").Range("B17") = "0%"

    End If

End Sub

如果我手动更新'Sheet4!B18',则会触发宏并显示所需的结果。如果我使用Sheet3上的3个选项按钮中的任何一个,即使目标单元格正在更新,宏也不会被触发。

在我的搜索中,我似乎找不到任何具体的东西,但从我所知道的“Worksheet_Change”函数看不到来自表单控件的单元格的更改,因为对链接单元格的更改被视为“重新计算”如果它来自一个公式。我不知道这是多么正确,但我的搜索让我相信我需要在3个按钮和/或组合框中分配另一个宏,当其中任何一个被选中/更改时,它会以某种方式触发工作宏在Sheet4上。

我想也许我可以创建一个新的宏,我将分配给组框或选项按钮本身,所以我尝试了,无法得到任何工作。我尝试将上面的宏代码添加到另一个子Sub mode()并仅分配给组框,然后只分配按钮,但两种情况都没有发生。我继续尝试调整代码,以防引用不正确,但无论我如何指定引用,都没有看到任何变化。我没有收到任何错误消息,但除非我手动更改'Sheet4!B18'中的值,否则不会触发任何操作。

有没有办法让我在Sheet4上工作的第一个宏触发关闭更改目标单元格值的选项按钮,比如强制它只查看那个特定单元格进行更改?我是否坚持为按钮和/或组合框制作另一个宏来触发Sheet4上的宏?我是不是太复杂了,我可以使用一些内置的Excel工作表功能?

2 个答案:

答案 0 :(得分:1)

IF / THEN是一个很好的方法。 VBA还支持具有IIF功能的三元逻辑,如下所示:

Worksheets("Sheet3").Range("B17") = IIF(Worksheets("Sheet4").Range("B18") = 2, "Some Text Here:", "0%")

这看起来有点难以阅读,但这是一个很好理解的概念,因为它存在于许多语言中,并且通常采用更简化的实现,使其非常有用和简洁。

此外,我建议进行一些其他更改,使您的代码更易于编写,阅读和维护(特别是当它变得更复杂时)。

首先,为工作表添加别名,如下所示:

Dim this as Worksheet: Set this = Worksheets("Sheet3")
Dim that as Worksheet: Set that = Worksheets("Sheet4")

现在您可以像这样重写代码:

If that.Range("B18") = 2 Then
    this.Range("B17") = "Some Text Here:"
Else
    this.Range("B17") = "0%"
End If

现在的三元方法是:

this.Range("B17") = IIF(that.Range("B18") = 2, "Some Text Here:", "0%")

您可以使用别名获得您喜欢的具体内容。例如,您可以实现范围,而不仅仅是工作表,如下所示:

Dim this as range: Set this = Worksheets("Sheet3").Range("B17")
Dim that as range: Set that = Worksheets("Sheet4").Range("B18")

this = IIf(that = 2, "Some Text Here:", "0%")

另外,我发现使用cells属性比使用range属性更容易,特别是当你开始进行单元格数学时。在这种情况下,Range("B17")变为Cells(17, 2)

您还可以通过在即时窗口中键入Application.ReferenceStyle = xlR1C1来更改电子表格中引用单元格的方式。这样你就不必在A2风格范围之间进行心理转换,而是采用笛卡尔风格(2,1)。

答案 1 :(得分:0)

有时你只需要经历整个思考过程并在你有“啊哈哈!”之前输入所有内容。那一刻,因为那正是我发生的事情。我对自己说,“为什么我不能只有一个由选项按钮触发的宏来检查我的链接单元格然后继续更新我想要的单元格?”好吧,最终我能够找到合适的代码,这是完美的:

Sub mode()  ' mode is the name of this macro

    If Worksheets("Sheet4").Range("B18") = 2 Then
        Worksheets("Sheet3").Range("B17") = "Some Text Here:"

    Else
        Worksheets("Sheet3").Range("B17") = "0%"

    End If

End Sub

事实证明,我忽略了简单的解决方案,上面的宏只是我将其分配到组框中的3个选项按钮后所需要的,而不是组框本身。由于用户无法访问隐藏的Sheet4,因此'Sheet4!B18'永远不会有手动用户输入,因此可以安全地删除我在Sheet4上首次使用的宏。由于所选择的选项按钮是指定宏的触发器,因此每次更改选项时都会执行该选项,并且仅在更改选项时执行。完美!

修改

感谢Chris Strickland提供更好代码的一些提示!我接着将以上内容修改为您在下面看到的效果稍好一些(使用Cells()而不是Range()),将原始值保存到另一个单元格,如果选择了选项1或3,则将其恢复,使用了别名,最后是IIf运算符。

Sub mode()  ' mode is the name of this macro
Dim S3 As Worksheet: Set S3 = Worksheets("Sheet3")
Dim S4 As Worksheet: Set S4 = Worksheets("Sheet4")

If IsNumeric(Cells(17, 2)) = True Then
    S3.Activate
    S4.Cells(18, 3) = Cells(17, 2).Value
End If
S3.Cells(17, 2) = IIf(S4.Cells(18, 2) = 2, "Some Text Here:", S4.Cells(18, 3))
End Sub