【问题标题】:Why UserForm is "Not Responding" During Run Time in VBA Excel?为什么用户窗体在 VBA Excel 中运行时“没有响应”?
【发布时间】:2012-11-16 09:32:08
【问题描述】:

我是 VBA Excel 的新手,我只知道我需要的东西来完成这个报告格式化任务。

我几乎完成了我的任务,但是当我运行程序并启动进度时,即使它成功运行,GUI 也有一分钟没有响应。我在这里分享我的代码,有什么问题吗?你能建议我任何最佳做法吗?我不希望它冻结,因为我的经理会觉得它很糟糕。

为了清楚起见,“无响应”是指它在屏幕上冻结并在其窗口框架上显示“无响应”,当我单击它时,它会给出如下消息:

*ps:我获得记录的工作表有 20997 行和 7 列,我在相同文件大小和 20997 行 23 列的另一个工作表上做了一些记录。而且我的 GUI 非常简单,它只有一个用于启动进度的命令按钮。

我该如何解决这个问题?

【问题讨论】:

  • 好吧,代码本身可能会正常工作,尽管样式不太理想。你说“用户窗体”:你是从模态窗体运行它吗?如果是这样,您需要隐藏表单才能正确返回工作簿。该表格不会让您做任何事情,除了回应它。也许在你的代码末尾你需要 Formname.Hide ?
  • @VinnyRoe:您好,感谢您的回复。对不起,我不明白您所说的“模态形式”是什么意思。基本上我所做的是,在打开 excel 文件后,我按下了 ALT+F11,而不是从文件菜单中,我选择了 Insert > User Form。但我认为隐藏表单并不能解决我的问题,因为我将来可能有更大的文件,这可能会导致更多问题

标签: vba excel userform


【解决方案1】:

你可以通过放置防止excel窗口冻结

DoEvents

在你的循环中。

【讨论】:

  • 请点赞,这是 VBA 表单中大多数冻结问题的实际解决方案
  • 这是最好的解决方案,您实际上需要允许应用程序处理常规事件(如单击、窗口拖动、重绘屏幕等),因此由于您的代码正在密集工作并且不会休息或不时放弃控制,那么应用程序几乎没有 CPU 时间来处理这些事件,所以我的最佳做法是找到所有的“Next”和“Loop”语句并在它们之前写下“DoEvents”一行,这样我可以保证每个循环周期都允许应用程序处理事件,如果它有一些
【解决方案2】:

发生这种情况是因为您的程序工作非常繁忙。例如,您的 Sub TheLoop() 正在访问 20995 x 16 次单元格以在其上写入字符串。 VBA 与 Excel 的交互很慢。

您可以采取一些措施来加快该过程。

1.在运行程序之前禁用事件处理程序、屏幕更新和计算。在程序结束时再次恢复设置。

   'Disable'
   Application.EnableEvents = False
   Application.ScreenUpdating = False
   Application.Calculation = xlCalculationManual

   '......  Code'

   'Enable'
   Application.EnableEvents = True
   Application.ScreenUpdating = True
   Application.Calculation = xlCalculationAutomatic

2.您可以优化Sub TheLoop。不要立即在单元格上写入,而是将值写入数组中。数组充满值后,将数组的值分配给您需要的范围。 例如:

Dim ResultValues() As String
Dim j As Long

ReDim ResultValues(2 To 20997, 1 To 3)

For j = 2 To 20997
    ResultValues(j, 1) = "New Defect"
    ResultValues(j, 2) = "3"
    ResultValues(j, 3) = "2"
Next j

With ThisWorkbook.Worksheets("myWorksheet")
    .Range(.Cells(2, 3), .Cells(20997, 5)) = ResultValues
End With

编辑:

鉴于您修改的列之间的列只是文本或空单元格,您可以:

  1. 将整个范围读入一个数组。
  2. 然后以与当前修改单元格相同的方式修改数组。
  3. 修改完成后,再次将整个矩阵转储到范围内。'

例如:

Sub TheLoop()
Dim arrRangeValues() as Variant
Dim j as Long

arrRangeValues= Range("A2:V20997").Value2

For j = 2 To 20997
    arrRangeValues(j, 1) = "Defect" 'Cells(row_index , column_index)'
    arrRangeValues(j, 3) = "New Defect"
    arrRangeValues(j, 4) = "3" ' this one also might be empty'
    arrRangeValues(j, 5) = "2" ' this one also might be empty'

    arrRangeValues(j, 7) = "Name Surname"
    arrRangeValues(j, 8) = arrRangeValues(j, 7)
    arrRangeValues(j, 16) = arrRangeValues(j, 7)
    ...
    arrRangeValues(j, 10) = " http://SERVER_NAME:8888/PROJECT_NAME/ "
Next j

Range("A2:V20997").Value2 = arrRangeValues
End Sub

【讨论】:

  • 您好,感谢您的回复。 :) 当我应用你的第一个建议时,我看起来有点快,但我认为这还不够,因为我的表格仍然冻结然后我决定尝试你的第二个建议,但即使我不知道 Dim 和 ReDim 在 VBA 中,似乎有必要在此处将我的列并排写入 ** ReDim ResultValues(2 To 20997, 1 To 3) ** 但还有一些其他列仅包含标题,其中大部分列位于我在 TheLoop 子例程中记录的列之间。
  • 我想应用您的解决方案,但我不想编写额外的代码来将列移动到其他列之间。您还有其他方法可以建议我吗? :)
  • 第 2,6,11,17,19,21 列的单元格是否只包含文本或空格?
  • 这些列中的 3 列是从 CostComplexity() 子例程中的另一个工作表导入的,其余为空白,除了列标题
【解决方案3】:

好的,我相信我找到了最好的解决方案。 (a) :)

我没有在 TheLoop 子例程中使用 for 循环,而是删除了循环并进行了如下更改。即使我没有禁用事件属性,当我将它与我的第一个代码进行比较时,它也会变得非常快,而且现在它没有冻结。

Sub TheLoop()

    Cells(2, 1).Resize(20996) = "Defect"
    Cells(2, 3).Resize(20996) = "New Defect"
    Cells(2, 4).Resize(20996) = "3"
    Cells(2, 5).Resize(20996) = "2"
    Cells(2, 7).Resize(20996) = "Name Surname"
    Cells(2, 8).Resize(20996) = "Name Surname"
    Cells(2, 9).Resize(20996) = "FALSE"


    Cells(2, 10).Resize(20996) = " http://SERVER_NAME:8888/PROJECT_NAME/ "


    Cells(2, 12).Resize(20996) = "Software Quality"
    Cells(2, 13).Resize(20996) = "Unsigned"
    Cells(2, 14).Resize(20996) = "Software Quality"
    Cells(2, 15).Resize(20996) = "1"
    Cells(2, 16).Resize(20996) = "Name Surname"
    Cells(2, 18).Resize(20996) = "Software Quality"
    Cells(2, 20).Resize(20996) = "Development"
    Cells(2, 22).Resize(20996) = " TYPE YOUR MODULE'S NAME TO HERE"

End Sub

【讨论】:

  • 这是一个非常具体的代码解决方案,实际上是绕过而不是解决此类问题的正确解决方案,正确的解决方案是:在循环中的“下一步”语句之前编写 DoEvents
  • @Shaybc 自从我上次处理 vba 以来已经有很长时间了。 DoEvent 可以防止冻结,但您的方法更快吗?有了这个解决方案,我可以立即做到。如果我没记错的话,循环需要很多时间来处理大量的 excel 文件
【解决方案4】:

我尝试过使用 Application.ScreenUpdating、Application.EnableEvents、Application.Calculation、DoEvents 和 Application.Wait (Now + TimeValue("0:00:10")),不幸的是,最后的选项无法解决这个问题问题,查看 Microsoft 网页,如果程序说我 “无响应” 是

,请说我
  1. 出于安全原因和
  2. 因为太重或太复杂
  3. 因为程序不会向用户发送任何即将执行的反馈。

在我的例子中,我尝试向用户展示和 MsgBox,最终为 Win10 操作系统和客户提供反馈,但是太无聊,用户点击是,是,是,是的,好的,好的,好的,好的,在其他论坛上查看有关 MsgBox 的 VBA(自动关闭),他们建议我使用代码 CreateObject("WScript.Shell").PopUp "Please Wait", 1 和 tada !我将停止看到“未响应消息”,如果用户不按任何单击或按钮来禁用消息,请不要担心程序将在消息关闭后 1 秒后执行,在我的情况下,这解决了我的问题很多,希望能帮到你,祝你好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    相关资源
    最近更新 更多