2013-09-30 33 views
4

如何滿足VBA代碼的以下條件?Excel VBA - 始終顯示打開的工作表

  1. 特定的工作表始終顯示在打開狀態,即使在未啓用宏的情況下打開了worbook。
  2. 工作簿用戶可以在任何工作表上工作時保存工作簿。
  3. 的保存必須不干擾用戶 - 沒有遠離導航到不同的片材,沒有消息框等
  4. 常規保存功能(Ctrl鍵 - 小號,點擊保存)在使用時必須保持可用和必須遵守上述標準。

我想避免我在此問題底部列出的嘗試解決方案。

詳情:
工作簿使用Office 2007在Windows 7機器上創建的。這是一個包含2個工作表,「計劃程序」和「信息」的.xlsm工作簿。工作表標籤不可見。並非所有用戶都將在打開工作簿時啓用宏。

  • 「信息」顯示,如果宏被禁用了,基本上會告訴你誰打開一個宏需要是工作簿的人:

    在打開的工作簿,用戶將只如下暴露於一種表啓用完整的工作簿功能。如果此時啓用了宏,則會啓動「調度程序」。

  • 「調度程序」是存儲和編輯數據的地方,如果啓用了宏,它將自動顯示。在未啓用宏的情況下打開工作簿時,不會顯示給用戶。

如果工作簿打開且宏被禁用,則「Info」必須首先顯示。

嘗試的解決方案(我在尋找更好的解決方案!):

  • Workbook.BeforeSave事件配售代碼。這會在激活「信息」時進行保存,以便在工作簿打開時顯示。但是,如果用戶處於「調度程序」而未完成,我無法在保存後在此事件中找到重新激活「調度程序」的方法。
  • 使用Application.OnKey重新映射按Ctrl - 小號按Ctrl - 小號按鍵。不幸的是,這留下了使用鼠標進行保存的用戶(單擊文件...保存或辦公按鈕...保存)。
  • 檢查每個操作過程中是否需要激活「調度程序」。換句話說,將代碼插入Workbook.SheetActivate.SheetChange事件中,以便在激活「信息」後進行保存後,將「調度程序」重新置於焦點。這會不斷運行VBA代碼,並將其作爲讓工作簿中的其他代碼陷入困境的好方法。
  • Worksheet("Info").Activate事件配售代碼,將焦點更改回「調度」。這導致「調度程序」而不是「信息」的結果顯示工作簿何時打開,即使禁用了宏。
+0

'如果打開工作簿和宏disabled.'如果宏被禁用,那麼爲什麼試試'嘗試Solutions' :)還是我失去了一些東西「信息」必須出現第一件事情? –

+0

好問題 - 工作簿包含宏,但是由共享驅動器上的用戶打開,該用戶可能有或可能沒有位於其可信文件路徑中的位置。因此,對於未啓用宏的情況下打開的用戶,我使用「Info」工作表來說,「打開宏!」一旦它們打開,我需要確保無論工作簿上發生了什麼變化,一旦保存,下一個打開禁用宏的工作簿的人就會看到「Info」。 –

+2

我能想到的唯一方法是以只讀模式保存文件。通過這種方式,它始終會以信息表的形式作爲第一張表單打開...只要您保存並關閉帶有活動信息表的文件即可。 Excel會記住您打開的最後一張工作表。 –

回答

4

我沒有時間來測試這一點,但你可能能夠在您的BeforeSave事件處理程序來做到這一點使用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 

然後在模塊1:

Public PreviousSheet As Worksheet 

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

我明白這段代碼的作用,但我很困惑。爲什麼.OnTime最早的時間= Now。一旦BeforeSave事件結束,實際的保存會發生嗎?如果是這樣,那麼不會。保存之前有時間發生? –

+0

@AaronThomas,準時不會發生之前的保存:VBA是單線程的,所以任何使用Application.OnTime不能運行,直到當前的代碼控制權返回給消息循環計劃 - 通過運行至完成或通過調用DoEvents 。在這種情況下,文件保存在計劃的操作可以運行之前完成。事實上,如果由於關閉工作簿而導致文件保存正在進行,則關閉也會完成,並且計劃的操作根本不會運行。就我所見,所有這些都正是你想要的。 – Joe

+0

除了一個問題以外,工作良好 - 作爲其副作用,如果用戶試圖關閉工作簿,然後單擊「是」保存他們的工作,Application.OnTime在工作簿關閉後執行。這導致工作簿重新打開並執行子「PreviousSheet」。如果用戶在關閉工作簿時試圖保存,如何終止此任何想法? –

5

這是否會無法工作? 更新處理節能優雅

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 
+0

我認爲這是一個很好的選擇,除了在情況下,用戶可能不想保存他們已經什麼完成了!這迫使無論如何都要保存這些有害的更改。不過+1的BeforeClose事件,我沒有想到這一點。 –

+0

我的答案更新,以處理有關保存有效的關注。 – nunzabar

+0

您的保存問題的更新是可行的,但開始時過於複雜,我就把你'workbookDirty'和簡單的方法檢查'如果(thisworkbook.saved)then'否則基本上你正在做'不可不Me.Saved'雙重否定,最好避免。 –

1

編輯2:這是一個重新寫了不使用AfterSave。您可能需要根據您的需要調整從GetSaveAsFilename創建的對話框。

這依賴於覆蓋默認保存行爲並處理自己保存。

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 

使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允許在保存後重新選擇「ActiveSheet」。

編輯:我注意到你在評論中有更多的要求。代碼已經更新,現在保存後,只有信息表可見,但是在打開或保存後,每個表格都會重新出現。

這使得以使任何用戶打開該文件,而無需宏將不能與活化的不同片保存,甚至查看其他片材。這肯定會有助於激勵他們啓用宏!

+0

從技術上講,有人打開沒有宏的工作簿,仍然可以添加工作表並保存選定的工作表。如果這成爲一個問題,你可以保護工作簿,但是你需要在你的代碼中包含邏輯。 –

+1

「...只要確保也使用AfterSave」 - 並確保您的所有用戶都使用Office 2010或更高版本,因爲這是在添加AfterSave事件時。 – Joe

+0

@Joe啊,這是有道理的,然後沒有人提出。 :)在這種情況下,您可以[在BeforeSave事件中處理所有內容](http://www.mrexcel.com/forum/excel-questions/428746-workbook-after-save-event.html),方法是取消保存並通過代碼處理自己。可能使用'Application.OnTime'就像你所建議的,可能會起作用,但我討厭不得不訴諸於此。 –

1

此問題已被鞭打死過去,它只是很難找到實際工作的解決方案。看看這個代碼應該做你需要的。基本上它會顯示一個啓動畫面,如果用戶不啓用宏,則隱藏所有其他工作表。如果用戶點擊保存並且不會干擾他們的工作,它仍然可以正常保存。如果他們在工作表打開的情況下保存,它將在下次打開時仍然只顯示啓動畫面。下載下面的示例文件,你可以自己測試,確保你下載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 

的樣本文件可以發現here.

+0

@Aaron,做了這個幫助,你需要更多的幫助嗎? – Reafidy

+0

不幸的是,我沒有能夠下載示例文件來檢查,儘管我可以按照您的代碼片段進行檢查。這是一個很好的答案,但我不認爲這是最好的答案。我已經設置了一旦啓用了宏,用戶將不可能切換到「信息」屏幕,因此隱藏和取消隱藏每次保存時的工作表似乎不如在每次保存前切換到「信息」在其他問題中提出。但是,這是一個很好的解決方案。 –

+0

@Aaron,如果用戶取消關閉,closing_check布爾值可以離開接收器,嘗試一下,你會發現它是一個誤報。還要小心自動保存,自動恢復。最後,我不建議使用您所選擇的計劃程序/準時。它應該妥善取消內的恕我直言,這隻會導致經驗的麻煩。希望聽起來不像酸葡萄,因爲你沒有選擇我的答案,我真的不介意。只是試圖幫助。祝一切順利。 – Reafidy

1

如何使用 '代理工作簿'。

的「代理工作簿」

  • 是直接由用戶
  • 打開的唯一工作簿包含的信息表
  • 包含VBA打開你的「真正的工作簿」使用Workbooks.Open(正如我在默認情況下Workbooks.Open文檔檢查是否需要VBA代碼甚至可以確保它不會在文件名添加到您最近的文件歷史記錄,除非你設置AddToMru參數爲true)
  • 你的「目標工作簿'是值得信賴的(我找到了一些樣本代碼here

「目標工作簿」

  • 包含您的日程和任何其他表
  • 如果在「代理服務器工作簿」 VBA代碼被執行
  • 可以保存只能打開由用戶在任何時候像往常一樣

我沒有Office 2007手頭測試這個,但認爲它應該這樣做。

+0

這也是一個解決方案,但我不認爲這是最好的,因爲它增加了另一個用戶需要訪問的工作簿。 –