如何在主项目中选择子项目任务的行?

3

我有一个总项目,里面有几个子项目。

我想根据字段 Text5 的值来设置行的颜色。

当前问题:如何使用VBA代码引用第二个子项目中的行。 当我运行代码并修改子项目2中任务ID 5(在Text5)的值时,它会修改子项目1中任务ID 5的颜色。

我该如何使用SelectRow并添加对所需子项目的引用?

我的代码(相关部分)

Sub FormatChangedTasks()

Dim SubPrj      As Subproject
Dim Tsk         As Task
Dim i           As Long

For Each SubPrj In ActiveProject.Subprojects
    ' compare the name of Sub-Project with the one saved in the "Stack" srray
    If SubPrj.SourceProject.Name = ModifiedPrjName Then
        For Each Tsk In SubPrj.SourceProject.Tasks
            If Not Tsk Is Nothing Then
                i = Tsk.ID

                ' check if Tsk.Text5 value has changed from value in "StatusStackArr" array
                If StatusStackArr(i - 1).StatusOldVal <> Tsk.Text5 Then
                    ' **** at the line below it selects the Row from the top
                    ' (not the desired Sub-Project) ******
                    SelectRow Row:=i, RowRelative:=False

                    ' --format entire row --
                    Select Case Tsk.Text5 ' Get the Field's used field, not name
                        Case "R", "Y", "G"
                            FontEx CellColor:=7, Color:=0
                            FontEx Italic:=False '  Font regular

                        Case "Complete"
                            FontEx Italic:=True '  Font Italic
                            FontEx CellColor:=15, Color:=14 ' Background Silver ; font Gray

                    End Select

               ' rest of code (un-relevant)
1个回答

1

挑战 — 格式化主项目中的行

要在表格中格式化文本,请使用FontEx方法。该方法用于格式化活动(已选)单元格。要选择要进行格式化的行,请使用SelectRow方法。要使用此方法,您需要知道:

  1. 相对于活动选择的位置,或
  2. 可见任务中的绝对位置,或
  3. 根据唯一标识符查找任务

对于选项 1 和 2,由于过滤器或折叠摘要隐藏了任务,因此必须相应地调整SelectRow方法的行参数。很难知道哪些任务可能被隐藏。使用此方法的最佳方式是首先确保所有任务都是可见的(请参见代码)。

此外,在处理子项目时,要计算绝对行位置是一项挑战,因为首先需要获取较早排程的子项目任务数和主项目本身的任何原生任务数量(尽管这是不典型的)。
所有这些都导致使用“查找”方法,选项3作为选择主项目中任务的最佳方法。要选择确切的任务,则必须使用带有唯一字段的查找方法。唯一ID字段是唯一保证的字段。
主项目内的唯一ID
当任务添加到项目中时,会分配一个递增的唯一ID,从1开始。当多个项目合并到主项目中时,通过添加种子值来更改唯一ID,以便在主项目中没有重复项。
种子值基于内部子项目“索引”而确定。第一个子项目的任务被赋予4194304的种子值,第二个子项目的任务具有8388608的种子值(4194304 * 2),依此类推。

如果从主项目中删除子项目,则其“索引”不会被重新使用。同样,如果在主项目中重新排列子项目,则“索引”值不会更改。因此,您不能使用子项目对象的Index属性来获取用于创建种子的内部“索引”值,因为该属性仅指示子项目的顺序。(请注意,有一种方法可以获取此内部值,但这超出了本问题的范围。另外需要知道的是,它还需要选择所有任务。)

解决方案

要在用户界面中选择任务,您需要知道它在主计划中的唯一ID。如果通过SourceProject.Tasks方法访问任务,则将访问其原生子项目中的任务,唯一ID将不包括种子值。例如,唯一ID可能是2,这在主项目中并不唯一,因此不足以使用Find方法选择任务。

由于您已经在循环遍历日程表中的所有任务,因此确定主唯一ID的最简单方法是通过在主项目中本地循环遍历所有任务。为此,请选择所有任务并循环遍历所选项。

Sub FormatChangedTasks()

' show all tasks
FilterClear
SelectAll
SummaryTasksShow (0)
OutlineShowAllTasks

Dim AllTasks As Tasks
Set AllTasks = ActiveSelection.Tasks

Dim Tsk As Task

For Each Tsk In AllTasks
    If Not Tsk Is Nothing Then
        ' compare the name of Sub-Project with the one saved in the "Stack" srray
        If Tsk.Project = ModifiedPrjName Then

            ' check if Tsk.Text5 value has changed from prior value
            ' NOTE: use a dictionary here instead of an array
            If StatusStackArr(i - 1).StatusOldVal <> Tsk.Text5 Then

                Find "Unique ID", "equals", Tsk.UniqueID
                SelectRow

                ' --format entire row --
                Select Case Tsk.Text5 ' Get the Field's used field, not name
                    Case "R", "Y", "G"
                        FontEx CellColor:=7, Color:=0
                        FontEx Italic:=False '  Font regular

                    Case "Complete"
                        FontEx Italic:=True '  Font Italic
                        FontEx CellColor:=15, Color:=14 ' Background Silver ; font Gray

                End Select

            ' rest of code (un-relevant)
        End If
    End If
Next Tsk
End Sub

注:

  • 除非您可以保证计划已完全展开并选择选项1或2,否则选择所有任务是必需的。选择所有任务将花费一些时间,具有10-15个子项目,但其余的代码将以接近相同的速度运行。
  • 如果任务被分组或以其他方式未按任务ID排序,则选项1或2的所有赌注都将失效。
  • 使用按任务ID索引的数组存储先前的值在主项目中效果不佳。相反,使用以主唯一ID为键的集合或字典存储先前的值。请参阅此SO帖子,了解如何在VBA中使用字典。

1
感谢您提供详细的答案。有没有一种方法可以使用“查找唯一ID”方法,然后在不通过选择循环的情况下转到该行?我不喜欢选择所有任务,它会减慢代码运行时间,并且在屏幕上显示不好。主项目有时会有10-15个子项目,因此它会大大减慢代码运行时间。我只想循环修改过的任务的子项目。是否有这样的方法? - Shai Rado
@ShaiRado,请参考上面的编辑说明,了解为什么选择所有任务是不可避免的,以及为什么这并不是坏事。虽然它可能看起来像一个hack,就像一个糟糕的Excel宏,但实际上它并不是,特别是因为其他选择要么非常受限制,要么难以实现,或者两者都有。 - Rachel Hettinger
1
感谢您提供如此详细的答案。我已经开始计算每个子项目的行数和一些漂亮的数学问题。但是,我将在明天(以色列时间)尝试您的解决方案,并查看响应时间是否可接受。如果您还清醒着,"主唯一标识符"是否与Task.UniqueID相同?还是有另一个属性? - Shai Rado
1
@ShaiRado,没有单独的唯一标识字段;当在主项目中查看任务时,任务的唯一标识是不同的。例如,在主项目中查看任务时,唯一标识可能是8388611,但如果直接打开该子项目,则任务唯一标识将为3(8388611 mod 4194304)。 - Rachel Hettinger
你很可能要去睡觉了,我无法正确保存UniqueID。我会发布一个新的,以免混淆未来的用户。 - Shai Rado
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接