Excel VBA – 总是显示打开的工作表

VBA代码如何满足以下条件?

  1. 一个特定的工作表总是显示在打开状态,即使在没有启用macros的情况下打开了worbook。
  2. 工作簿用户可能在工作表上工作时保存工作簿。
  3. 保存不得干扰用户 – 不得导航到不同的表单,不得留言框等。
  4. 常规的保存function( CtrlS ,点击保存)必须保持可用,使用时必须遵守上述条件。

我想避免在这个问题的底部列出的尝试解决scheme。

细节:
工作簿是在Windows 7计算机上使用Office 2007创build的。 这是一个.xlsm工作簿,带有2个工作表,“调度程序”和“信息”。 工作表标签不可见。 并非所有用户都将打开工作簿时启用macros。

打开工作簿后,用户将只能看到一张表,如下所示:

  • 如果macros被禁用,“信息”将显示出来,基本上告诉打开工作簿的人需要为完整的工作簿function启用macros。 如果此时启用了macros,“调度程序”将被激活。
  • “调度程序”是存储和编辑数据的地方,如果启用了macros,它将自动显示。 在不启用macros的情况下打开工作簿时,不会显示给用户。

如果工作簿打开并且macros被禁用,“信息”必须首先显示。

尝试解决scheme (我正在寻找更好的解决scheme!):

  • 将代码放在Workbook.BeforeSave事件中。 这会激活“信息”,从而在工作簿打开时显示。 但是,如果用户在“日程安排”而没有完成,我不能在这个事件中find一个方法来重新激活保存后的“日程安排”。
  • 使用Application.OnKey重新映射CtrlsCtrlS按键。 不幸的是,这留下了使用鼠标保存的用户(单击文件…保存或办公室button…保存)。
  • 检查每个动作,如果需要激活“调度程序”。 换句话说,将代码插入到Workbook.SheetActivate.SheetChange事件中,在“Info”激活保存后,将“Scheduler”放回到焦点。 这不断运行VBA代码,并将其作为让工作簿中的其他代码陷入麻烦的好方法。
  • Worksheet("Info").Activate放置代码Worksheet("Info").Activate事件 ,将焦点改回“调度程序”。 这导致了“调度程序”而不是“信息”的结果,即使在禁用macros的情况下也显示工作簿何时打开。

我没有时间来testing这个,但是你可以在你的BeforeSave事件处理Application.OnTime中使用Application.OnTime来做到这一点。 就像是:

 Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Dim objActiveSheet Set objActiveSheet = Me.ActiveSheet If objActiveSheet Is InfoSheet Then Exit Sub If Module1.PreviousSheet Is Nothing Then Set Module1.PreviousSheet = objActiveSheet InfoSheet.Activate Application.OnTime Now, "ActivatePreviousSheet" End If End Sub 

然后在Module1中:

 Public PreviousSheet As Worksheet Public Sub ActivatePreviousSheet() If Not PreviousSheet Is Nothing Then PreviousSheet.Activate Set PreviousSheet = Nothing End If End Sub 

这不行吗? 更新后处理优雅

 Private Sub Workbook_Open() ThisWorkbook.Worksheets("Scheduler").Activate End Sub Private Sub Workbook_BeforeClose(Cancel As Boolean) ThisWorkbook.Worksheets("Info").Activate If (ShouldSaveBeforeClose()) Then Me.Save Else Me.Saved = True ' Prevents Excel Save prompt. End If End Sub Private Function ShouldSaveBeforeClose() As Boolean Dim workbookDirty As Boolean workbookDirty = (Not Me.Saved) If (Not workbookDirty) Then ShouldSaveBeforeClose= False Exit Function End If Dim response As Integer response = MsgBox("Save changes to WorkBook?", vbYesNo, "Attention") ShouldSaveBeforeClose= (response = VbMsgBoxResult.vbYes) End Function 

编辑2:这是一个不使用AfterSave的重写。 您可能需要根据您的需要调整从GetSaveAsFilename创build的对话框。

这依赖于覆盖默认的保存行为和处理自己保存。

 Private actSheet As Worksheet Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Cancel = True PrepareForSave manualSave SaveAsUI AfterSave ThisWorkbook.Saved End Sub Private Sub PrepareForSave() Set actSheet = ThisWorkbook.ActiveSheet ThisWorkbook.Sheets("Info").Activate hidesheets End Sub Private Sub manualSave(ByVal SaveAsUI As Boolean) On Error GoTo SaveError 'To catch failed save as Application.EnableEvents = False If SaveAsUI Then If Val(Application.Version) >= 12 Then sPathname = Application.GetSaveAsFilename(FileFilter:="Excel Files (*.xlsm), *.xlsm") If sPathname = False Then 'User hit Cancel GoTo CleanUp End If ThisWorkbook.SaveAs Filename:=sPathname, FileFormat:=52 Else sPathname = Application.GetSaveAsFilename(FileFilter:="Excel Files (*.xls), *.xls") If sPathname = False Then GoTo CleanUp End If ThisWorkbook.SaveAs Filename:=sPathname, FileFormat:=xlNormal End If Else ThisWorkbook.Save End If SaveError: If Err.Number = 1004 Then 'Cannot access save location 'User clicked no to overwrite 'Or hit cancel End If CleanUp: Application.EnableEvents = True End Sub Private Sub AfterSave(ByVal bSaved As Boolean) showsheets If actSheet Is Nothing Then ThisWorkbook.Sheets("Scheduler").Activate Else actSheet.Activate Set actSheet = Nothing End If If bSaved Then ThisWorkbook.Saved = True End If End Sub Private Sub hidesheets() For Each ws In ThisWorkbook.Worksheets If ws.Name <> "Info" Then ws.Visible = xlVeryHidden End If Next End Sub Private Sub showsheets() For Each ws In ThisWorkbook.Worksheets ws.Visible = True Next End Sub Private Sub Workbook_Open() AfterSave True End Sub 

如果没有启用macros,首先使Info显示的唯一方法是如果这是如何保存工作簿。 这是保存时最合理的处理方式。

除非我误解了你的问题,否则不要使用BeforeSave看起来是错误的。 只要确保使用AfterSave以及。 这是一个例子:

 Private actSheet As Worksheet Private Sub Workbook_AfterSave(ByVal Success As Boolean) showsheets actSheet.Activate Set actSheet = Nothing Thisworkbook.Saved = true 'To prevent save prompt from appearing End Sub Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Set actSheet = ThisWorkbook.activeSheet ThisWorkbook.Sheets("Info").Activate hidesheets End Sub Private Sub Workbook_Open() showsheets ThisWorkbook.Sheets("Scheduler").Activate End Sub Private Sub hidesheets() For Each ws In ThisWorkbook.Worksheets If ws.Name <> "Info" Then ws.Visible = xlVeryHidden End If Next End Sub Private Sub showsheets() For Each ws In ThisWorkbook.Worksheets ws.Visible = True Next End Sub 

使用私人对象actSheet允许保存后重新select“ActiveSheet”。

编辑:我注意到你在评论中有更多的要求。 代码已经更新,现在保存后,只有信息表可见,但是当打开或保存后,每个表将重新出现。

这使得任何用户在没有macros的情况下打开文件将无法保存激活的不同页面,甚至不能查看其他页面。 这肯定会有助于激励他们启用macros!

这个问题在过去一直被鞭打,只是很难find一个真正有效的解决scheme。 看看这个代码应该做你所需要的。 基本上它显示一个启animation面,如果用户不启用macros,所有其他表单将隐藏。 如果用户点击保存,它将仍然正常保存,不会干扰他们的工作。 如果他们保存工作表打开它将仍然只显示下次打开时的启animation面。 下载下面的示例文件,你可以自己testing,确保你下载由Reafidy张贴的文件有超过400个视图。 如果你需要修改进一步让我知道。

 Private Sub Workbook_BeforeClose(Cancel As Boolean) bIsClosing = True End Sub Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Dim wsArray() As Variant Dim iCnt As Integer Application.ScreenUpdating = 0 Splash.Visible = True For Each wsSht In ThisWorkbook.Worksheets If Not wsSht.CodeName = "Splash" Then If wsSht.Visible = True Then iCnt = iCnt + 1: Redim Preserve wsArray(1 To iCnt) wsArray(iCnt) = wsSht.Name End If wsSht.Visible = xlSheetVeryHidden End If Next Application.EnableEvents = 0 ThisWorkbook.Save Application.EnableEvents = 1 If Not bIsClosing Then For iCnt = 1 To UBound(wsArray) Worksheets(wsArray(iCnt)).Visible = True Next iCnt Splash.Visible = False Cancel = True End If Application.ScreenUpdating = 1 End Sub Private Sub Workbook_Open() Dim wsSht As Worksheet For Each wsSht In ThisWorkbook.Worksheets wsSht.Visible = xlSheetVisible Next wsSht Splash.Visible = xlSheetVeryHidden bIsClosing = False End Sub 

一个示例文件可以在这里find。

如何使用“代理工作簿”。

“代理工作簿”

  • 是用户直接打开的唯一工作簿
  • 包含信息表
  • 包含VBA使用Workbooks.Open打开您的“真正的工作簿”(正如我已经检查了Workbooks.Open文档默认情况下,它不会将文件名添加到您最近的文件历史logging,除非您将AddToMru参数设置为true)
  • 如果需要,VBA代码甚至可以确保你的“目标工作簿”是可信的(我在这里find了一些示例代码)

“目标工作簿”

  • 包含您的时间表和任何其他表
  • 仅在“代理工作簿”中的VBA代码执行时才会打开
  • 可以像往常一样随时由用户保存

我手边没有Office 2007来testing,但认为它应该做的。