MEET FEATURE REQUIREMENTS, SCHEDULE, and BUDGET! Consulting available to teach your organization to apply this methodology and tools for powerful quantitative management of your business processes.
- Instruction of your staff at your site, using courseware, application example, and a functional template.
- Mentoring your key staff on an ongoing or periodic basis, on these tools or on Quantitative Program Management.
- Contracting or Employment in your organization on specific topics.
Check out my YouTube Channel: Power Operational Intelligence
Now Live! Overview, Structure, Task Data, Table Design, SQL Server, and Re-Linking now showing.
Video courses covering material on this website, and more, are presented in the playlists.
Code snippet links at YouTube Code Snippets. Twitter at @poweroperation1, #poweropi, #poweroperationalintelligence.
Subscribe on YouTube, and click the "Notification" Bell icon to be notified as content is published.
Microsoft Project Task Data ExportThe following VB code exports task data from MSProject to an Excel file. To use the code, copy from this text file.
References Option Explicit Public Sub ReportDatesExport() 'Copyright (c) 2013 Richard M. Bixler, All Rights Reserved. Do not delete this copyright notice. 'Runs with "ctl-t" from MSProject UI. Dim thisProject As Project Dim fileName As String, filePath As String, mapName As String, meFileName As String Dim msgBoxResponse As VbMsgBoxResult Set thisProject = ActiveProject fileName = thisProject.Name filePath = thisProject.Path fileName = Left(fileName, InStrRev(fileName, ".", , vbTextCompare) - 1) 'OPTIONAL: warn the user if exporting from a non-rollup project, and allow them to abort ' the operation. If InStr(1, LCase(fileName), "rollup", vbTextCompare) <= 0 Then msgBoxResponse = MsgBox("Export from Rollup. Click Ok to continue anyway, _ Cancel to abort.", vbOKCancel, "Export Rollup") If msgBoxResponse = vbCancel Then Exit Sub End If 'NOTE: the export will be into a file called <filename>.xlsx, similar to the <filename>.mpp you are 'exporting. The export will be in the same directory as the .mpp you are exporting. 'You will need to import this filename to use the data. mapName = "ReportDatesExport" createMap mapName:=mapName FileSaveAs Name:=filePath & "/" & fileName & ".xlsx", FormatID:="MSProject.ACE", map:=mapName 'FileSaveAs Name:=filePath & "/" & fileName & ".xls", FormatID:="MSProject.XLS5", map:=mapName End Sub Sub createMap(ByVal mapName As String) 'Copyright (c) 2013 Richard M. Bixler, All Rights Reserved. Do not delete this copyright notice. MapEdit Name:=mapName, Create:=True, OverwriteExisting:=True, DataCategory:=pjMapTasks, _ CategoryEnabled:=True, TableName:="Task_Table1", FieldName:="Name", _ ExternalFieldName:="Name", HeaderRow:=True, AssignmentData:=False, TextFileOrigin:=0, _ UseHtmlTemplate:=False, IncludeImage:=False MapEdit Name:=mapName, DataCategory:=pjMapTasks, FieldName:="Start", _ ExternalFieldName:="Start_Date" MapEdit Name:=mapName, DataCategory:=pjMapTasks, FieldName:="Finish", _ ExternalFieldName:="Finish_Date" MapEdit Name:=mapName, DataCategory:=pjMapTasks, FieldName:="Notes", _ ExternalFieldName:="Notes" MapEdit Name:=mapName, DataCategory:=pjMapTasks, FieldName:="UniqueID", _ ExternalFieldName:="UniqueID" End Sub Visio .mpp PresentationThe following VB code displays exported MSProject task data as bars in a Visio doc. To use the code, copy from this text file. Link Visio2010 External Data to Excel export file from Microsoft Project.
In Visio2010, insert a timeline object on a page (from Timeline Shapes) and configure it. In Visio2010, a insert a Block Interval or Diamond Milestone on the page. In Visio2010, show the External Data pane along with the Drawing pane. In the External Data, scroll to the desired task and drag from it to the Block Interval or Diamond Milestone to create a link. The following code will position the Diamond Milestone to the Start Date of the linked task, or size and position the Block Interval properly relative to the dates shown for the Timeline Shape in the drawing. A task shape rectangle with a start date or end date outside the start and end dates of the timeline onthe page is truncated to that end date, and the shape outline will be shown as a dashed line. A task shape rectangle completely outside the timeline will be hidden.
In Visio2010 Modules: Module1 Option Explicit Dim inchesPerDay As Double Public Sub setupShapes() 'Copyright (c) 2012 Richard M. Bixler, All Rights Reserved. Do not delete this copyright notice. Dim thisPage As Page Dim shapeVar As Variant Dim thisShape As Shape Dim cellValue As Variant, cellValueW As Variant, cellVisMilestoneStart As Variant Dim cellStartDate As String, cellFinishDate As String, cellName As String, cellUniqueID As String Dim setLeft As String, setWidth As String, setHeight As String Dim cellLookFor As String, temp As String, tempTest As String Dim dateStart As Date, dateEnd As Date, dateStartLocal As Date, dateFinishLocal As Date Dim dateTest As Date Dim dimLeft As Double, dimRight As Double, dimTotal As Double, dimLeftLocal As Double Dim dimWidthLocal As Double, dimWidth As Double Dim gotLeft As Boolean, gotRight As Boolean Dim dateRange As Double, widthTest As Double, testDbl As Double Dim vsoDataRecordset As Visio.DataRecordset Dim intDataRecordsetCount As Integer, thisDataRecordsetNumber As Integer 'Refresh the DataRecordset intDataRecordsetCount = ActiveDocument.DataRecordsets.Count For thisDataRecordsetNumber = 1 To intDataRecordsetCount Set vsoDataRecordset = ActiveDocument.DataRecordsets(thisDataRecordsetNumber) vsoDataRecordset.Refresh Next thisDataRecordsetNumber Set thisPage = ActivePage cellStartDate = "Prop._VisDM_Start_Date" cellFinishDate = "Prop._VisDM_Finish_Date" cellName = "Prop._VisDM_Name" cellUniqueID = "Prop._VisDM_UniqueID" cellVisMilestoneStart = "User.visMilestoneDate" gotLeft = False gotRight = False 'Get timeline Start and End dates from timeline object For Each shapeVar In thisPage.Shapes Set thisShape = shapeVar If InStr(1, thisShape.NameU, "timeline", vbTextCompare) > 0 Then 'When a timeline shape is found, associate start and end dates with 'physical size and placement of the timeline object. cellValue = "" cellValueW = "" If thisShape.CellExists("User.visBeginDate", True) Then dateStart = _ thisShape.Cells("User.visBeginDate").Formula If thisShape.CellExists("User.visEndDate", True) Then dateEnd = _ thisShape.Cells("User.visEndDate").Formula If thisShape.CellExists("BeginX", True) Then cellValue = thisShape.Cells("BeginX")._ Formula If thisShape.CellExists("EndX", True) Then cellValueW = thisShape.Cells("EndX")._ Formula If cellValue <> "" And cellValueW <> "" Then cellValue = Trim(Left(cellValue, Len(cellValue) - 3)) cellValueW = Trim(Left(cellValueW, Len(cellValueW) - 3)) dimLeft = CSng(cellValue) dimRight = CSng(cellValueW) gotLeft = True gotRight = True Exit For End If End If Next shapeVar If gotLeft And gotRight Then dateRange = CDbl(dateEnd - dateStart + 1) dimTotal = dimRight - dimLeft inchesPerDay = CDbl(dimTotal / dateRange) 'Scan all shapes, and place the ones that are linked to schedule data. Set width ' to match duration (finish date - start date). Determine midpoint date given the ' duration and start date, and set PinX to locate the shape along the timeline. For Each shapeVar In thisPage.Shapes Set thisShape = shapeVar cellValue = thisShape.Characters 'If it's linked to the data from the mpp, a shape will have a UniqueID cell specifying 'the UniqueID of the mpp task to which it is linked, as well as cells for start and 'end dates for the task. If thisShape.CellExists(cellUniqueID, True) Then 'If it's a shape linked to the import data file, then get the start and end dates ' from the linkage. If thisShape.CellExists(cellStartDate, True) Then dateStartLocal = _ DateValue(formulaStringToString(thisShape.Cells(cellStartDate).Formula)) If thisShape.CellExists(cellFinishDate, True) Then dateFinishLocal = _ DateValue(formulaStringToString(thisShape.Cells(cellFinishDate).Formula)) 'If it's a milestone shape: Milestone date is taken from the Start date of a task, ' so set it that way to be sure its displayed position and width are correct. If thisShape.CellExists(cellVisMilestoneStart, True) Then _ dateFinishLocal = dateStartLocal 'If shape is completely outside the timeline, just hide the shape. If dateStartLocal >= dateEnd Or dateFinishLocal <= dateStart Then 'Put the shape at the timeline limit so that it won't invoke an adjacent page. If dateStartLocal >= dateEnd Then dateStartLocal = dateEnd dateFinishLocal = dateStartLocal End If If dateFinishLocal <= dateStart Then dateFinishLocal = dateStart dateStartLocal = dateFinishLocal End If 'Hide the shape or milestone... If thisShape.CellExists(cellVisMilestoneStart, True) Then 'Hide Milestone 'Not clear how to hide a milestone... the following do not work ' thisShape.Cells("Transparency").Formula = "100%" ' thisShape.Cells("LineColorTrans").Formula = "100%" ' thisShape.Cells("FillForegndTrans").Formula = "100%" ' thisShape.Cells("FillBkgndTrans").Formula = "100%" ' thisShape.Cells("HideText").Formula = "True" Else 'Hide Shape thisShape.Cells("Geometry1.NoShow").Formula = "True" thisShape.Cells("HideText").Formula = "True" End If 'Otherwise show the shape, with appropriate modifiers. Else 'Show the shape or milestone... If thisShape.CellExists(cellVisMilestoneStart, True) Then 'Show Milestone 'Not clear how to show a milestone... the following do not work ' thisShape.Cells("Transparency").Formula = "0%" ' thisShape.Cells("LineColorTrans").Formula = "0%" ' thisShape.Cells("FillForegndTrans").Formula = "0%" ' thisShape.Cells("FillBkgndTrans").Formula = "0%" ' thisShape.Cells("HideText").Formula = "False" Else 'Show Shape thisShape.Cells("Geometry1.NoShow").Formula = "False" thisShape.Cells("HideText").Formula = "False" End If 'If shape extends outside timeline, make the outline "dashed" If dateStartLocal < dateStart Or dateFinishLocal > dateEnd Then 'If shape extends beyond limits of the timeline... 'If it's not a milestone, make outline dashed. If Not thisShape.CellExists(cellVisMilestoneStart, True) Then _ thisShape.Cells("LinePattern").Formula = "2" Else 'If it's not a milestone, make outline a solid line. If Not thisShape.CellExists(cellVisMilestoneStart, True) Then _ thisShape.Cells("LinePattern").Formula = "1" End If 'If shape extends beyond timeline start, truncate the start of the task ' to the milestone start. If dateStartLocal < dateStart Then dateStartLocal = dateStart If thisShape.CellExists(cellVisMilestoneStart, True) Then 'If it's a milestone, keep the start and end dates consistent. dateFinishLocal = dateStart End If End If 'If shape extends beyond timeline end, truncate the end of the task to the ' milestone end. If dateFinishLocal > dateEnd Then dateFinishLocal = dateEnd If thisShape.CellExists(cellVisMilestoneStart, True) Then 'If it's a milestone, keep the start and end dates consistent. dateStartLocal = dateEnd End If End If End If 'Set the shape dimensions and position to match its net start and end dates. dimWidth = CDbl(dateFinishLocal - dateStartLocal + 1) * inchesPerDay setWidth = formatInches(dimWidth) 'testDbl = CDbl(Left(setWidth, Len(setWidth) - 3)) / inchesPerDay setLeft = formatInches(dimLeft + dimWidth / 2 + _ daysToInches(CDbl(dateStartLocal - dateStart + 1))) 'dateTest = dateStart + (CDbl(Left(setLeft, Len(setLeft) - 3)) - _ dimLeft) / inchesPerDay setHeight = "0.25 in" 'Cells are set as strings, so they have to be formatted properly. thisShape.Cells("PinX").Formula = stringToFormulaForString(setLeft) thisShape.Cells("Width").Formula = stringToFormulaForString(setWidth) thisShape.Cells("Height").Formula = stringToFormulaForString(setHeight) 'If shape is a milestone, set the visible date. If thisShape.CellExists(cellVisMilestoneStart, True) Then _ thisShape.Cells(cellVisMilestoneStart) = _ DateValue(formulaStringToString(thisShape.Cells(cellStartDate)._ Formula)) End If Next shapeVar End If End Sub Public Sub updatePath() 'Copyright (c) 2012 Richard M. Bixler, All Rights Reserved. Do not delete this copyright notice. Dim vsoDataRecordset As Visio.DataRecordset Dim thisDataConnection As DataConnection Dim intDataRecordsetCount As Integer, thisDataRecordsetNumber As Integer Dim thisPath As String, thisFileName As String 'Refresh the DataRecordset intDataRecordsetCount = ActiveDocument.DataRecordsets.Count For thisDataRecordsetNumber = 1 To intDataRecordsetCount Set vsoDataRecordset = ActiveDocument.DataRecordsets(thisDataRecordsetNumber) Set thisDataConnection = vsoDataRecordset.DataConnection thisFileName = thisDataConnection.FileName If InStr(1, thisFileName, "netapp12a", vbTextCompare) Then thisFileName = Replace(thisFileName, "netapp12a", "netapp24a") 'thisDataConnection.FileName = thisFileName End If thisPath = thisDataConnection.ConnectionString If InStr(1, thisPath, "netapp12a", vbTextCompare) Then thisPath = Replace(thisPath, "netapp12a", "netapp24a") thisDataConnection.ConnectionString = thisPath End If vsoDataRecordset.Refresh Next thisDataRecordsetNumber End Sub Private Function stringToFormulaForString(strIn As String) As String Dim strResult As String On Error GoTo stringToFormulaForString_Err strResult = strIn strResult = Replace(strResult, Chr(34), Chr(34) & Chr(34)) strResult = Chr(34) & strResult & Chr(34) stringToFormulaForString = strResult Exit Function stringToFormulaForString_Err: Debug.Print Err.Description End Function Private Function formulaStringToString(strFormula As String) As String Const ONE_QUOTE As String = """" Const TWO_QUOTES As String = """""" Dim strConvertedFormula As String, strFirstCharacter As String Dim strLastCharacter As String, intStringLength As Integer On Error GoTo formulaStringToString_Err strConvertedFormula = strFormula intStringLength = Len(strFormula) strFirstCharacter = Mid(strFormula, 1, 1) strLastCharacter = Mid(strFormula, intStringLength, 1) If (strFirstCharacter = ONE_QUOTE And strLastCharacter = ONE_QUOTE) Then strConvertedFormula = Mid(strFormula, 2, (intStringLength - 2)) strConvertedFormula = Replace(strConvertedFormula, TWO_QUOTES, ONE_QUOTE) End If formulaStringToString_End: formulaStringToString = strConvertedFormula Exit Function formulaStringToString_Err: strConvertedFormula = "" Debug.Print Err.Description Resume formulaStringToString_End End Function Private Function daysToInches(ByVal inputDays As Integer) As Double daysToInches = inputDays * inchesPerDay End Function Private Function formatInches(ByVal inputInches As Double) As String formatInches = Format(inputInches, "0.00000") & " in" End Function Public Sub saveImages() Save_GIF Save_pdf End Sub Private Sub Save_GIF() 'Enable diagram services Dim DiagramServices As Integer Dim thisFileName As String, thisFilePath As String, thisFileExtension As String Dim thisDocument As Document Set thisDocument = ActiveDocument DiagramServices = thisDocument.DiagramServicesEnabled thisDocument.DiagramServicesEnabled = visServiceVersion140 thisFilePath = thisDocument.FullName thisFileName = thisDocument.Name thisFileExtension = Right(thisFileName, Len(thisFileName) - _ InStrRev(thisFileName, ".", , vbTextCompare)) thisFilePath = Left(thisFilePath, Len(thisFilePath) - Len(thisFileName)) thisFileName = Left(thisFileName, Len(thisFileName) - Len(thisFileExtension) - 1) Application.Settings.SetRasterExportResolution visRasterUseSourceResolution, 96#, 96#, _ visRasterPixelsPerInch Application.Settings.SetRasterExportSize visRasterFitToSourceSize, 16.666667, 20.145833, _ visRasterInch Application.Settings.RasterExportDataFormat = visRasterNonInterlace Application.Settings.RasterExportColorReduction = visRasterAdaptive Application.Settings.RasterExportRotation = visRasterNoRotation Application.Settings.RasterExportFlip = visRasterNoFlip Application.Settings.RasterExportBackgroundColor = 16777215 Application.Settings.RasterExportTransparencyColor = 16777215 Application.Settings.RasterExportUseTransparencyColor = False Application.ActiveWindow.Page.Export thisFilePath & thisFileName & ".gif" 'Restore diagram services ActiveDocument.DiagramServicesEnabled = DiagramServices End Sub Private Sub Save_pdf() 'Enable diagram services Dim DiagramServices As Integer Dim thisFileName As String, thisFilePath As String, thisFileExtension As String Dim thisDocument As Document Set thisDocument = ActiveDocument DiagramServices = ActiveDocument.DiagramServicesEnabled ActiveDocument.DiagramServicesEnabled = visServiceVersion140 thisFilePath = thisDocument.FullName thisFileName = thisDocument.Name thisFileExtension = Right(thisFileName, Len(thisFileName) - _ InStrRev(thisFileName, ".", , vbTextCompare)) thisFilePath = Left(thisFilePath, Len(thisFilePath) - Len(thisFileName)) thisFileName = Left(thisFileName, Len(thisFileName) - Len(thisFileExtension) - 1) Application.ActiveDocument.ExportAsFixedFormat visFixedFormatPDF, thisFilePath & _ thisFileName & ".pdf", visDocExIntentPrint, visPrintAll, 1, 1, False, True, True, _ True, False 'Restore diagram services ActiveDocument.DiagramServicesEnabled = DiagramServices End Sub In Visio Objects: ThisDocument(docname) Dim thisEventHandler As EventHandler Private Sub Document_DocumentOpened(ByVal Doc As IVDocument) 'Set up handler to catch app-level events Set thisEventHandler = New EventHandler Set thisEventHandler.vsoApplication = Application 'Refresh when opened Module1.setupShapes End Sub In Visio Class Modules: EventHandler Public WithEvents vsoApplication As Visio.Application 'Instantiation of this class contains vsoApplication object which will be set 'to contain a Visio application object. Events from that object can be caught 'and handled here. Private Sub vsoApplication_CellChanged(ByVal vsoCell As IVCell) Dim vsoCellname As String 'If values in a timeline object change, re-draw the doc to reflect changed dates 'or physical placement due to timeline object size change. vsoCellname = vsoCell.Shape.NameU If InStr(1, LCase(vsoCellname), "timeline", vbTextCompare) > 0 Then Module1.setupShapes End Sub Private Sub vsoApplication_DocumentOpened(ByVal Doc As IVDocument) Dim vsoDataRecordset As Visio.DataRecordset Dim intDataRecordsetCount As Integer, thisDataRecordsetNumber As Integer If Doc.Name = ActiveDocument.Name Then 'Refresh the DataRecordset intDataRecordsetCount = ActiveDocument.DataRecordsets.Count For thisDataRecordsetNumber = 1 To intDataRecordsetCount Set vsoDataRecordset = ActiveDocument.DataRecordsets(thisDataRecordsetNumber) vsoDataRecordset.Refresh Next thisDataRecordsetNumber 'Update the drawing to show new data Module1.setupShapes End If End Sub Procedural State MachineThe following VB code illustrates implementation of a state machine using a Case statement. private enum stStates state1_Name state2_Name end enum private enum txinput_signals input_signal1_Name input_signal2_Name input_signal3_Name end enum initialize_all() While Not FileIO.thisTextStream.AtEndOfStream And Not exit_record_loop FileIO.currentRecord = FileIO.thisTextStream.ReadLine select case currentState.name case state1_Name state1_processingForCurrentRecord() state1_assert_output_signalsForCurrentRecord() state1_determine_input_signalsForCurrentRecord() select case input_signals case input_signal1_Name currentState.name = state2_Name case input_signal2_Name exit_record_loop = true end select case state2_Name state2_processingForCurrentRecord() state2_assert_output_signalsForCurrentRecord() state2_determine_input_signalsForCurrentRecord() if input_signal3_Name then currentState = state1_Name end select close_everything() Wend |