7

我对 VBA Excel 很陌生,我只知道这个报告格式化任务需要的东西。

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

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

在此处输入图像描述

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

我怎样才能解决这个问题?

4

4 回答 4

20

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

DoEvents

在你的循环里面。

于 2013-03-15T12:26:28.640 回答
4

发生这种情况是因为您的程序工作非常繁忙。例如,您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
于 2012-11-28T15:24:20.883 回答
0

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

我没有在 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
于 2012-11-29T13:52:14.577 回答
0

我尝试过使用 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 秒后执行,在我的情况下,这解决了我的问题很多,希望能帮到你,祝你好运。

于 2021-05-17T23:39:52.747 回答