我对 VBA 很陌生,会尽力解释我的问题。我有一个工作簿,可以将任务列表与 Outlook 任务双向同步,并且工作得很好。我还有一个宏,可以在每次“状态”列(D 列)更改时创建一个静态时间戳。问题是,每次我打开工作表并与 Outlook 同步时,它都会刷新 D 列(以及工作表的其余部分),并且即使状态文本保持不变,时间戳也会更新。下面是我用来创建时间戳的宏:有没有办法修改,所以只有当单元格(D 列)中的实际文本发生变化(即“进行中”变为“等待”)时,它才会时间戳,并且不只是在工作簿同步和刷新所有数据时?
太感谢了!!!修改后的代码--这是从“Microsoft Excel 对象”文件夹中的“ThisWorkbook”与 Outlook 同步的代码。
'--> Declare some constants
'Edit the constants below as needed so they correctly reflect the column number they appear in in the spreadsheet'
Const EXC_CLIENT = 1
Const EXC_SUBJECT = 2
Const EXC_START = 5
Const EXC_STATUS = 4
Const EXC_DUE = 8
Const EXC_EID = 26
Const PROC_NAME = "Outlook Synchronization"
'Do not change any constants from this point on
Const olTaskNotStarted = 0
Const olTaskInProgress = 1
Const olTaskComplete = 2
Const olTaskWaiting = 3
Const olTaskDeferred = 4
Const olText = 1
Const olYesNo = 6
Const olFolderTasks = 13
Const DESKTOP_READOBJECTS = &H1&
'--> Declare some variables
Dim olkApp As Object, _
olkSes As Object, _
olkFld As Object, _
olkTsk As Object, _
olkPrp As Object, _
excWks As Excel.Worksheet, _
lngRow As Long, _
strRun As String, _
bolSkp As Boolean
Private Sub InitializeExcel()
Set excWks = Application.ActiveWorkbook.Sheets(1)
lngRow = 2
strRun = Format(Now, "yyyy-mm-dd-hh-nn-ss")
End Sub
Private Sub DeactivateExcel()
Set excWks = Nothing
End Sub
Private Sub InitializeOutlook()
Set olkApp = CreateObject("Outlook.Application")
Set olkSes = olkApp.GetNamespace("MAPI")
olkSes.Logon olkApp.DefaultProfileName
Set olkFld = olkSes.GetDefaultFolder(olFolderTasks)
End Sub
Private Sub DeactivateOutlook()
olkSes.Logoff
Set olkFld = Nothing
Set olkSes = Nothing
Set olkApp = Nothing
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'--> On saving the workbook you will be given an opportunity to synchronize from Excel to Outlook
InitializeExcel 'Prep Excel for a sync
InitializeOutlook 'Prep Outlook for a sync
Excel2Outlook 'Sync from Excel to Outlook
DeactivateExcel 'Clean-up Excel
DeactivateOutlook 'Clean-up Outlook
End Sub
Private Sub Workbook_Open()
'--> On opening the workbook you will be given an opportunity to syncronize data from Outlook to Excel
bolSkp = False 'Set this to True if you don't want to be prompted to run the sync when opening/closing the spreadsheet.
InitializeExcel 'Prep Excel for a sync
InitializeOutlook 'Prep Outlook for a sync
Outlook2Excel 'Sync from Outlook to Excel
DeactivateExcel 'Clean-up Excel
DeactivateOutlook 'Clean-up Outlook
End Sub
Private Sub Excel2Outlook()
If Not bolSkp Then
If MsgBox("Should I sync the tasks to Outlook?", vbQuestion + vbYesNo, PROC_NAME) = vbYes Then
Do Until excWks.Cells(lngRow, 1) = ""
Select Case excWks.Cells(lngRow, EXC_EID)
Case ""
Set olkTsk = olkFld.Items.Add()
With olkTsk
.UserProperties.Add "ExcelTaskList", olYesNo, True
.UserProperties.Item("ExcelTaskList").Value = True
.UserProperties.Add "Synced", olText
.UserProperties.Item("Synced").Value = strRun
.Save
End With
excWks.Cells(lngRow, EXC_EID) = olkTsk.EntryID
Case Else
Set olkTsk = olkSes.GetItemFromID(excWks.Cells(lngRow, EXC_EID))
End Select
With olkTsk
.Subject = excWks.Cells(lngRow, EXC_CLIENT) & "/" & excWks.Cells(lngRow, EXC_SUBJECT)
If IsDate(excWks.Cells(lngRow, EXC_START)) Then .StartDate = excWks.Cells(lngRow, EXC_START)
If IsDate(excWks.Cells(lngRow, EXC_DUE)) Then .DueDate = excWks.Cells(lngRow, EXC_DUE)
Select Case excWks.Cells(lngRow, EXC_STATUS)
Case "Complete"
.Status = olTaskComplete
Case "Deferred"
.Status = olTaskDeferred
Case "In Progress"
.Status = olTaskInProgress
Case "Not Started"
.Status = olTaskNotStarted
Case "Waiting"
.Status = olTaskWaiting
End Select
olkTsk.UserProperties.Item("Synced").Value = strRun
.Save
End With
lngRow = lngRow + 1
Loop
For lngRow = olkFld.Items.Count To 1 Step -1
Set olkTsk = olkFld.Items(lngRow)
Set olkPrp = olkTsk.UserProperties.Find("ExcelTaskList", True)
If TypeName(olkPrp) <> "Nothing" Then
If olkTsk.UserProperties.Item("Synced").Value < strRun Then
olkTsk.Delete
End If
End If
Next
End If
End If
End Sub
Private Sub Outlook2Excel()
Dim excRng As Excel.Range, arrTmp As Variant, intCnt As Integer
If Not bolSkp Then
If MsgBox("Should I sync tasks from Outlook?", vbQuestion + vbYesNo, PROC_NAME) = vbYes Then
For intCnt = olkFld.Items.Count To 1 Step -1
Set olkTsk = olkFld.Items(intCnt)
Set olkPrp = olkTsk.UserProperties.Find("ExcelTaskList", True)
If TypeName(olkPrp) = "Nothing" Then
'The task does not exist in the spreadsheet. Add it.
lngRow = excWks.UsedRange.Rows.Count + 1
With olkTsk
If InStr(1, .Subject, "/") > 0 Then
arrTmp = Split(.Subject, "/")
excWks.Cells(lngRow, EXC_CLIENT) = arrTmp(0)
excWks.Cells(lngRow, EXC_SUBJECT) = arrTmp(1)
Else
excWks.Cells(lngRow, EXC_CLIENT) = "Select Client"
excWks.Cells(lngRow, EXC_SUBJECT) = .Subject
End If
If .StartDate <> #1/1/4501# Then
excWks.Cells(lngRow, EXC_START) = .StartDate
excWks.Cells(lngRow, EXC_START).NumberFormat = "[$-409]d-mmm;@"
End If
Select Case .Status
Case olTaskComplete
excWks.Cells(lngRow, EXC_STATUS) = "Complete"
Case olTaskDeferred
excWks.Cells(lngRow, EXC_STATUS) = "Deferred"
Case olTaskInProgress
excWks.Cells(lngRow, EXC_STATUS) = "In Progress"
Case olTaskNotStarted
excWks.Cells(lngRow, EXC_STATUS) = "Not Started"
Case olTaskWaiting
excWks.Cells(lngRow, EXC_STATUS) = "Waiting"
End Select
If .DueDate <> #1/1/4501# Then
excWks.Cells(lngRow, EXC_DUE) = .DueDate
excWks.Cells(lngRow, EXC_DUE).NumberFormat = "[$-409]ddd, mmm. d;@"
End If
excWks.Cells(lngRow, EXC_EID) = .EntryID
.UserProperties.Add "ExcelTaskList", olYesNo, True
.UserProperties.Item("ExcelTaskList").Value = True
.UserProperties.Add "Synced", olText
.UserProperties.Item("Synced").Value = strRun
.Save
End With
Else
If olkTsk.UserProperties.Item("Synced").Value > olkTsk.LastModificationTime Then
For lngRow = 2 To excWks.UsedRange.Rows.Count
If excWks.Cells(lngRow, EXC_EID) = olkTsk.EntryID Then Exit For
Next
If lngRow >= 2 And lngRow <= excWks.UsedRange.Rows.Count Then
With olkTsk
If InStr(1, .Subject, "/") > 0 Then
arrTmp = Split(.Subject, "/")
excWks.Cells(lngRow, EXC_CLIENT) = arrTmp(0)
excWks.Cells(lngRow, EXC_SUBJECT) = arrTmp(1)
Else
excWks.Cells(lngRow, EXC_CLIENT) = "Select Client"
excWks.Cells(lngRow, EXC_SUBJECT) = .Subject
End If
If .StartDate <> #1/1/4501# Then excWks.Cells(lngRow, EXC_START) = .StartDate
Select Case .Status
Case olTaskComplete
excWks.Cells(lngRow, EXC_STATUS) = "Complete"
Case olTaskDeferred
excWks.Cells(lngRow, EXC_STATUS) = "Deferred"
Case olTaskInProgress
excWks.Cells(lngRow, EXC_STATUS) = "In Progress"
Case olTaskNotStarted
excWks.Cells(lngRow, EXC_STATUS) = "Not Started"
Case olTaskWaiting
excWks.Cells(lngRow, EXC_STATUS) = "Waiting"
End Select
If .DueDate <> #1/1/4501# Then excWks.Cells(lngRow, EXC_DUE) = .DueDate
.UserProperties.Item("Synced").Value = strRun
.Save
End With
Else
MsgBox "Critical problem. There was no match in the spreadsheet for the task" & vbCrLf & vbTab & olkTsk.Subject, vbCritical + vbOKOnly, PROC_NAME
End If
End If
End If
Next
On Error Resume Next
For lngRow = excWks.UsedRange.Rows.Count To 2 Step -1
If excWks.Cells(lngRow, EXC_EID) <> "" Then
Set olkTsk = olkSes.GetItemFromID(excWks.Cells(lngRow, EXC_EID))
Debug.Print excWks.Cells(lngRow, EXC_SUBJECT)
If (TypeName(olkTsk) = "Nothing") Or (olkTsk.Parent.Name = "Deleted Items") Then
Set excRng = excWks.Range("A" & lngRow, "Z" & lngRow)
excRng.Delete xlShiftUp
End If
End If
Set olkTsk = Nothing
Next
On Error GoTo 0
End If
End If
End Sub
Public Sub ForceExcel2Close()
Dim varDesktop As Variant
varDesktop = OpenInputDesktop(0, False, DESKTOP_READOBJECTS)
'varDesktop will be 0 if the screen is locked, non-zero if it is not.
If varDesktop = 0 Then
bolSkp = True
ThisWorkbook.Save
CreateScriptFile
RunScriptFile
End If
End Sub
Sub CreateScriptFile()
Dim objFSO As Object, objFil As Object
Set objFSO = CreateObject("Scripting.FileSystemobject")
Set objFil = objFSO.CreateTextFile(Environ("TMP") & "\CloseExcel.vbs", True)
With objFil
.WriteLine "WScript.Sleep 5000"
.WriteLine "Set excApp = GetObject(,""Excel.Application"")"
.WriteLine "excApp.Quit"
.WriteLine "Set excApp = Nothing"
.Close
End With
Set objFSO = Nothing
Set objFil = Nothing
End Sub
Sub RunScriptFile()
Dim objShl As Object
Set objShl = CreateObject("WScript.Shell")
objShl.Run Environ("TMP") & "\CloseExcel.vbs", 0, False
Set objShl = Nothing
End Sub