A new Class TGantt

A new Class TGantt

Postby Antonio Linares » Wed Oct 05, 2011 8:17 pm

We couldn't resist to implement a much simpler and better coded Class TGantt :-)

So here you have it. We will include it in next FWH build, and we plan to continue enhancing it.

gantt.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"

#define GWL_STYLE       -16

static nOldCol, nOldRow

//----------------------------------------------------------------------------//

CLASS TGantt FROM TControl

   DATA   aItems INIT {}
   DATA   oItem, oLbx
   DATA   lCaptured AS LOGICAL INIT .F.
   DATA   hPen
   DATA   lLResize, lRResize AS LOGICAL INIT .F.
   DATA   bChange, bPressed
   DATA   lGridMonth INIT .F.  

   CLASSDATA lRegistered AS LOGICAL

   METHOD New( nTop, nLeft, nWidth, nHeight, oWnd, lBorder,;
               lVScroll, lHScroll, nClrFore, nClrBack, bchange, dpresed, oLbx ) CONSTRUCTOR

   METHOD Redefine( nId, oWnd, nClrFore, nClrBack ) CONSTRUCTOR

   METHOD AddItem( nTop, nLeft, nBottom, nRight )

   METHOD AtItem( nRow, nCol )

   METHOD EraseBkGnd( hDC ) INLINE 1

   METHOD GridMonth()

   METHOD Display() INLINE ::BeginPaint(), ::Paint(), ::EndPaint(), 0

   METHOD Paint()

   METHOD LButtonDown( nRow, nCol, nKeyFlags )
   METHOD LButtonUp( nRow, nCol, nKeyFlags )  

   METHOD MouseMove( nRow, nCol, nKeyFlags )
   
   METHOD End()

ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( nTop, nLeft, nWidth, nHeight, oWnd, lBorder,;
            lVScroll, lHScroll, nClrFore, nClrBack, bChange, bPressed, oLbx ) CLASS TGantt

   DEFAULT lBorder := .T., nClrFore := 0, nClrBack := CLR_WHITE,;
           lVScroll := .F., lHScroll := .F.,;
           oWnd := GetWndDefault()

   ::cCaption   = ""
   ::oWnd      = oWnd
   ::bChange   = bChange
   ::bPressed  = bPressed
   ::oLbx      = oLbx
   ::nStyle    = nOr( WS_CHILD,;
                      If( lBorder, WS_BORDER, 0 ),;
                      If( lVScroll, WS_VSCROLL, 0 ),;
                      If( lHScroll, WS_HSCROLL, 0 ),;
                      WS_VISIBLE, WS_TABSTOP )
   ::Register()      

   ::SetColor( nClrFore, nClrBack )

   ::hPen = CreatePen( PS_SOLID, 1, nRGB( 128, 128, 128 ) )

   if oWnd:lVisible
      ::Create()
      ::Default()
      ::lVisible = .t.
      oWnd:AddControl( Self )
   else
      oWnd:DefControl( Self )
      ::lVisible  = .F.
   endif

   /*
   if lVScroll
      DEFINE SCROLLBAR ::oVScroll VERTICAL OF Self
   endif
   if lHScroll
      DEFINE SCROLLBAR ::oHScroll HORIZONTAL OF Self
   endif
   */

   
return Self

//----------------------------------------------------------------------------//

METHOD Redefine( nId, oWnd, nClrFore, nClrBack, bChange, bPressed, oLbx ) CLASS TGantt

   DEFAULT oWnd := GetWndDefault()

   ::nId       = nId
   ::cCaption  = ""
   ::lCaptured = .F.
   ::oWnd      = oWnd
   ::bChange   = bChange
   ::bPressed   = bPressed
   ::oLbx      = oLbx

   ::Register()

   ::SetColor( nClrFore, nClrBack )
   
   if lAnd( GetWindowLong( ::hWnd, GWL_STYLE ), WS_VSCROLL )
      DEFINE SCROLLBAR ::oVScroll VERTICAL OF Self
   endif
   if lAnd( GetWindowLong( ::hWnd, GWL_STYLE ), WS_HSCROLL )
      DEFINE SCROLLBAR ::oHScroll HORIZONTAL OF Self
   endif

   oWnd:DefControl( Self )

return Self

//----------------------------------------------------------------------------//

METHOD AddItem( nTop, nLeft, nBottom, nRight, nClrBack ) CLASS TGantt

   local oItem := TGanttItem():New( Self, nTop, nLeft, nBottom, nRight, nClrBack )
   
   AAdd( ::aItems, oItem )
   
return oItem  
   
//----------------------------------------------------------------------------//

METHOD AtItem( nRow, nCol ) CLASS TGantt

   local nItem := AScan( ::aItems, { | oItem | oItem:IsOver( nRow, nCol ) } )

return If( nItem != 0, ::aItems[ nItem ], nil )

//----------------------------------------------------------------------------//

METHOD GridMonth() CLASS TGantt

   local n, nWidth := ::nWidth() / 31
   
   MoveTo( ::hDC, 0, 18 )
   LineTo( ::hDC, ::nWidth, 18 )
   
   for n = 1 to 30
      MoveTo( ::hDC, nWidth * n, 0 )
      LineTo( ::hDC, nWidth * n, ::nHeight )
   next  
   
   for n = 1 to 31
      ::Say( 3, 7 + ( ( n - 1 ) * nWidth ),;
             If( n < 10, " ", "" ) + AllTrim( Str( n ) ),,, If( ::oFont != nil, ::oFont,), .T. )
   next    

return nil

//----------------------------------------------------------------------------//

METHOD Paint() CLASS TGantt

   local aInfo := ::DispBegin()
   
   FillRect( ::hDC, GetClientRect( ::hWnd ), ::oBrush:hBrush )
   
   if ::lGridMonth
      ::GridMonth()
   endif  
   
   AEval( ::aItems, { | oItem | oItem:Paint() } )

   if ::bPainted != nil
      Eval( ::bPainted, ::hDC )
   endif

   ::DispEnd( aInfo )

return 0

//----------------------------------------------------------------------------//

METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS TGantt

   local oItem

   if ::lCaptured
      if ::oItem:IsOver( nRow, nCol, 5 )
         ::oItem:DrawBorder() // to remove the previous painted lines
         if ::lRResize
            ::oItem:nRight = nCol - ( nOldCol - ::oItem:nRight )
         elseif ::lLResize
            ::oItem:nLeft = nCol - ( nOldCol - ::oItem:nLeft )
         else
            ::oItem:nLeft = nCol - ( nOldCol - ::oItem:nLeft )
            ::oItem:nRight = nCol - ( nOldCol - ::oItem:nRight )
         endif
         ::oItem:DrawBorder()
         nOldCol = nCol
         return nil
      endif  
   else
      if ( oItem := ::AtItem( nRow, nCol ) ) != nil
         if nCol < oItem:nLeft + 5 .or. nCol > oItem:nRight - 5
            CursorWE()
            return nil
         endif
      endif      
   endif      

return Super:MouseMove( nRow, nCol, nKeyFlags )

//----------------------------------------------------------------------------//

METHOD LButtonDown( nRow, nCol, nKeyFlags ) CLASS TGantt

   local oItem

   if ::oLbx != nil
      ::oLbx:LButtonDown( nRow + 32, 40, nKeyFlags )
   endif

   if ( oItem := ::AtItem( nRow, nCol ) ) != nil
      nOldCol = nCol
      nOldRow = nRow
      ::lCaptured = .T.
      ::oItem = oItem
      ::oItem:DrawBorder()
      ::lLResize = nCol < oItem:nLeft + 5
      ::lRResize = nCol > oItem:nRight - 5
      if ::lLResize .or. ::lRResize
         CursorWE()
      else  
         CursorHand()  
      endif    
   endif
       
return Super:LButtonDown( nRow, nCol, nKeyFlags )

//----------------------------------------------------------------------------//

METHOD LButtonUp( nRow, nCol, nKeyFlags ) CLASS TGantt

   if ::lCaptured
      ::oItem:DrawBorder() // to remove the last painted lines
      ::Refresh()
      if ::bChange != nil
         Eval( ::bChange, Self )
      endif
      ::lCaptured = .F.
   endif

return Super:LButtonUp( nRow, nCol, nKeyFlags )

//----------------------------------------------------------------------------//

METHOD End() CLASS TGantt

   DeleteObject( ::hPen )

return Super:End()

//----------------------------------------------------------------------------//

CLASS TGanttItem

   DATA   nTop, nLeft, nBottom, nRight
   DATA   nClrBack
   DATA   oGantt
   
   METHOD New( oGantt, nTop, nLeft, nBottom, nRight, nClrBack )

   METHOD DrawBorder()
   
   METHOD IsOver( nRow, nCol, nMargin )
   
   METHOD Paint()
   
ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( oGantt, nTop, nLeft, nBottom, nRight, nClrBack ) CLASS TGanttItem

   ::oGantt   = oGantt
   ::nTop     = nTop
   ::nLeft    = nLeft
   ::nBottom  = nBottom
   ::nRight   = nRight
   ::nClrBack = nClrBack
   
return Self

//----------------------------------------------------------------------------//

METHOD IsOver( nRow, nCol, nMargin ) CLASS TGanttItem

   DEFAULT nMargin := 0

return nRow >= ::nTop .and. nCol >= ::nLeft - nMargin .and. ;
       nRow <= ::nBottom .and. nCol <= ::nRight + nMargin

//----------------------------------------------------------------------------//

METHOD DrawBorder() CLASS TGanttItem

   local hDC     := ::oGantt:GetDC()
   local nOldRop := SetROP2( hDC, 7 )
   local nOldPen := SelectObject( hDC, ::oGantt:hPen )
   
   MoveTo( hDC, ::nLeft,  ::nTop )
   LineTo( hDC, ::nRight - 1, ::nTop )
   LineTo( hDC, ::nRight - 1, ::nBottom - 1 )
   LineTo( hDC, ::nLeft,  ::nBottom - 1 )
   LineTo( hDC, ::nLeft,  ::nTop )
   SetROP2( hDC, nOldRop )
   SelectObject( hDC, nOldPen )
   ::oGantt:ReleaseDC()
   
return nil

//----------------------------------------------------------------------------//

METHOD Paint() CLASS TGanttItem

   local hPen := CreatePen( 0, 1, ::nClrBack )
   
   FillRect( ::oGantt:GetDC(), { ::nTop, ::nLeft, ::nBottom, ::nRight }, hPen )
   
   DeleteObject( hPen )  
   ::oGantt:ReleaseDC()
   
return nil

//-----------------------------------------------------//          


TestGant.prg
Code: Select all  Expand view  RUN
#include "FiveWin.ch"
#include "Gantt.ch"

function Main()

   local oFont, oWnd, oGantt

   DEFINE FONT oFont NAME "Verdana" SIZE 0, -10

   DEFINE WINDOW oWnd TITLE "Class TGantt test"
   
   @ 1, 1 GANTT oGantt SIZE 300, 300 OF oWnd
   
   oGantt:SetFont( oFont )
   oGantt:lGridMonth = .T.
   
   oGantt:AddItem( 30, 10,  50,  80, CLR_BLUE )
   oGantt:AddItem( 60, 30,  80, 110, CLR_RED )
   oGantt:AddItem( 90, 50, 110,  90, CLR_GREEN )
   oGantt:AddItem( 120, 10, 140,  80, CLR_CYAN )  
   oGantt:AddItem( 150, 50, 170, 120, CLR_YELLOW )
   
   oWnd:oClient = oGantt

   oWnd:Center()

   ACTIVATE WINDOW oWnd

return nil
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A new Class TGantt

Postby Antonio Linares » Wed Oct 05, 2011 8:26 pm

Here you have it, with a working example and full source code included:

http://code.google.com/p/fivewin-contributions/downloads/detail?name=newgantt.zop&can=2&q=
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A new Class TGantt

Postby James Bott » Wed Oct 05, 2011 10:45 pm

Antonio,

As always your code is clear and clean.

Referring to the addItem() method:

oGantt:AddItem( 150, 50, 170, 120, CLR_YELLOW )

Eventually the addItem() method needs to be changed to something like:

oGantt:AddItem( cDescription, dStart, dEnd, nColor )

Internally the class can figure out the coordinates of the task display based on the start and end date of the task and the start date of the earliest task.

Later we need to consider task dependencies. Tasks can be dependent on another task being completed or partially completed. So, instead of a start date, a task starts at another's end date, or 5 days before the end date, or two days after another task's start date, etc.

Sometimes a task needs finer starts and ends including the hour. This is useful for scheduling, for instance.

Another issue is that tasks need to be displayed in what is called a Work Breakdown Structure (WBS) which is basically an outline format. Tasks at the lowest level have start and end dates (or dependencies) and tasks at the higher levels start when the first subtask starts and end when the last subtask ends. These upper level items (not really tasks) may or may not have a bar displayed. The bar might be a different form so it is easily visible as not being a task. The color of an item might default to a color based on the level of the item in the WBS.

The WBS needs to have at least three levels. This means that we would need a nLevel parameter and possibly a oParent parameter in the addItem() method.

Project management is complicated and thus I think it is wise to consider what will be needed eventually when designing the Gantt class. Perhaps it would be useful to write up an informal Gantt class specification before getting too far into the class design. Everyone could contribute to this specification.

Lots to think about. Comments welcome.

Regards,
James

Here is a sample WBS:

Code: Select all  Expand view  RUN
Project Alpha
   Design Phase
       Interface
       class
       input
       output
   Coding Phase
       interface
       class
       input
       output
    Testing Phase
       ...
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: A new Class TGantt

Postby TimStone » Thu Oct 06, 2011 5:18 pm

Thats a nice start. I will be happy to start working with it.

You defined a specific grid, but what we really need I believe is the ability to define a grid, and also to start with a text element.

For example, how about a chart for the following information:

First column: Task information ( text )

Column 2 to n are steps to be perfomed.

James is correct about the format, although it is not necessarily dates we are tracking. Work in progress may be through stages, not dates.

Also, we need to be able to use this with resources ...

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: A new Class TGantt

Postby James Bott » Thu Oct 06, 2011 8:14 pm

Tim,

James is correct about the format, although it is not necessarily dates we are tracking. Work in progress may be through stages, not dates.


I do believe that a Gantt chart by definition is showing the schedule of a project so the scale is time. http://en.wikipedia.org/wiki/Gantt_chart

It appears that what you are looking for is a horizontal bar chart rather than a Gantt chart with a WBS. In your case you would want all the items' bars to start at zero? You also don't need a WBS either I am guessing?

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: A new Class TGantt

Postby Antonio Linares » Thu Oct 06, 2011 8:47 pm

I have downloaded and tested this free Gantt application as it is a very good way to understand how the Class TGantt should behave:

http://softlayer.dl.sourceforge.net/project/openproj/OpenProj%20Binaries/1.4/openproj-1.4.msi

Image
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: A new Class TGantt

Postby James Bott » Thu Oct 06, 2011 9:44 pm

Antonio,

I was just going to post a link to a sample Gantt chart, but you have already posted a good one.

Others may not really need a Gnatt but something similar as Tim has indicated. I suspect that many, if not most, may not need a Gantt chart since Gantts were designed for project management. Perhaps we should take a poll to see.

Does anyone want to describe the type of chart they need? A picture would be helpful too.

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: A new Class TGantt

Postby Bayron » Fri Oct 07, 2011 2:48 am

In my prior Job I had to make the scheduling work in many big Construction Projects were Union Companies had to be scheduled, and I used MicroSoft Projects, but I don't see any other use ratter than to build scheduling software, I never even used it in the small construction projects, as building up to 10 row houses...

So I will not have the need for a Gantt diagram Class now or in the near future... It will be great to have it, but I will preffer that effort to be put into the New Metro Class...
=====>

Bayron Landaverry
(215)2226600 Philadelphia,PA, USA
+(502)46727275 Guatemala
MayaBuilders@gMail.com

FWH12.04||Harbour 3.2.0 (18754)||BCC6.5||UEstudio 10.10||
Windows 7 Ultimate

FiveWin, One line of code and it's done...
User avatar
Bayron
 
Posts: 815
Joined: Thu Dec 24, 2009 12:46 am
Location: Philadelphia, PA

Re: A new Class TGantt

Postby frose » Fri Oct 07, 2011 6:42 am

Hi to all,

since years we are looking to substitute our old fashioned planning tables with paper cards for each production step with a modern future-proofed solution.

Round about one year ago we decided to adapt a Manufacturing Execution System (MES)-modul to our FiveWin-based ERP-system, called ‘JobDISPO MES’. It’s a high sophisticated piece of software with a lot of features, impossible for us to program these things by ourselves, even if FiveWin offers a Gantt class.

Meanwhile we are quite happy, that we are working with a competent partner, whose firm with the complex process of automatically optimization of work sequences.

But maybe there are some other needs for us to use this new Gantt class. Perhaps to visualize the results of the JobDISPO-process back in the ERP-system. So we appreciate these activities and looking forward to have a easy to use Gantt class for future implementations.
Windows 11 Pro 22H2 22621.1848
Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384
Harbour 3.2.0dev (r2008190002)
FWH 23.10 x86
User avatar
frose
 
Posts: 392
Joined: Tue Mar 10, 2009 11:54 am
Location: Germany, Rietberg

Re: A new Class TGantt

Postby TimStone » Fri Oct 07, 2011 8:40 pm

James & Antonio,

I'm looking at this to schedule jobs. You schedule across months. I would like to schedule a job across a single day, or perhaps more.

Here is what I would want to schedule:

Description
Start Time
End Time
Status

The status field would determine the color of the bar. For example, Green would be "in progress", Red would be "hold", Yellow could be "Testing" and Blue could be completed. The bar would start at the start time, progress to the current time ( or end time if it is posted ), and the color would reflect the status. The description would be in a left column.

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: A new Class TGantt

Postby James Bott » Fri Oct 14, 2011 9:47 pm

Tim,

What you are describing is a standard Gantt chart. Typically, the horizontal scale can be hours, days, or months. You have a description, start, end, and percent complete which are all typical scheduling data and are used in a Gantt. We really just need to add the hour to the start and end dates and provide a X-axis in hours for you to get what you need.

addItem( description, start date, start time, end date, end time, percent complete)

Perhaps it would be useful to build a base class that is a simple horizontal bar chart. Then the Gantt chart could inherit from that class. This way we could fill both needs with less work.

Comments anyone?

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: A new Class TGantt

Postby Antonio Linares » Sat Oct 15, 2011 8:13 am

James,

I agree with you. We plan to continue this development asap :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42118
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Marc Venken and 60 guests