我在Excel中使用VBA计算大量数据,并希望在完成后显示MsgBox。 MsgBox实际上显示了计算所花费的时间。
问题是用户在计算发生时决定做其他事情。 Excel继续计算,当它完成时,MsgBox确实显示但由于某种原因,Excel没有将焦点放在MsgBox上。 Excel图标将在任务栏中闪烁,如果我们单击它,Excel会最大化,但MsgBox在Excel窗口后面,我们永远不能单击它。所以摆脱它的唯一方法是taskkill excel.exe ...不是很好。 Alt + Pause不起作用,因为代码只会在当前代码行之后停止,而代码将在MsgBox关闭时停止。
我之前尝试过AppActivate("Microsoft Excel")
函数但没有成功(How do I bring focus to a msgbox?)。应用程序名称实际上比Excel 2010更长,因为Excel 2010将文档名称添加到窗口标题。
知道如何解决这个恼人的问题吗?
答案 0 :(得分:3)
听起来像宏程序正在使应用程序无响应。不确定这是否会有所帮助,但您是否考虑在长时间运行的过程中添加DoEvents或Sleep(API调用)以将控制权交还给操作系统? Sleep是一个API调用,因此您需要在模块中声明它才能使用它。 DoEvents会阻止应用程序锁定,但它会使用更多的CPU,因此如果它处于循环I中 会偶尔访问它(迭代次数的30%或更少)。如果它不是循环并且您知道长时间运行过程中的瓶颈在哪里,则可以在每个长时间运行的过程之后调用DoEvents。
#If VBA7 And Win64 Then
' 64 bit Excel
Public Declare PtrSafe Sub Sleep Lib "kernel32" ( _
ByVal dwMilliseconds As LongLong)
#Else
' 32 bit Excel
Public Declare Sub Sleep Lib "kernel32" ( _
ByVal dwMilliseconds As Long)
#End If
然后在你的过程中
Sub SomeLongProcessWithDoEventsExample()
For i = 1 to 100000
'Some lengthy code
If i Mod 333 = 0 Then
DoEvents
End If
Next i
End Sub
Sub SomeLongProcessWithSleepExample()
For i = 1 to 100000
'Some lengthy code
If i Mod 333 = 0 Then
Sleep 1 * 1000 'Millseconds
End If
Next i
End Sub
我建议设置Application.ScreenUpdating = False,然后在流程完成后重新打开它,但这可能会让事情变得更糟。
<强>更新强>
只需阅读输入答案时输入的评论。另一个选项而不是messsage框将打开文件夹窗口,毕竟文件正在保存 文件已创建(用保存位置替换Environ $(&#34; APPDATA&#34;)):
Shell "explorer.exe" & " " & Environ$("APPDATA"), vbMaximizedFocus
或打开其中一个PDF:
Shell Environ$("COMSPEC") & " /c Start C:\SomeFile.pdf", vbMaximizedFocus
另一个选项
我无法将其放在评论中,因为代码太多了,但是对MessageBox进行API调用,但是不要设置消息框的所有者(hWnd)将其设置为&amp; ; H0或&amp; O0。 vbSystemModal应该让它弹出到顶部。我不知道在用户点击正常后是否允许您选择Excel应用程序窗口:
MessageBox &O0, "My Message", "My Caption", vbOKOnly + vbSystemModal
#If VBA7 And Win64 Then
Public Declare PtrSafe Function MessageBox _
Lib "User32" Alias "MessageBoxA" _
(ByVal hWnd As LongLong, _
ByVal lpText As String, _
ByVal lpCaption As String, _
ByVal wType As LongLong) _
As Long
#Else
Public Declare Function MessageBox _
Lib "User32" Alias "MessageBoxA" _
(ByVal hWnd As Long, _
ByVal lpText As String, _
ByVal lpCaption As String, _
ByVal wType As Long) _
As Long
#End If
答案 1 :(得分:3)
我做了一些测试,发现了一个潜在的工作。
我设置了这个简单的程序来测试你的情况:
Sub test()
If Application.Wait(Now + TimeValue("0:00:10")) Then
MsgBox "Time expired"
End If
End Sub
我运行它,然后最小化所有窗口,当计时器启动时,没有任何反应。如果我切换到Excel,我可以看到消息框,但没有别的。
所以我尝试了这个:
Sub test()
If Application.Wait(Now + TimeValue("0:00:10")) Then
ThisWorkbook.Activate
MsgBox "Time expired"
End If
End Sub
这次我运行程序,然后最小化所有窗口,而不是看不到任何消息框弹出(但不是Excel窗口)。
我认为通过在ThisWorkbook.Activate
代码之前添加MsgBox
,您可以在文件中发生同样的事情。
它并不能让你一路走来,但希望比你所处的更好。
答案 2 :(得分:3)
* oops没有阅读你的其余问题,我使用AppActivate并按预期工作,我正在使用MS Office Professional Plus 2010
我无法从guitarthrower获得工作方法,但能够将其作为一个例子。而不是ThisWorkbook.Activate
尝试AppActivate ("Microsoft excel")
,而是MsgBox
Sub test()
If Application.Wait(Now + TimeValue("0:00:10")) Then
AppActivate ("Microsoft excel")
MsgBox "Time expired"
End If
End Sub
答案 3 :(得分:2)
我尝试了大部分其他答案:
ThisWorkbook.Activate
AppActivate()
Application.Wait()
Sleep
图书馆无论出于何种原因,以上都不起作用。我相信在我们的计算机环境中有一些非常具体的业务设置可能会造成问题。正如其他人所提到的,即使在双显示器设置中,所有上述解决方案都应该适用于安装了任何Office 2010版本的任何全新格式化Windows 7安装。所以这些答案都是+1。此外,我注意到问题仅发生在某些特定的工作簿中。真的很奇怪的行为,可能只是一个Office 2010错误,与我在工作簿中做的事情有关(无论是VBA还是简单的Excel)。
话虽如此,我真正的解决方案(并非真正解决初始问题)并未使用MsgBox()
。确实存在几种解决方法,我发现表单对我来说是最好的。因此,我没有在这个问题上浪费更多时间,而是使用非常简单的以下代码来替换原来的MsgBox()
:
Application.ScreenUpdating = False
frmMsgBox.Show
Application.ScreenUpdating = True
我可以在frmMsgBox
的标签中放置我想要的任何文字,因为这是Excel,我只需使用隐藏的单元格传递参数。
感谢您的帮助。
答案 4 :(得分:2)
无论其他应用程序有何重点,这都适用于Excel:
在消息框或任何警告之前输入以下代码:
AppActivate Application.Caption DoEvents
相信我,这太棒了!