How to filter for milestones *and* their predecessors?

A

Ancient Brit

I've checked the FAQ and I can't find anything that addresses my particular
challenge, so my apologies if this does turn out to be a commonly asked
question.

I've been given an MSP2003 file and asked to create a tracking Gantt view
that can be updated quickly and as required. I'm not an MSP guru but I have a
programming background and I like a challenge :)

The view has to consist of all milestones (which if that was all it was,
filtering would do it nicely) *and* any and all tasks whose ID appears in the
predecessor cell for each milestone. While each related task ID appears in
the filtered view (in the predecessor cell for the milestone), the ID gives
no indication of the nature of the task, and an appended lookup table would
not be practical (some 400 tasks).

I can't find a simple filtering solution but I can see a possible route
using a macro, and I'd be grateful for constructive feedback on the approach
(or a polite vector if the question's been answered a gazillion times already
:)).

I'm considering creating an extra column based on Flag1 with content Yes/No
for simplicity. This could be part of the macro but it might complicate
things a little (need to test whether the column already exists, if so is the
content only Yes/No or does it have some other content and how to handle that
as an error, otherwise set all entries to default No).

Stepping through the project, each task is examined.

If it is a milestone, Flag1 is set to Yes.

Then the predecessor entry for that task is examined.

If the cell is empty, the process continues with the next task.

If not empty, the macro will step through the list of IDs in the cell, using
each ID to address the appropriate task and set Flag1 for the task to Yes.

After the last entry in the cell, the macro moves on to the next task, until
the end of the project is reached.

A possible complication is the existence of an embedded project from another
user, where the ID sequence of the host project is interrupted, starts from 1
again for the duration of the embedded project, and then continues where it
left off. This could make identifying the predecessor tasks given an ID a
little difficult. I'm hoping the IDs for the embedded project have some
identifier that distinguishes them!

Finally, I have already identified a way to filter on Flag1=Yes. The
resulting view shows all milestones and all related tasks that are not
milestones, in ID sequence.

Grateful for any feedback.

Peter
 
J

John

Ancient Brit said:
I've checked the FAQ and I can't find anything that addresses my particular
challenge, so my apologies if this does turn out to be a commonly asked
question.

I've been given an MSP2003 file and asked to create a tracking Gantt view
that can be updated quickly and as required. I'm not an MSP guru but I have a
programming background and I like a challenge :)

The view has to consist of all milestones (which if that was all it was,
filtering would do it nicely) *and* any and all tasks whose ID appears in the
predecessor cell for each milestone. While each related task ID appears in
the filtered view (in the predecessor cell for the milestone), the ID gives
no indication of the nature of the task, and an appended lookup table would
not be practical (some 400 tasks).

I can't find a simple filtering solution but I can see a possible route
using a macro, and I'd be grateful for constructive feedback on the approach
(or a polite vector if the question's been answered a gazillion times already
:)).

I'm considering creating an extra column based on Flag1 with content Yes/No
for simplicity. This could be part of the macro but it might complicate
things a little (need to test whether the column already exists, if so is the
content only Yes/No or does it have some other content and how to handle that
as an error, otherwise set all entries to default No).

Stepping through the project, each task is examined.

If it is a milestone, Flag1 is set to Yes.

Then the predecessor entry for that task is examined.

If the cell is empty, the process continues with the next task.

If not empty, the macro will step through the list of IDs in the cell, using
each ID to address the appropriate task and set Flag1 for the task to Yes.

After the last entry in the cell, the macro moves on to the next task, until
the end of the project is reached.

A possible complication is the existence of an embedded project from another
user, where the ID sequence of the host project is interrupted, starts from 1
again for the duration of the embedded project, and then continues where it
left off. This could make identifying the predecessor tasks given an ID a
little difficult. I'm hoping the IDs for the embedded project have some
identifier that distinguishes them!

Finally, I have already identified a way to filter on Flag1=Yes. The
resulting view shows all milestones and all related tasks that are not
milestones, in ID sequence.

Grateful for any feedback.

Peter

Peter,
I know I said this should really be posted to this newsgroup, but since
I already addressed it in the main group, this post is unnecessary at
this point. However, in the event that someone else wishes to respond,
they might want to read our thread in the main newsgroup first.

John
Project MVP
 
A

Ancient Brit

Hi John

My apologies - once you indicated that the query properly belonged here, I
transferred to this group. I did wonder why you'd continued in the other
group...

My problem now is that my deadlines have been foreshortened and I have other
priorities to handle as well, so I don't have the luxury of spending time
working exclusively on the problem to my own satisfaction.

As an interim solution I submitted a manual workaround, which is labor
intensive and not what I had planned at all, but it will give me 24 hours
breathing space.

Normally I'm quite happy to work on something with little or no
documentation and minimal support, but then I usually have more time at my
disposal :(

I'll get back to this after I've grabbed some more sleep. Four hours in two
days is not my idea of adequate rest...

Best,

Peter
 
J

John

Ancient Brit said:
Hi John

My apologies - once you indicated that the query properly belonged here, I
transferred to this group. I did wonder why you'd continued in the other
group...

My problem now is that my deadlines have been foreshortened and I have other
priorities to handle as well, so I don't have the luxury of spending time
working exclusively on the problem to my own satisfaction.

As an interim solution I submitted a manual workaround, which is labor
intensive and not what I had planned at all, but it will give me 24 hours
breathing space.

Normally I'm quite happy to work on something with little or no
documentation and minimal support, but then I usually have more time at my
disposal :(

I'll get back to this after I've grabbed some more sleep. Four hours in two
days is not my idea of adequate rest...

Best,

Peter
Peter,
I responded in the main newsgroup because I also answer VBA questions
and you had already posted in the main group, so.... while I was there.

All I'm saying is that for future reference it is better to post in the
most appropriate group, and for VBA issues that is this group (i.e.
developer).

Hope you get rested.
John
 
A

Ancient Brit

Hi John
Peter,
I responded in the main newsgroup because I also answer VBA questions
and you had already posted in the main group, so.... while I was there.

All I'm saying is that for future reference it is better to post in the
most appropriate group, and for VBA issues that is this group (i.e.
developer).

Hope you get rested.

Understood. My online life began in the late 80s/early 90s in Usenet/Netnews
so I know what you mean. Folks were somewhat unforgiving if you posted in the
wrong group, even innocently. I wasn't initially convinced that VBA was the
only way to go, which is why I didn't post here first (and didn't spam all
groups simultaneously).

I got rest, thanks. Although one would always want more...

I took a look at the TaskDependency Object and I have a hunch that in the
long term it would be the better way to go but for a quick and dirty (well,
so much for quick) solution I like the idea of parsing the predecessors in
order to set Flag1 appropriately. Since this will also be visible in the
additional column I've added that's useful for those viewing the results (a
little positive reinforcement always goes down well with senior management :))

I did a quick look around for the macro you said you had produced but
couldn't locate it immediately - can I play dumb and ask for a URL, please?
:) Ordinarily I'm an advocate of LBD (learning by doing) but for now I have
to make do with SSEI (stealing someone else's ideas)...

Sorry - not stealing. Employing re-usable code.

I realize that I'm going to have to make sure that the entire project
(including the embedded project) is fully expanded before the work starts, so
that's something else to consider.

Best,

Peter
 
J

John

Ancient Brit said:
Hi John



Understood. My online life began in the late 80s/early 90s in Usenet/Netnews
so I know what you mean. Folks were somewhat unforgiving if you posted in the
wrong group, even innocently. I wasn't initially convinced that VBA was the
only way to go, which is why I didn't post here first (and didn't spam all
groups simultaneously).

I got rest, thanks. Although one would always want more...

I took a look at the TaskDependency Object and I have a hunch that in the
long term it would be the better way to go but for a quick and dirty (well,
so much for quick) solution I like the idea of parsing the predecessors in
order to set Flag1 appropriately. Since this will also be visible in the
additional column I've added that's useful for those viewing the results (a
little positive reinforcement always goes down well with senior management
:))

I did a quick look around for the macro you said you had produced but
couldn't locate it immediately - can I play dumb and ask for a URL, please?
:) Ordinarily I'm an advocate of LBD (learning by doing) but for now I have
to make do with SSEI (stealing someone else's ideas)...

Sorry - not stealing. Employing re-usable code.

I realize that I'm going to have to make sure that the entire project
(including the embedded project) is fully expanded before the work starts, so
that's something else to consider.

Best,

Peter

Peter,
Don't worry about the posting. I think we've spent enough time on that
and you obviously understand our newsgroup "groundrules".

The macro I referred to is not available on any website - at least it
better not be. I don't have a website of handy dandy Project VBA macros
like fellow MVP, Jack Dahlgren, although at one point in the past I did
consider creating one.

The macro is only available directly from me and it is not freeware. It
does quite a bit more than you need. All you really need is to parse
through the predecessor list and then use the Find Method for each
predecessor. Set the desired flag on the found predecessor task and go
to the next predecessor or task. If you are still interested in my
macro, even if only for the parsing algorithm, you can contact me at the
address below.

John
Project MVP
jensenj6atatcomcastdotdotnet
(remove obvious redundancies)
 
A

Ancient Brit

Well, it's taken an age to get back to this - other priorities took over
(including a system failure that refuses to be resolved - can you say "manual
editing of the MBR required"? :))

Anyway, I did get an interim solution that works well enough but doesn't
address the embedded project for now (although I know how to do that) - quick
n' dirty code extract below - and in the process came across a weird bug. If
I step through an action it processes perfectly; if I Run, it doesn't
(nothing happens):

SelectTaskField Row:=0, Column:="Flag1"
SetTaskField Field:="Flag1", Value:="Yes"

This sets the Project Summary Flag1 entry (the summary is set to be viewed,
a user-defined column named MRT containing values for Flag1 is visible) to
the same value as others in the project (MSP2003 doesn't like talking to the
Project Summary for some reason - using zero as an index value seems to be a
no-no, even though using Recorder generates code that does just that).

Step through it in Debug mode and it works fine. Run the code and it
doesn't. I haven't been able to locate this as a known bug (but I've not been
looking for long - too many other fires to put out).

The code fragment (extract from a larger Sub()) that solved part of my
problem is:

Sub pbTestProject()

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

Dim pbTotalTasks, pbTaskCount, pbPredPointer As Long 'Set up sundry
variables

Set pbTasks = ActiveProject.Tasks 'Get current project's collection of
tasks

pbTotalTasks = pbTasks.Count 'Get the count of the tasks; this defines
the work to be done

SelectTaskColumn Column:="Flag1" 'Clear out the current settings for all
MRT entries in the current project

EditClear

'Begin work loop, count through all tasks (there are other operations to
be performed too, not shown here):

For pbTaskCount = 1 To pbTotalTasks

'Test for milestone

If pbTasks(pbTaskCount).Milestone = True Then

pbTasks(pbTaskCount).Flag1 = "Yes"

If Not pbTasks(pbTaskCount).PredecessorTasks Is Nothing Then

Set pbPredecessor = pbTasks(pbTaskCount).PredecessorTasks

For Each pbItem In pbPredecessor

pbPredPointer = pbItem.ID

pbTasks(pbPredPointer).Flag1 = "Yes"

Next pbItem

End If

End If

Next pbTaskCount

End Sub

No parsing required, which makes my life easier :)

The milestones are flagged as is as any task that is a Predecessor of a
milestone, which is what I needed. The code can be re-used for an embedded
project by making the project active, I think. I'll get some time to work on
that later. But for now I'm happy :)

I gleaned useful info and inspiration from various sources including Jack
Dalgren's excellent resources, for which I am very grateful. I didn't make
the deadline but then other catastrophes intervened that gave me a good
excuse :)

Many thanks to all - keep up the excellent work.

And Happy New Year!

Best,

Peter
 
J

John

Ancient Brit said:
Well, it's taken an age to get back to this - other priorities took over
(including a system failure that refuses to be resolved - can you say "manual
editing of the MBR required"? :))

Anyway, I did get an interim solution that works well enough but doesn't
address the embedded project for now (although I know how to do that) - quick
n' dirty code extract below - and in the process came across a weird bug. If
I step through an action it processes perfectly; if I Run, it doesn't
(nothing happens):

SelectTaskField Row:=0, Column:="Flag1"
SetTaskField Field:="Flag1", Value:="Yes"

This sets the Project Summary Flag1 entry (the summary is set to be viewed,
a user-defined column named MRT containing values for Flag1 is visible) to
the same value as others in the project (MSP2003 doesn't like talking to the
Project Summary for some reason - using zero as an index value seems to be a
no-no, even though using Recorder generates code that does just that).

Step through it in Debug mode and it works fine. Run the code and it
doesn't. I haven't been able to locate this as a known bug (but I've not been
looking for long - too many other fires to put out).

The code fragment (extract from a larger Sub()) that solved part of my
problem is:

Sub pbTestProject()

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

Dim pbTotalTasks, pbTaskCount, pbPredPointer As Long 'Set up sundry
variables

Set pbTasks = ActiveProject.Tasks 'Get current project's collection of
tasks

pbTotalTasks = pbTasks.Count 'Get the count of the tasks; this defines
the work to be done

SelectTaskColumn Column:="Flag1" 'Clear out the current settings for all
MRT entries in the current project

EditClear

'Begin work loop, count through all tasks (there are other operations to
be performed too, not shown here):

For pbTaskCount = 1 To pbTotalTasks

'Test for milestone

If pbTasks(pbTaskCount).Milestone = True Then

pbTasks(pbTaskCount).Flag1 = "Yes"

If Not pbTasks(pbTaskCount).PredecessorTasks Is Nothing Then

Set pbPredecessor = pbTasks(pbTaskCount).PredecessorTasks

For Each pbItem In pbPredecessor

pbPredPointer = pbItem.ID

pbTasks(pbPredPointer).Flag1 = "Yes"

Next pbItem

End If

End If

Next pbTaskCount

End Sub

No parsing required, which makes my life easier :)

The milestones are flagged as is as any task that is a Predecessor of a
milestone, which is what I needed. The code can be re-used for an embedded
project by making the project active, I think. I'll get some time to work on
that later. But for now I'm happy :)

I gleaned useful info and inspiration from various sources including Jack
Dalgren's excellent resources, for which I am very grateful. I didn't make
the deadline but then other catastrophes intervened that gave me a good
excuse :)

Many thanks to all - keep up the excellent work.

And Happy New Year!

Best,

Peter
Peter,
Boy, it's been so long I forgot what the goal is. At any rate I'm glad
you got something that seems to work for you. I have just a few comments
on your code.

1. The following dimension statement only dimensions the last variable
as long, the others will all be variant
Dim var1, var2, var3 as long
Each variable must be individually dimensioned, for example,
Dim var1 as long, var2 as long, var3 as long

2. You do not need to run your loop using the Count property. Since you
previously selected the task column, all tasks in the current view are
still selected. You could use the following loop structure
For each pbtask in ActiveSelection.Tasks

3. You used an, If Not [something] Is Nothing Then, to avoid tasks with
no predecessors. That's one way to do it but you don't really need it at
that location in the code, but you should have that error trap in the
main loop. The following loop construct will get what you need a little
more efficiently, is a little more robust, and works directly on a
master file (no need to activate each subproject separately). By the
way, this construct also allows you to do whatever you need to do with
the Project Summary Task fields because if the Project Summary Task is
displayed, it will be the first task in the active selection.

Sub Check_Preds()
Dim t As Task
Dim ptx As Task
Dim pt As Tasks
OutlineShowTasks expandinsertedprojects:=True
SelectTaskColumn
For Each t In ActiveSelection.Tasks
If Not t Is Nothing Then
If t.Milestone = True Then
t.Flag1 = True
Set pt = t.PredecessorTasks
For Each ptx In pt
ptx.Flag1 = True
Next ptx
End If
End If
Next t

End Sub

John
Project MVP
 
A

Ancient Brit

Hi John

Thanks for the critique - I'll get some time hopefully later to go through
in detail, but just to address a couple of points:

I hacked this bit of code out of a more complex macro (no need to anger my
client by placing their work in public :)) so inevitably despite my best
efforts some incongruities will arise.

My DIMs originally were one per line for clarity; I concatenated the three
Longs into one for convenience, not realising that they would be treated
differently. Oops. Thanks for that info! Useful to know.

I went with the Count to make sure that every task was addressed (and so I
could audit the process; a physical change log is created in the process); in
future I may well use For Each as I did for the predecessors (as long as
control over the sequence can be exerted). Thanks for that too.

My If...Nothing test is I think in the right place - there are milestones
with no predecessors, but the milestones still need to be flagged. Tasks that
are not milestones but which have predecessors don't need to be flagged, and
neither do their predecessors.

Nice bit of tight coding - and I guess it takes care of embedded projects,
too, with which I've been wrestling (there are some really screwy aspects to
the object model, or maybe it's just M$ and their implementation of the
code). Odd that the SubProject object doesn't possess the same attributes as
the Project object...

However, I need to let the user know (i) whether there are embedded projects
and (ii) if so, what they are (there's a possible requirement to selectively
exclude certain embedded projects from the process), so I may stick with the
direction in which I'm heading for that aspect.

Thanks again for your help!

Best,

Peter

John said:
Ancient Brit said:
Well, it's taken an age to get back to this - other priorities took over
(including a system failure that refuses to be resolved - can you say "manual
editing of the MBR required"? :))

Anyway, I did get an interim solution that works well enough but doesn't
address the embedded project for now (although I know how to do that) - quick
n' dirty code extract below - and in the process came across a weird bug. If
I step through an action it processes perfectly; if I Run, it doesn't
(nothing happens):

SelectTaskField Row:=0, Column:="Flag1"
SetTaskField Field:="Flag1", Value:="Yes"

This sets the Project Summary Flag1 entry (the summary is set to be viewed,
a user-defined column named MRT containing values for Flag1 is visible) to
the same value as others in the project (MSP2003 doesn't like talking to the
Project Summary for some reason - using zero as an index value seems to be a
no-no, even though using Recorder generates code that does just that).

Step through it in Debug mode and it works fine. Run the code and it
doesn't. I haven't been able to locate this as a known bug (but I've not been
looking for long - too many other fires to put out).

The code fragment (extract from a larger Sub()) that solved part of my
problem is:

Sub pbTestProject()

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

Dim pbTotalTasks, pbTaskCount, pbPredPointer As Long 'Set up sundry
variables

Set pbTasks = ActiveProject.Tasks 'Get current project's collection of
tasks

pbTotalTasks = pbTasks.Count 'Get the count of the tasks; this defines
the work to be done

SelectTaskColumn Column:="Flag1" 'Clear out the current settings for all
MRT entries in the current project

EditClear

'Begin work loop, count through all tasks (there are other operations to
be performed too, not shown here):

For pbTaskCount = 1 To pbTotalTasks

'Test for milestone

If pbTasks(pbTaskCount).Milestone = True Then

pbTasks(pbTaskCount).Flag1 = "Yes"

If Not pbTasks(pbTaskCount).PredecessorTasks Is Nothing Then

Set pbPredecessor = pbTasks(pbTaskCount).PredecessorTasks

For Each pbItem In pbPredecessor

pbPredPointer = pbItem.ID

pbTasks(pbPredPointer).Flag1 = "Yes"

Next pbItem

End If

End If

Next pbTaskCount

End Sub

No parsing required, which makes my life easier :)

The milestones are flagged as is as any task that is a Predecessor of a
milestone, which is what I needed. The code can be re-used for an embedded
project by making the project active, I think. I'll get some time to work on
that later. But for now I'm happy :)

I gleaned useful info and inspiration from various sources including Jack
Dalgren's excellent resources, for which I am very grateful. I didn't make
the deadline but then other catastrophes intervened that gave me a good
excuse :)

Many thanks to all - keep up the excellent work.

And Happy New Year!

Best,

Peter
Peter,
Boy, it's been so long I forgot what the goal is. At any rate I'm glad
you got something that seems to work for you. I have just a few comments
on your code.

1. The following dimension statement only dimensions the last variable
as long, the others will all be variant
Dim var1, var2, var3 as long
Each variable must be individually dimensioned, for example,
Dim var1 as long, var2 as long, var3 as long

2. You do not need to run your loop using the Count property. Since you
previously selected the task column, all tasks in the current view are
still selected. You could use the following loop structure
For each pbtask in ActiveSelection.Tasks

3. You used an, If Not [something] Is Nothing Then, to avoid tasks with
no predecessors. That's one way to do it but you don't really need it at
that location in the code, but you should have that error trap in the
main loop. The following loop construct will get what you need a little
more efficiently, is a little more robust, and works directly on a
master file (no need to activate each subproject separately). By the
way, this construct also allows you to do whatever you need to do with
the Project Summary Task fields because if the Project Summary Task is
displayed, it will be the first task in the active selection.

Sub Check_Preds()
Dim t As Task
Dim ptx As Task
Dim pt As Tasks
OutlineShowTasks expandinsertedprojects:=True
SelectTaskColumn
For Each t In ActiveSelection.Tasks
If Not t Is Nothing Then
If t.Milestone = True Then
t.Flag1 = True
Set pt = t.PredecessorTasks
For Each ptx In pt
ptx.Flag1 = True
Next ptx
End If
End If
Next t

End Sub

John
Project MVP
 
J

John

Peter,
My further comments are shown in-line
Hi John

Thanks for the critique - I'll get some time hopefully later to go through
in detail, but just to address a couple of points:
You're welcome and thanks for the feedback.
I hacked this bit of code out of a more complex macro (no need to anger my
client by placing their work in public :)) so inevitably despite my best
efforts some incongruities will arise.

My DIMs originally were one per line for clarity; I concatenated the three
Longs into one for convenience, not realising that they would be treated
differently. Oops. Thanks for that info! Useful to know.
I actually didn't realize this myself until mid last year even though
I've been writing VBA for many years. We can all learn something.
I went with the Count to make sure that every task was addressed (and so I
could audit the process; a physical change log is created in the process); in
future I may well use For Each as I did for the predecessors (as long as
control over the sequence can be exerted). Thanks for that too.
The "For Each..." will address every task also and the process can
always be "audited". But, as I said, your approach is fine.
My If...Nothing test is I think in the right place - there are milestones
with no predecessors, but the milestones still need to be flagged. Tasks that
are not milestones but which have predecessors don't need to be flagged, and
neither do their predecessors.
For your construct, the "If Not...Nothing Then" is correct. However, you
ALSO need to have a similar statement just after the "For
pbTaskCount..." since there may be blank task lines in the file. If
there are blank lines, your code, as written, will generate a run time
error.
Nice bit of tight coding - and I guess it takes care of embedded projects,
too, with which I've been wrestling (there are some really screwy aspects to
the object model, or maybe it's just M$ and their implementation of the
code). Odd that the SubProject object doesn't possess the same attributes as
the Project object...
Well for the most part, it does - you just have to know how to work with
it (see below for an example).
However, I need to let the user know (i) whether there are embedded projects
and (ii) if so, what they are (there's a possible requirement to selectively
exclude certain embedded projects from the process), so I may stick with the
direction in which I'm heading for that aspect.
There are a couple different ways to detect and address subprojects in a
master. It is very easy to detect subprojects. For example the following
will work,
NumSubp = ActiveProject.Subprojects.Count

This code uses the above and then fills an array with the names of the
subprojects,
Sub subp()
Dim sp As Subproject
Dim spNam() As String
Dim NumSp As Integer, i As Integer
'keep the read only pop-up from displaying if master is collapsed
DisplayAlerts = False
NumSp = activeproject.Subprojects.count
ReDim spNam(NumSp)
i = 1
For Each sp In activeproject.Subprojects
spNam(i) = sp.SourceProject.Name
i = i + 1
Next sp

End Sub

Hope this helps even further.
John
Project MVP
John said:
Ancient Brit said:
Well, it's taken an age to get back to this - other priorities took over
(including a system failure that refuses to be resolved - can you say
"manual
editing of the MBR required"? :))

Anyway, I did get an interim solution that works well enough but doesn't
address the embedded project for now (although I know how to do that) -
quick
n' dirty code extract below - and in the process came across a weird bug.
If
I step through an action it processes perfectly; if I Run, it doesn't
(nothing happens):

SelectTaskField Row:=0, Column:="Flag1"
SetTaskField Field:="Flag1", Value:="Yes"

This sets the Project Summary Flag1 entry (the summary is set to be
viewed,
a user-defined column named MRT containing values for Flag1 is visible)
to
the same value as others in the project (MSP2003 doesn't like talking to
the
Project Summary for some reason - using zero as an index value seems to
be a
no-no, even though using Recorder generates code that does just that).

Step through it in Debug mode and it works fine. Run the code and it
doesn't. I haven't been able to locate this as a known bug (but I've not
been
looking for long - too many other fires to put out).

The code fragment (extract from a larger Sub()) that solved part of my
problem is:

Sub pbTestProject()

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

Dim pbTotalTasks, pbTaskCount, pbPredPointer As Long 'Set up sundry
variables

Set pbTasks = ActiveProject.Tasks 'Get current project's collection
of
tasks

pbTotalTasks = pbTasks.Count 'Get the count of the tasks; this
defines
the work to be done

SelectTaskColumn Column:="Flag1" 'Clear out the current settings for
all
MRT entries in the current project

EditClear

'Begin work loop, count through all tasks (there are other operations
to
be performed too, not shown here):

For pbTaskCount = 1 To pbTotalTasks

'Test for milestone

If pbTasks(pbTaskCount).Milestone = True Then

pbTasks(pbTaskCount).Flag1 = "Yes"

If Not pbTasks(pbTaskCount).PredecessorTasks Is Nothing Then

Set pbPredecessor = pbTasks(pbTaskCount).PredecessorTasks

For Each pbItem In pbPredecessor

pbPredPointer = pbItem.ID

pbTasks(pbPredPointer).Flag1 = "Yes"

Next pbItem

End If

End If

Next pbTaskCount

End Sub

No parsing required, which makes my life easier :)

The milestones are flagged as is as any task that is a Predecessor of a
milestone, which is what I needed. The code can be re-used for an
embedded
project by making the project active, I think. I'll get some time to work
on
that later. But for now I'm happy :)

I gleaned useful info and inspiration from various sources including Jack
Dalgren's excellent resources, for which I am very grateful. I didn't
make
the deadline but then other catastrophes intervened that gave me a good
excuse :)

Many thanks to all - keep up the excellent work.

And Happy New Year!

Best,

Peter
Peter,
Boy, it's been so long I forgot what the goal is. At any rate I'm glad
you got something that seems to work for you. I have just a few comments
on your code.

1. The following dimension statement only dimensions the last variable
as long, the others will all be variant
Dim var1, var2, var3 as long
Each variable must be individually dimensioned, for example,
Dim var1 as long, var2 as long, var3 as long

2. You do not need to run your loop using the Count property. Since you
previously selected the task column, all tasks in the current view are
still selected. You could use the following loop structure
For each pbtask in ActiveSelection.Tasks

3. You used an, If Not [something] Is Nothing Then, to avoid tasks with
no predecessors. That's one way to do it but you don't really need it at
that location in the code, but you should have that error trap in the
main loop. The following loop construct will get what you need a little
more efficiently, is a little more robust, and works directly on a
master file (no need to activate each subproject separately). By the
way, this construct also allows you to do whatever you need to do with
the Project Summary Task fields because if the Project Summary Task is
displayed, it will be the first task in the active selection.

Sub Check_Preds()
Dim t As Task
Dim ptx As Task
Dim pt As Tasks
OutlineShowTasks expandinsertedprojects:=True
SelectTaskColumn
For Each t In ActiveSelection.Tasks
If Not t Is Nothing Then
If t.Milestone = True Then
t.Flag1 = True
Set pt = t.PredecessorTasks
For Each ptx In pt
ptx.Flag1 = True
Next ptx
End If
End If
Next t

End Sub

John
Project MVP
:

Hi John

Hi John

My apologies - once you indicated that the query properly
belonged
here,
I
transferred to this group. I did wonder why you'd continued in
the
other
group...
<snip>

Peter,
I responded in the main newsgroup because I also answer VBA
questions
and you had already posted in the main group, so.... while I was
there.

All I'm saying is that for future reference it is better to post in
the
most appropriate group, and for VBA issues that is this group (i.e.
developer).

Hope you get rested.

Understood. My online life began in the late 80s/early 90s in
Usenet/Netnews
so I know what you mean. Folks were somewhat unforgiving if you
posted in
the
wrong group, even innocently. I wasn't initially convinced that VBA
was
the
only way to go, which is why I didn't post here first (and didn't
spam
all
groups simultaneously).

I got rest, thanks. Although one would always want more...

I took a look at the TaskDependency Object and I have a hunch that in
the
long term it would be the better way to go but for a quick and dirty
(well,
so much for quick) solution I like the idea of parsing the
predecessors
in
order to set Flag1 appropriately. Since this will also be visible in
the
additional column I've added that's useful for those viewing the
results
(a
little positive reinforcement always goes down well with senior
management
:))

I did a quick look around for the macro you said you had produced but
couldn't locate it immediately - can I play dumb and ask for a URL,
please?
:) Ordinarily I'm an advocate of LBD (learning by doing) but for now
:I
:have
to make do with SSEI (stealing someone else's ideas)...

Sorry - not stealing. Employing re-usable code.

I realize that I'm going to have to make sure that the entire project
(including the embedded project) is fully expanded before the work
starts, so
that's something else to consider.

Best,

Peter

Peter,
Don't worry about the posting. I think we've spent enough time on that
and you obviously understand our newsgroup "groundrules".

The macro I referred to is not available on any website - at least it
better not be. I don't have a website of handy dandy Project VBA macros
like fellow MVP, Jack Dahlgren, although at one point in the past I did
consider creating one.

The macro is only available directly from me and it is not freeware. It
does quite a bit more than you need. All you really need is to parse
through the predecessor list and then use the Find Method for each
predecessor. Set the desired flag on the found predecessor task and go
to the next predecessor or task. If you are still interested in my
macro, even if only for the parsing algorithm, you can contact me at
the
address below.

John
Project MVP
jensenj6atatcomcastdotdotnet
(remove obvious redundancies)
 
A

Ancient Brit

Hi John

A few more bits of feedback (also inline)...

John said:
Peter,
My further comments are shown in-line
You're welcome and thanks for the feedback.

No probs - I wish I had time to devote to learning a great deal more :)
I actually didn't realize this myself until mid last year even though
I've been writing VBA for many years. We can all learn something.

Yep - couldn't agree more. I first started becoming interested in computing
in around 1971, hand-coded my first paper tape disassembler (in octal) from a
minimal reference manual that listed a couple of dozen opcodes on one page,
and it's been downhill ever since :) There isn't a day goes by that I don't
add something to my arsenal - I'm about to dip my toes into the icy waters of
manual MBR editing to try and recover a recalcitrant system...

I've been tripping over some oddities in Project's VBA and if I get time I'd
like to air some of them here. For example, to help me track the process
visually I had the macro select each row of the project as it addressed each
in sequence.

Because I had an embedded project (still linked to the original file
elsewhere on the network) I expected that when the macro got to the next
index in the sequence it would "jump" over the embed - but it didn't. The row
numbers went 164, 165, 1, 2, 3... 92, 166, 167... and the selection continued
into the embed - i.e., after 165 instead of jumping to row 166, which lies on
the "far side" of the embed, it went to row 1 of the embed (which would
technically be the 166th row). Curious.
The "For Each..." will address every task also and the process can
always be "audited". But, as I said, your approach is fine.

I wasn't 100% sure that the For Each process would go through in numerical
order and I wanted to be absolutely certain (the Quality Engineer in me :))
which is another reason for going that route.
For your construct, the "If Not...Nothing Then" is correct. However, you
ALSO need to have a similar statement just after the "For
pbTaskCount..." since there may be blank task lines in the file. If
there are blank lines, your code, as written, will generate a run time
error.

That's what I thought would happen - but it didn't and I wasn't sure why.
For consistency and completeness I will include the test, and I think I know
why the runtime error didn't appear, but I will need to run some tests to be
sure.
Well for the most part, it does - you just have to know how to work with
it (see below for an example).

Some appear to be extremely convoluted, I notice. I'm away from the system
with a working copy of Project so I can't bring an example up, but I will do.
There are a couple different ways to detect and address subprojects in a
master. It is very easy to detect subprojects. For example the following
will work,
NumSubp = ActiveProject.Subprojects.Count

This code uses the above and then fills an array with the names of the
subprojects,
Sub subp()
Dim sp As Subproject
Dim spNam() As String
Dim NumSp As Integer, i As Integer
'keep the read only pop-up from displaying if master is collapsed
DisplayAlerts = False
NumSp = activeproject.Subprojects.count
ReDim spNam(NumSp)
i = 1
For Each sp In activeproject.Subprojects
spNam(i) = sp.SourceProject.Name
i = i + 1
Next sp

End Sub

Hope this helps even further.

It does - thank you. I did something similar but added a count (so: 1) X,
2), Y, 3) Z... with a cr/lf where the commas are) and placed the results in a
Msgbox for the user to decide whether to proceed or not.

Much appreciated - always grateful for people taking time to put something
of value together for my benefit.

Best,

Peter
John
Project MVP
John said:
Well, it's taken an age to get back to this - other priorities took over
(including a system failure that refuses to be resolved - can you say
"manual
editing of the MBR required"? :))

Anyway, I did get an interim solution that works well enough but doesn't
address the embedded project for now (although I know how to do that) -
quick
n' dirty code extract below - and in the process came across a weird bug.
If
I step through an action it processes perfectly; if I Run, it doesn't
(nothing happens):

SelectTaskField Row:=0, Column:="Flag1"
SetTaskField Field:="Flag1", Value:="Yes"

This sets the Project Summary Flag1 entry (the summary is set to be
viewed,
a user-defined column named MRT containing values for Flag1 is visible)
to
the same value as others in the project (MSP2003 doesn't like talking to
the
Project Summary for some reason - using zero as an index value seems to
be a
no-no, even though using Recorder generates code that does just that).

Step through it in Debug mode and it works fine. Run the code and it
doesn't. I haven't been able to locate this as a known bug (but I've not
been
looking for long - too many other fires to put out).

The code fragment (extract from a larger Sub()) that solved part of my
problem is:

Sub pbTestProject()

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

Dim pbTotalTasks, pbTaskCount, pbPredPointer As Long 'Set up sundry
variables

Set pbTasks = ActiveProject.Tasks 'Get current project's collection
of
tasks

pbTotalTasks = pbTasks.Count 'Get the count of the tasks; this
defines
the work to be done

SelectTaskColumn Column:="Flag1" 'Clear out the current settings for
all
MRT entries in the current project

EditClear

'Begin work loop, count through all tasks (there are other operations
to
be performed too, not shown here):

For pbTaskCount = 1 To pbTotalTasks

'Test for milestone

If pbTasks(pbTaskCount).Milestone = True Then

pbTasks(pbTaskCount).Flag1 = "Yes"

If Not pbTasks(pbTaskCount).PredecessorTasks Is Nothing Then

Set pbPredecessor = pbTasks(pbTaskCount).PredecessorTasks

For Each pbItem In pbPredecessor

pbPredPointer = pbItem.ID

pbTasks(pbPredPointer).Flag1 = "Yes"

Next pbItem

End If

End If

Next pbTaskCount

End Sub

No parsing required, which makes my life easier :)

The milestones are flagged as is as any task that is a Predecessor of a
milestone, which is what I needed. The code can be re-used for an
embedded
project by making the project active, I think. I'll get some time to work
on
that later. But for now I'm happy :)

I gleaned useful info and inspiration from various sources including Jack
Dalgren's excellent resources, for which I am very grateful. I didn't
make
the deadline but then other catastrophes intervened that gave me a good
excuse :)

Many thanks to all - keep up the excellent work.

And Happy New Year!

Best,

Peter
Peter,
Boy, it's been so long I forgot what the goal is. At any rate I'm glad
you got something that seems to work for you. I have just a few comments
on your code.

1. The following dimension statement only dimensions the last variable
as long, the others will all be variant
Dim var1, var2, var3 as long
Each variable must be individually dimensioned, for example,
Dim var1 as long, var2 as long, var3 as long

2. You do not need to run your loop using the Count property. Since you
previously selected the task column, all tasks in the current view are
still selected. You could use the following loop structure
For each pbtask in ActiveSelection.Tasks

3. You used an, If Not [something] Is Nothing Then, to avoid tasks with
no predecessors. That's one way to do it but you don't really need it at
that location in the code, but you should have that error trap in the
main loop. The following loop construct will get what you need a little
more efficiently, is a little more robust, and works directly on a
master file (no need to activate each subproject separately). By the
way, this construct also allows you to do whatever you need to do with
the Project Summary Task fields because if the Project Summary Task is
displayed, it will be the first task in the active selection.

Sub Check_Preds()
Dim t As Task
Dim ptx As Task
Dim pt As Tasks
OutlineShowTasks expandinsertedprojects:=True
SelectTaskColumn
For Each t In ActiveSelection.Tasks
If Not t Is Nothing Then
If t.Milestone = True Then
t.Flag1 = True
Set pt = t.PredecessorTasks
For Each ptx In pt
ptx.Flag1 = True
Next ptx
End If
End If
Next t

End Sub

John
Project MVP


:

Hi John

Hi John

My apologies - once you indicated that the query properly
belonged
here,
I
transferred to this group. I did wonder why you'd continued in
the
other
group...
<snip>

Peter,
I responded in the main newsgroup because I also answer VBA
questions
and you had already posted in the main group, so.... while I was
there.

All I'm saying is that for future reference it is better to post in
the
most appropriate group, and for VBA issues that is this group (i.e.
developer).

Hope you get rested.

Understood. My online life began in the late 80s/early 90s in
Usenet/Netnews
so I know what you mean. Folks were somewhat unforgiving if you
posted in
the
wrong group, even innocently. I wasn't initially convinced that VBA
was
the
only way to go, which is why I didn't post here first (and didn't
spam
all
groups simultaneously).

I got rest, thanks. Although one would always want more...

I took a look at the TaskDependency Object and I have a hunch that in
the
long term it would be the better way to go but for a quick and dirty
(well,
so much for quick) solution I like the idea of parsing the
predecessors
 
J

John

Peter,
More comments (boy this is getting to be one complex thread) :)
Yep - couldn't agree more. I first started becoming interested in computing
in around 1971, hand-coded my first paper tape disassembler (in octal) from a
minimal reference manual that listed a couple of dozen opcodes on one page,
and it's been downhill ever since :) There isn't a day goes by that I don't
add something to my arsenal - I'm about to dip my toes into the icy waters of
manual MBR editing to try and recover a recalcitrant system...
My first foray into programming was in college. It was Fortran coded up
on punch cards. The world of programming has changed, believe it or not
:) Project VBA can be challenging but very rewarding once you get the
hang of it. Fellow MVP, Rod Gill, has a book specifically devoted to
Project VBA. For more information, go to, http://www.projectvbabook.com.
I've been tripping over some oddities in Project's VBA and if I get time I'd
like to air some of them here. For example, to help me track the process
visually I had the macro select each row of the project as it addressed each
in sequence.
Feel free, that's what this forum is for. Unfortunately there are
several skeletons in the Project Object Browser and they don't get fixed
with each new release of Project, but such is life.
Because I had an embedded project (still linked to the original file
elsewhere on the network) I expected that when the macro got to the next
index in the sequence it would "jump" over the embed - but it didn't. The row
numbers went 164, 165, 1, 2, 3... 92, 166, 167... and the selection continued
into the embed - i.e., after 165 instead of jumping to row 166, which lies on
the "far side" of the embed, it went to row 1 of the embed (which would
technically be the 166th row). Curious.
Nothing curious here. In a dynamically consolidated master, the
subprojects are NOT actually in the master file, rather, the master
contains pointers to the actual subproject. That's why you see the IDs
repeat and that's why trying to use IDs to track tasks in a dynamic
master is an exercise in frustration.
I wasn't 100% sure that the For Each process would go through in numerical
order and I wanted to be absolutely certain (the Quality Engineer in me :))
which is another reason for going that route.
Well I'll tell you, it absolutely will go through all tasks, more or
less depending on how the loop is set up. With the ActiveSelection
approach, the loop will go through ALL tasks that are visible and
selected in the current view - absolutely!
That's what I thought would happen - but it didn't and I wasn't sure why.
For consistency and completeness I will include the test, and I think I know
why the runtime error didn't appear, but I will need to run some tests to be
sure.
Well, it may be that there are no blank lines in your files. I never use
them but some people just seem to like those spaces between groups of
tasks in their file so I always include the error detection in macros I
write, unless, I have applied a filter and used the ActiveSelection loop
format. Then I don't need to worry about blank task lines.
Some appear to be extremely convoluted, I notice. I'm away from the system
with a working copy of Project so I can't bring an example up, but I will do.
Yes, they can be involved. Sometimes you need to think outside the bun,
I mean box, to get the data you want.
It does - thank you. I did something similar but added a count (so: 1) X,
2), Y, 3) Z... with a cr/lf where the commas are) and placed the results in a
Msgbox for the user to decide whether to proceed or not.

Much appreciated - always grateful for people taking time to put something
of value together for my benefit.
Again, you're welcome.

John
 
A

Ancient Brit

Hi John

John said:
Peter,
More comments (boy this is getting to be one complex thread) :)

My first foray into programming was in college. It was Fortran coded up
on punch cards. The world of programming has changed, believe it or not
:) Project VBA can be challenging but very rewarding once you get the
hang of it. Fellow MVP, Rod Gill, has a book specifically devoted to
Project VBA. For more information, go to, http://www.projectvbabook.com.

Thanks for that - I did, and I'll be making an investment :)

If Rod's reading this thread he might like to know that there's a bad link
on the page http://www.projectvbabook.com/projectvbaprogrammingbook/index.htm
- there's an "r" missing from the URL behind the graphic of the book.

I have chunks of VBA in my skillmix - mostly Excel (VBA3, which isn't much
good these days :)), a smattering of Word and a tad of Access, and now
Project's aspiring to be a tad in a month or two :)
Feel free, that's what this forum is for. Unfortunately there are
several skeletons in the Project Object Browser and they don't get fixed
with each new release of Project, but such is life.
Nothing curious here. In a dynamically consolidated master, the
subprojects are NOT actually in the master file, rather, the master
contains pointers to the actual subproject. That's why you see the IDs
repeat and that's why trying to use IDs to track tasks in a dynamic
master is an exercise in frustration.

Understood about the repeating IDs - my probable misunderstanding lies in
the expectation that Select would have followed the sequence of IDs for the
active project, skipping over the IDs belonging to the embedded subproject.
IME such a behavior would be considered a bug.

For example, this works as expected:

pbTasks(pbPredPointer).Flag1 = "Yes"

if pbPredPointer points to a task in the active project.

But:

SelectRow Row:=pbPredPointer, RowRelative:=False

acts on a different task for the same value of pbPredPointer. You see my
confusion?
Well I'll tell you, it absolutely will go through all tasks, more or
less depending on how the loop is set up. With the ActiveSelection
approach, the loop will go through ALL tasks that are visible and
selected in the current view - absolutely!

I'm sure it does go through every task - just not sure that it will go
through in a sequence that allows the ready identification of an omission.
If, for example, For Each... goes through all tasks in the order in which
they were originally entered into the project (i.e. not in index order) that
would make a visual examination of a change log more of an effort. A
numerical sequence is much easier to examine visually and spot an omission.
It's not a biggie - just me being anal. :)
Well, it may be that there are no blank lines in your files. I never use
them but some people just seem to like those spaces between groups of
tasks in their file so I always include the error detection in macros I
write, unless, I have applied a filter and used the ActiveSelection loop
format. Then I don't need to worry about blank task lines.

The current embedded subproject has such spaces, but on investigation the
main project doesn't (and I'm with you on the use of spaces). So I inserted a
new task, kept it blank, and ran the macro. No runtime error. I'll look into
this more deeply when I get a chance.
Yes, they can be involved. Sometimes you need to think outside the bun,
I mean box, to get the data you want.

One example is the name of a subproject:

ActiveProject.Subprojects.Item(index).SourceProject

compared with:

Projects(index).FullName

Why not just Subprojects(index).FullName?

It would make coding for some aspects (for me, obviously; YMMV) so much
easier if the same attributes could be accessed using the same convention.
Oh, well.
Again, you're welcome.

John

Appreciated, again :)

Best,

Peter
 
J

John

Peter,
Oh man, my screen is screaming with "thread flow", but, let's press on.
I guess it's not too bad since each new reply to the existing thread
shows up in black while the previous portion of the thread is grey, at
least on my newsreader. I'd just hate to have to go back through
everything at a later date and try to follow it all.
Hi John



Thanks for that - I did, and I'll be making an investment :)

If Rod's reading this thread he might like to know that there's a bad link
on the page http://www.projectvbabook.com/projectvbaprogrammingbook/index.htm
- there's an "r" missing from the URL behind the graphic of the book.
Perhaps Rod will read this but I'll be honest with you, if I had seen
this complex thread and one of the other MVPs was the principal
responder, I would just pass it up. It probably looks way to formidable
to jump into midstream. I don't have a problem with the link for Rod's
book - it works fine for me (I use a Safari browser on an iMac - yeah,
I'm one of those guys).
I have chunks of VBA in my skillmix - mostly Excel (VBA3, which isn't much
good these days :)), a smattering of Word and a tad of Access, and now
Project's aspiring to be a tad in a month or two :)


Understood about the repeating IDs - my probable misunderstanding lies in
the expectation that Select would have followed the sequence of IDs for the
active project, skipping over the IDs belonging to the embedded subproject.
IME such a behavior would be considered a bug.

For example, this works as expected:

pbTasks(pbPredPointer).Flag1 = "Yes"

if pbPredPointer points to a task in the active project.

But:

SelectRow Row:=pbPredPointer, RowRelative:=False

acts on a different task for the same value of pbPredPointer. You see my
confusion?
Sure, it is real easy to get confused with this stuff. All you have to
remember is that when using foreground processing (i.e. selection
oriented), the indexing is with respect to the visible display AND the
row index is NOT the ID, but the displayed row number. For example, if
the display happens to be filtered or sorted such that the first visible
row is actually ID 3, then using 3 as the row argument value in the
SelectRow Method, will get you the task that's on the third row, not
task ID 3. Using background processing (i.e. operating directly on
Project's objects) WILL follow the ID sequence because it is independent
of any view that might be displayed.
I'm sure it does go through every task - just not sure that it will go
through in a sequence that allows the ready identification of an omission.
If, for example, For Each... goes through all tasks in the order in which
they were originally entered into the project (i.e. not in index order) that
would make a visual examination of a change log more of an effort. A
numerical sequence is much easier to examine visually and spot an omission.
It's not a biggie - just me being anal. :)
Actually a For Each... loop goes through the current ID sequence, not
the Unique ID sequence, which is the original sequence of how tasks were
entered. But, you are apparently more comfortable using your approach,
so go for it.
The current embedded subproject has such spaces, but on investigation the
main project doesn't (and I'm with you on the use of spaces). So I inserted a
new task, kept it blank, and ran the macro. No runtime error. I'll look into
this more deeply when I get a chance.


One example is the name of a subproject:

ActiveProject.Subprojects.Item(index).SourceProject

compared with:

Projects(index).FullName

Why not just Subprojects(index).FullName?
Because, the code is operating on the current active project. The only
way to access the subprojects is via indirect reference (i.e. through
the master). As an alternative you could open the subproject, activate
it and then work directly with that project's objects.
It would make coding for some aspects (for me, obviously; YMMV) so much
easier if the same attributes could be accessed using the same convention.
Oh, well.
Are we getting there?

John
Project MVP
 
A

Ancient Brit

Hi John

John said:
Peter,
Oh man, my screen is screaming with "thread flow", but, let's press on.
I guess it's not too bad since each new reply to the existing thread
shows up in black while the previous portion of the thread is grey, at
least on my newsreader. I'd just hate to have to go back through
everything at a later date and try to follow it all.

It could be something to keep you occupied in your retirement on those cold
winter nights :)
Perhaps Rod will read this but I'll be honest with you, if I had seen
this complex thread and one of the other MVPs was the principal
responder, I would just pass it up. It probably looks way to formidable
to jump into midstream. I don't have a problem with the link for Rod's
book - it works fine for me (I use a Safari browser on an iMac - yeah,
I'm one of those guys).

Actually, I'm a Mackie as well - although my poor beast had to be left
behind 12 years ago when I trekked to the US to become shackled - I mean
married - and has since been abused by some friend of a family member (now no
longer a friend :))

However... Even a Safari browser isn't smart enough to work out that
"http://www.projectseverbooks.com/" should be
"http://www.projectserverbooks.com/" :)

I'll write to Rod and let him know. Other pages have the same graphic and
the correct link - just not the one above. It's not a biggie unless you don't
have the core knowledge to understand why the link doesn't work.
Sure, it is real easy to get confused with this stuff. All you have to
remember is that when using foreground processing (i.e. selection
oriented), the indexing is with respect to the visible display AND the
row index is NOT the ID, but the displayed row number. For example, if
the display happens to be filtered or sorted such that the first visible
row is actually ID 3, then using 3 as the row argument value in the
SelectRow Method, will get you the task that's on the third row, not
task ID 3. Using background processing (i.e. operating directly on
Project's objects) WILL follow the ID sequence because it is independent
of any view that might be displayed.

Ah, well, thence my confusion - if the row value wasn't the same as the
index I'd expect it to renumber upon filtering, but it doesn't. So I figured
that index and row number were synonymous (tempered by probably an indicator
showing whether the task in question was in the main project or a subproject
- such as a filename +/- a path, for example).

Where it really gets confusing for me is when the Predecessor value doesn't
match what Project says it's accessing (I seem to recall reading somewhere
that the IDs are "x mod y" or something, but it's not too important. As long
as Project VBA knows what it's doing :)
Actually a For Each... loop goes through the current ID sequence, not
the Unique ID sequence, which is the original sequence of how tasks were
entered. But, you are apparently more comfortable using your approach,
so go for it.
Because, the code is operating on the current active project. The only
way to access the subprojects is via indirect reference (i.e. through
the master). As an alternative you could open the subproject, activate
it and then work directly with that project's objects.

I thought that's what happened when I targeted a subproject - as in
ActiveProject.Subprojects... but apparently not. However, your use of
OutlineShowTasks expandinsertedprojects:=True works well when I'm aiming to
process everything in sight :)
Are we getting there?

Yep, I think so. I'm just waiting for the next client meeting when the scope
will creep :)

Best,

Peter
 
J

John

Ancient Brit said:
Hi John



It could be something to keep you occupied in your retirement on those cold
winter nights :)


Actually, I'm a Mackie as well - although my poor beast had to be left
behind 12 years ago when I trekked to the US to become shackled - I mean
married - and has since been abused by some friend of a family member (now no
longer a friend :))

However... Even a Safari browser isn't smart enough to work out that
"http://www.projectseverbooks.com/" should be
"http://www.projectserverbooks.com/" :)

I'll write to Rod and let him know. Other pages have the same graphic and
the correct link - just not the one above. It's not a biggie unless you don't
have the core knowledge to understand why the link doesn't work.


Ah, well, thence my confusion - if the row value wasn't the same as the
index I'd expect it to renumber upon filtering, but it doesn't. So I figured
that index and row number were synonymous (tempered by probably an indicator
showing whether the task in question was in the main project or a subproject
- such as a filename +/- a path, for example).

Where it really gets confusing for me is when the Predecessor value doesn't
match what Project says it's accessing (I seem to recall reading somewhere
that the IDs are "x mod y" or something, but it's not too important. As long
as Project VBA knows what it's doing :)


I thought that's what happened when I targeted a subproject - as in
ActiveProject.Subprojects... but apparently not. However, your use of
OutlineShowTasks expandinsertedprojects:=True works well when I'm aiming to
process everything in sight :)


Yep, I think so. I'm just waiting for the next client meeting when the scope
will creep :)

Best,

Peter
Peter,
Yeah that "client requirement creep" is a blast :)

Good luck in your further efforts.
John
Project MVP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top