65.9K
CodeProject 正在变化。 阅读更多。
Home

GtProject:GT 图形用户界面库的 C++ 项目管理控件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2017年3月2日

MIT

6分钟阅读

viewsIcon

12634

downloadIcon

580

GtProject 旨在为用户提供一个类似 Microsoft Project 的控件,用于安排任务的进度。

引言

GT 是一个紧凑、高效且可定制的图形用户界面 (GUI) 库,适用于 Windows 环境(未来还将添加 Linux 和 Mac)。大部分代码是平台无关的,仅直接依赖于操作系统图形、线程和剪贴板 API(这些功能已封装)。随着 GUI 系统的不断增长,你可能会问为什么要创建另一个系统。GT 的创建是为了解决一些主要竞争对手的不足之处,并且非常紧凑(GT 目前包含约 90,000 行代码,包括注释)。由于代码行数如此之少,GT 可以直接嵌入到你的应用程序解决方案或项目文件中。其主要竞争对手是 MFC、QT、GIMP Toolkit、wxWidgets、Fox Toolkit。GT 在设计和功能上最接近 QT。有关 GT 的更多信息,请阅读以下文章:

GtProject 是 GT 库的一个新添加项。作为一名工程师,我一直在我的应用程序中需要项目或任务管理功能。GtProject 旨在为用户提供一个类似 Microsoft Project 的控件,用于安排任务的进度。

GtProject 设计概述

代码库的主要组件如下:

  • GtProjectView 是用于查看 GtProjectModel 对象的主要视口控件。它包含一个用于控制模型的菜单、一个用于查看任务的树视图、一个用于标记时间的日期标尺控件,以及一个用于显示甘特图的视口。
  • GtProjectModel 是包含所有正在建模的任务的类。它能够使用 HPC Template Library (HTL) 序列化引擎对其自身进行序列化。有关 HTL 的更多信息,请参阅以下文章。原生存储格式是 XDL。
  • GtProjectTask 是主要任务对象。它提供任务的开始和结束日期,可以包含子任务,并与其他任务之间存在约束。
  • GtProjectConstraint 是两个任务之间的约束。下面显示了四种类型。在所有情况下,任务 A 都是约束的所有者。总的来说,它们将任务约束网络变成了一个有向无环图 (DAG)。
    • GtEndToBegin - 从任务 A 的结束到任务 B 的开始
    • GtBeginToEnd - 从任务 A 的开始到任务 B 的结束
    • GtBeginToBegin - 从任务 A 的开始到任务 B 的开始
    • GtEndToEnd - 从任务 A 的结束到任务 B 的结束

GtProjectView 看起来如下:

Using the Code

使用 GtProject 非常简单。在任何使用 GT 作为用户界面的应用程序中,将以下代码插入到打算作为电子表格父级的 GtDialogInitializeControls() 方法中。设置控件大小并将其添加到该对话框的子控件集合中。

//in header file
GtProjectView * m_ptrProject;

//in InitializeControls()
m_ptrProject = new GtProjectView(this);
rectNew.xMin = 0; rectNew.xMax = 900; rectNew.yMin = 0; rectNew.yMax = 650;
m_ptrProject->Set_objFrame(rectNew);
this->AddSubWidget(m_ptrProject);

与 GT 的其他控件一样,GtProjectView 是可嵌套的。因此,如果你想将其插入到选项卡页面、框架等中,也可以这样做。只需相应地设置父对象指针和 AddSubWidget 方法。例如,将项目查看器插入到框架中看起来是这样的:

//in InitializeControls()
m_ptrProject = new GtProjectView(m_ptrProjFrame);
rectNew.xMin = 0; rectNew.xMax = 900; rectNew.yMin = 0; rectNew.yMax = 650;
m_ptrProject->Set_objFrame(rectNew);
m_ptrProjFrame->AddSubWidget(m_ptrProject);

控件的菜单是**项目**和**任务**。**项目**菜单包含所有文档控件功能,如**新建**、**打开**、**保存**、**另存为**、**关闭**。**任务**菜单包含操作单个任务所需的所有命令。菜单项是**属性**、**添加任务**、**添加子任务**、**删除任务**和**删除所有任务**。添加和删除是显而易见的。任务属性会打开所选任务的属性编辑器,如下所示:

要编辑日期,可以直接在编辑框中输入,或者通过单击相应日期的“sel”按钮启动日期选择器。这将启动日历视图日期选择对话框(如下所示)。编辑器的下半部分用于创建和删除任务之间的约束。要添加约束,请单击**添加**按钮,在列表视图中选择它,然后单击“**Sel Target**”来选择与之相关的任务。单击**保存**以保存对约束的更改,然后再选择另一个进行编辑。

GtProject 如何工作(如何绘制甘特图)

GtProject 的核心是显示甘特图信息的可视化引擎。有必要讨论一下它的实现方式,以了解 GtProject 的工作原理。查看器的甘特图部分有三个主要组件:视口、日期标尺和水平滚动条。日期标尺负责在视口顶部显示时间的标记。它连接到水平滚动条,其限制根据日期标尺左上角的组合框设置为天、月或年的数量。根据当前的水平滚动位置,它确定可见的第一天、月或年。下面展示了基于月份计算的代码片段作为示例。

//set at timeline and cursor start
iYearStart = m_dtStart.Get_intYear();
iMonthStart = m_dtStart.Get_intMonth();

//advance to viewport start, iCursor is from the horizontal scrollbar position
for (i = 0; i < iCursor; i++)
{
    iMonthStart++;
    if (iMonthStart > 12)
    {
        iMonthStart = 1;
        iYearStart++;
    }
}

m_dtViewStart.Set_intYear(iYearStart);
m_dtViewStart.Set_intMonth(iMonthStart);

一旦确定了视口起始位置,标尺的 OnPaint() 算法就会在视口顶部以固定的间隔标记时间。Months 的增量被设定为每 150 像素一个月。接下来就是正确地在视口中绘制任务。为了实现这一点,首先要确定一个任务是否可见以供绘制。这是通过查询树视图来查看表示该任务的节点是否可见来完成的。如果任务可见,代码会获取该树节点的框架。该节点的 Y 值会被保留下来,以便与任务正确对齐。接下来,使用日期标尺中的一个实用函数 GetDatePos() 来计算该节点的 x 值。

//get the rect from the tree view node, then calculate task position in viewport
GtRectI rectDraw = ptrNode->m_objFrame;
rectDraw.xMin = m_dateRuler->GetDatePos(ptrTask->Get_objStart());
rectDraw.xMax = m_dateRuler->GetDatePos(ptrTask->Get_objEnd());
rectDraw.yMin += 5;
rectDraw.yMax -= 5;
ptrTask->Set_objDrawFrame(rectDraw);

GetDatePos 的工作方式类似于日期标尺的绘图算法,它从视口开始将时间推进到请求的日期时间,并返回该日期的 x 坐标。如果日期时间超出视口范围,则返回相应的限制,以便任务的绘图矩形不会绘制在视口外部。应该注意的是,时间尺度的渲染由 GtDateRuler 完成,而任务和约束的渲染由 GtProjectView 完成。

未来发展

GtProject 的目标是为用户提供一个封装的项目管理控件。现在,基础项目、任务、约束和甘特图查看器已投入运行,作者将开始使 GtProject 更像 Microsoft。第一个任务将是实现 Microsoft Project 的自动调平功能,该功能会自动移动开始日期以遵守任务之间的约束。接下来,将把资源和利用率计算添加到任务中。

历史

  • 2017 年 3 月 2 日:初始版本

作者:Anthony Daniels

© . All rights reserved.