【问题标题】:How to tell if Sub is called from immediate window如何判断是否从即时窗口调用 Sub
【发布时间】:2017-05-22 08:49:51
【问题描述】:

我只想从即时窗口运行一些潜艇,比如这个有点冒险的潜艇:

Public Sub clear()

Application.SendKeys "^a", True
Application.SendKeys "{delete}", True

End Sub

万一你无法解决;它将 ctrl+aDel 发送到应用程序,并具有清除当时光标周围的任何内容的效果。

我通过输入clear 在即时窗口中使用它,即时窗口中的所有内容都会被删除。

正如您可能知道的那样,这个 Sub 非常危险并且相对容易意外调用。因此,我希望它在从即时窗口调用时运行 only

  • 不是来自另一个子
  • 不是来自表单控件
  • 不是来自 ActiveX(虽然它实际上只是一个子)
  • 不是来自用户调用(通过开发人员/宏选项卡)

也不是来自任何其他来源(我已经列出了所有这些,因为我认为即使您不能直接判断它是由即时窗口调用的,您也可以通过排除其他来源来间接判断选项)

这可能以编程方式进行吗?理想情况下,我只想在我的 clear() 子程序的开头进行一个简单的布尔检查,告诉它什么都不做,除非被即时窗口调用。


注意

一种方法可能是通过使用 调用堆栈ctrl+L 打开对话框),我立即注意到调用不会在堆栈中留下任何痕迹,而调用clear() 的子程序会被列出,因此可以排除。但我不确定如何通过 VBA 访问它

【问题讨论】:

  • 您说“这个 Sub 非常危险,并且相对容易意外调用。”所以我将函数重命名为例如cleardebug 所以它不同于 listbox.clear() 之类的任何东西,并且不会再意外调用它。不应该有人不小心调用了一个名为cleardebug 的函数,无法想象这种情况会意外发生。
  • @Peh 我同意它可能对 vba 调用有所帮助,但我不完全相信有两个原因;首先,我能想到的意外调用的主要形式只是在运行宏窗口中单击了错误的宏——更改名称并不能解决这个问题。其次,键入cleardebug 感觉比手动执行 ctrl+a+del 更费力(显然您可以选择一个不同的名称,但要找到足够明显的东西以令人难忘但又足够模糊以至于在 VBA 中没有其他含义,并且足够简洁打字很难)!
  • 好吧,让我说一下,网络上有大约 1000 个关于如何清除即时窗口的讨论、操作方法和教程,以及针对该问题的大约 10 种不同的解决方案。如果有一个解决方案,比如将即时窗口检测为函数调用者(或者像你建议的相反),我想有人已经找到了。我认为除了讨论已经指出的这些之外,没有更好的解决方案。
  • @Peh 有效点,但是一个新的问题措辞可能会吸引一些不同的想法,我发现在我所做的研究中没有提到这种方法(几乎可以肯定是因为这是一种徒劳的方法,但可能是因为它没有被考虑)
  • 我一直使用 MZ 工具上提供的按钮来清除即时窗口 - 不幸的是不再免费了。 mztools.com

标签: vba excel immediate-window


【解决方案1】:

一个简单的解决方案是添加一个参数

Public Sub clear(sCaller As String)

If sCaller = "Immediate" Then
    Application.SendKeys "^a", True
    Application.SendKeys "{delete}", True
End If

End Sub

这也可能不是您想要的,但显然可以将风险降到最低

【讨论】:

  • 实际上它甚至可以是一个可选参数,因为用户/按钮点击不能传递字符串,并且很难不小心输入一个子。所以拥有它Optional 只会避免错误消息,但不会降低安全性
  • 或者您将原始代码更改为 Application.SendKeys "^g ^a {DEL}"
【解决方案2】:

我知道这不是你问题的答案,但如果你想“清除”你的即时窗口,这就是我使用的:

Sub clear()
For i = 0 To 100
    Debug.Print ""
Next i
End Sub

【讨论】:

  • 我在其他地方看到过这个,在 clear the immediate window 的大辩论中,我不喜欢它如何将光标留在窗口底部。另外,正如您所说,它回答了我的具体情况,但没有回答实际问题(尽管解决方法是 SO 精神!)。
【解决方案3】:

我找到了一种结合了一些想法的方法:

Public Sub clear(Optional s As Variant)

If TypeName(Application.Caller) = "Error" And IsMissing(s) = False Then
'Do code
End If

End Sub

发生的情况是,如果从范围(仅限函数)或按钮调用 sub,那么这将被 TypeName 测试捕获,因为它们将分别返回 RangeString。错误选项是立即窗口、Sub 或用户调用。额外的参数不能由用户给出,因此被排除在外。最后,我们希望子调用不包含参数。

sVariant,这样您就可以在即时窗口中输入clear whatever,而不必在" 中输入watever(以表示文本)。

显然可以通过适当的参数变得更安全。显然,这并不理想,因为 hope 这个词本来就是要显示的!当然,它也不能真正回答问题。

【讨论】:

  • 小点:您的参数是可选的,因此在调用例程时,无论是由用户(可能但不太可能)还是由另一个子程序,都不必完全提供.
  • @Rory,但我检查它是否IsMissing 使得子程序中的代码必须运行,而不是子程序作为一个整体运行(以避免在意外调用时出错)
  • 对不起 - 我忽略了那部分。从技术上讲,额外的参数可以由用户给出,它不会意外发生! ;)
猜你喜欢
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多