【发布时间】:2014-12-18 21:51:38
【问题描述】:
我正在运行 Excel 2013,并且我最近开发的一个宏不一致(万岁!)导致 Excel 冻结,给我“Excel 已停止工作”错误。简而言之,宏会提示用户提供一些关于他们想要做什么的基本信息,然后创建许多新工作表(基于模板工作表)并用摘要选项卡中的信息行填充每个工作表(用户填写在开始宏之前)。当我运行宏时,它会在我完成提示后立即冻结。我可以立即重新启动工作簿,使用相同的输入再次运行宏,它就会工作。因此,问题难以重现,因此难以诊断和修复。
我已经尝试了很多方法来解决这个问题(更改 Shift:=xl--- 调用 xlShift---;将选项卡从分页预览更改为普通视图;将宏按钮移动到另一个工作表),但它仍然冻结。最近的尝试(似乎工作了一段时间)是将用于启动宏的表单控件按钮更改为 ActiveX 控件按钮(位于“摘要”选项卡上)。我尝试设置一个基本的错误处理程序,但是当我让它再次冻结时没有找到任何东西。我试过单步执行代码,当它冻结时,是在第一次执行 selection.insert 调用之后。
我在下面包含了完整的宏,但(潜在的)问题行是:
Sheets(yr_temp).Rows(3 + task_counter).Insert (xlShiftDown)
关于可能发生的事情以及我可以尝试解决此问题的任何其他想法?我唯一没有完全测试的是在 .Insert 行之后插入 Application.Wait Now + (TimeValue("00:00:01") ;另一个用户说这对他们有用(在moment UPDATE #4:找到了!这是link。),虽然情况略有不同。此外,该行可以在宏的一次执行中运行数百次,所以请等待每次一秒钟是相当繁重的(我没有尝试过使用几分之一秒,我也不确定多短的等待仍然会产生预期的效果)。
更新 #1:我忘记了这个花絮。当它冻结时,它似乎总是在我打开工作簿后第一次运行宏时。我不相信它曾经在第二次或第三次或...运行宏时冻结。
更新 #2:在为 yr_temp 和 task_counter 添加 debug.print 调用(感谢 Alex Bell 的建议)并多次运行宏后,我终于让它冻结了我当我观看即时窗口时。同样,在第一次调用奇怪的麻烦的 sheet.insert 行之后,它似乎已经崩溃了。更重要的是,yr_temp 和 task_counter 的值与之前每次顺利运行的尝试中的有效数字相同。那么,任何其他想法可能导致这个问题?这个周末我将尝试在另一台计算机上运行它,看看它是否可能与这个系统有关,而不是宏本身。
更新 #3:我尝试在我的另一台计算机上使用工作簿(运行 Office 2010)。到目前为止,我还没有让它冻结,但我现在断言它不会在那个系统上冻结还为时过早。
Sub Generate_MM_Sheets()
'' Turn off screen updating for duration of macro (to improve macro speed...and prevent seizures)
Application.ScreenUpdating = False
'' Declare all variables
Dim valid_resp As Boolean, user_resp As String '' For user prompts
Dim yr_start As Integer, yr_num As Integer, yr_counter As Integer, yr_temp As String '' For year values
Dim task_num As Integer, task_counter As Integer, task_temp As Integer '' For task numbers
Dim sheets_num As Integer, sheet_counter As Integer '' For sheet numbers
Dim proj_name As String '' For project name
Dim wb_current As String, wb_new As String '' For workbook names
'' Prompt user to define starting year for the Maintenance Manual sheets
valid_resp = False
Do
user_resp = InputBox("Enter the desired starting year for the Maintenance Manual sheets", , Year(Now()))
If user_resp = "" Then '' If the user hits Cancel or returns an empty response, restore screen updating and end the macro
Application.ScreenUpdating = True
Exit Sub
ElseIf Not IsNumeric(user_resp) Then '' If the response is not a number, warn the user and retry
MsgBox ("Doh! Invalid entry. The value you entered was not a number.")
ElseIf Not user_resp = Int(user_resp) Or user_resp <= 0 Then '' If the response is not a positive integer, warn the user and retry
MsgBox ("Aw snap! Invalid entry. The value you entered was not a positive integer.")
Else '' Otherwise the response is deemed valid. Set the response validity to true and define the macro variable as the user response
valid_resp = True
yr_start = user_resp
End If
Loop Until valid_resp = True '' Loop until a valid response is entered
'' Same logic as above, but this time to define the number of years for the Maintenance Manual sheets
valid_resp = False
Do
user_resp = InputBox("Enter the desired total number of years for the Maintenance Manual sheets", , 30)
If user_resp = "" Then
Application.ScreenUpdating = True
Exit Sub
ElseIf Not IsNumeric(user_resp) Then
MsgBox ("Come on! Invalid entry. The value you entered was not a number.")
ElseIf Not user_resp = Int(user_resp) Or user_resp <= 0 Then
MsgBox ("Bummer, dude! Invalid entry. The value you entered was not a positive integer.")
Else
valid_resp = True
yr_num = user_resp
End If
Loop Until valid_resp = True
'' Prompt user to define project name for use in the Maintenance Manual sheet headers
proj_name = InputBox("Enter the name of the project for the Maintenance Manual sheets")
'' Use the above responses, the data in the Summary tab and the template in the Template tab to create and populate the Maintenance Manual sheets
task_num = Range(Sheets("Summary").Range("A4"), Sheets("Summary").Range("A4").End(xlDown)).Rows.Count '' Count the number of Tasks in the Summary tab
sheets_num = ActiveWorkbook.Sheets.Count '' Count the current number of sheets in the macro workbook (this value is used when moving the generated sheets to new workbook)
Sheets("Template").PageSetup.CenterHeader = proj_name & Chr(10) & "Maintenance Items" '' Update the header of the Template tab to be used on the generated sheets
For yr_counter = 1 To yr_num '' Loop through each year
yr_temp = yr_start + yr_counter - 1 '' Determine the year value for this loop
Sheets("Template").Copy After:=Sheets(Sheets.Count) '' Copy the Template tab to the end of the workbook
Sheets("Template (2)").Name = yr_temp '' Rename the new tab based on the year value for this loop
Sheets(yr_temp).Range("A1").Value = Sheets(yr_temp).Range("A1").Value & yr_temp '' Revise the new tab's description based on the year value for this loop
task_counter = 0
For task_temp = 1 To task_num '' Loop through each task
task_rem = (yr_counter + Sheets("Summary").Range("E4").Offset(task_temp - 1, 0).Value) Mod _
Sheets("Summary").Range("D4").Offset(task_temp - 1, 0).Value '' Check if the task is due this year (i.e., the year count (plus task age) is a factor of the task frequency)
If task_rem = 0 Then '' Then, for each task that is due this year...
task_counter = task_counter + 1 '' Increment the counter for the number of tasks that have been identified as due this year
Sheets("Summary").Rows(3 + task_temp).Copy '' Copy the task from the Summary sheet and insert it at the bottom of the new tab
Sheets(yr_temp).Rows(3 + task_counter).Insert (xlShiftDown)
End If
Next task_temp
Sheets(yr_temp).Columns("D:E").Delete (xlShiftToLeft) '' Delete the frequency and current age columns from the new tab
Sheets(yr_temp).Rows(4 + task_counter).Delete (xlShiftUp) '' Delete the blank placeholder row (used to preserve formatting and print area) from the new tab
Next yr_counter
'' Move all of the newly generated Maintenance Manual sheets to a new workbook
wb_current = ActiveWorkbook.Name '' Note: This is used in the following code block, but needs to be performed here for simplicity
Sheets(sheets_num + 1).Select '' Select the first annual sheet
For sheet_counter = 2 To yr_num '' Add each of the remaining annual sheets to the selection
Sheets(sheets_num + sheet_counter).Select False
Next sheet_counter
ActiveWindow.SelectedSheets.Move '' Move the selected sheets (hopefully all of the newly generated annual sheets) to a new workbook
'' Restore the macro workbook tabs to their original state (for aesthetic/convenience reasons) and then focus back to the newly created workbook
wb_new = ActiveWorkbook.Name
Workbooks(wb_current).Sheets("Instructions").Activate
Workbooks(wb_current).Sheets("Summary").Activate
Workbooks(wb_current).Sheets("Template").PageSetup.CenterHeader = Chr(10) & "Maintenance Items" '' Remove project name from Template tab header
Workbooks(wb_new).Activate
'' Restore screen updating
Application.ScreenUpdating = True
End Sub
【问题讨论】:
-
代码的哪个特定部分导致了问题?
-
当我单步执行代码时,我让它冻结了两次。两次它都冻结了,这是它第一次尝试执行以下插入行时:Sheets(yr_temp).Rows(3 + task_counter).Insert (xlShiftDown)
-
然后你必须检查各个变量的状态:task_temp、yr_temp、task_counter。为此目的使用 Debug.Print 或添加 Watches。