featured products
exmlgrid excombobox explorertree

How do you find the control's help / documentation on your computer:

Frequently Asked Questions - General

Click the programming language you use for general questions:

How-To Questions

Click the programming language you use for how-to questions:

Exontrol Software - ExGantt FAQ page

Frequently Asked Questions - ExGantt Component

Listed below are the questions that we are asked quite often. Before you write us, be sure to check here. 

Are you looking for something?

Just press CTRL+F ( or select Edit\Find menu item ) and you have a dialog that will help you to locate the string that are you looking for.

Where can I find the control's release notes?

The control's release notes can be found on our web site, looking for the Release Notes column in the control's main page. Click here for direct link.

What is the difference between EXGANTT and EXG2ANTT controls?

The main difference between eXGantt and eXG2antt is that eXGantt is a read only control, so actually it is provided for viewing data only, while using the eXG2antt users can edit/update at runtime the data ( cells, bars, and so on ). Also, the eXG2antt component provides other features that the eXGantt does not support such as: Built-in Editors, Summary Bars, Histogram, InsideZoom, Undo/Redo, Grouping Bars, Summary Bars, PDM (Precedence Diagramming Method), Notes/Boxes and more.

Shortly, the eXGantt control is a limited version of the eXG2antt component, while the eXG2antt is a full featured control. We provided 2 versions of our gantt view as that are application where only viewing data is required so no user interaction and also there are applications where changing data at runtime using UI is required.

In conclusion, the eX(G)rid-eX(G)antt, shortly eXG2antt, combines the eXGrid and eXGantt components in a standalone component, or the eXGantt  is a subset of eXG2antt control.

I really like the EXGANTT control, but how do you print from it?

By default, the exgantt setup installs the exprint.dll in your system folder. If you can't locate there, please feel from to download it from our web site. The Exontrol's ExPrint component ( exprint.dll ) provides Print and Print Preview capabilities for the exGantt component, as well for other components too. Once that you can have the exPrint component in your Components list, insert a new instance of "ExPrint 1.0 Control Library" to your form and add the following VB code:
Private Sub Command1_Click()
    With Print1
        Set .PrintExt = Gantt1.Object
        .Preview
    End With
End Sub

The following sample shows how to call Preview method in C#:

private void button1_Click(object sender, System.EventArgs e)
{
	axPrint1.PrintExt = axGantt1.GetOcx();
	axPrint1.Preview();
} 

The following sample shows how to call Preview method in C++:

void CTemplate2Dlg::OnPreview() 
{
	m_print.SetPrintExt( m_gantt.GetControlUnknown() );
	m_print.Preview();
	
}

where the m_print is a member that wraps the Exontrol.Print component, and m_gantt is the wrapper class for Exontrol.Gantt control.

The Exontrol Print Preview mainframe looks like follows:

The exPrint component is free of charge, if you are registered user of the exGantt component.

The following VB sample opens the Print Preview frame:

With Print1
    Set .PrintExt = Gantt1.Object
    .Preview
End With

The following C++ sample opens the Print Preview frame:

m_print.SetPrintExt( m_gantt.GetControlUnknown() );
m_print.Preview();

The following VB.NET sample opens the Print Preview frame:

With AxPrint1
    .PrintExt = AxGantt1.GetOcx()
    .Preview()
End With

The following C# sample opens the Print Preview frame:

axPrint1.PrintExt = axGantt1.GetOcx();
axPrint1.Preview();

The following VFP sample opens the Print Preview frame:

with thisform.Print1.Object
    .PrintExt = thisform.Gantt1.Object
    .Preview()
endwith

How can we print just a user selected area rather than the whole document, eg from date to date?

The Exontrol's ExPrint component provides print and print preview capabilities for the component. The Options property of the ExPrint object may be used to pass custom options for the print and print preview of the component. 

Currently, the component supports the following options:

  • DateStart, indicates the new starting date for the print and print preview. If missing, the default starting date is used. 
  • DateEnd, indicates the new ending date for the print and print preview. If missing, the default ending date is used.
  • ColumnsOnEveryPage=#value#, specifies that the control prints the columns section on each page, if the value is not zero. If the ColumnsOnEveryPage option is negative, its absolute value minus one, indicates the index of the column being printed on each page, else if positive, it indicates the maximum ratio of page's width that can be covered by the columns section on every page as the following samples:
    • ColumnsOnEveryPage=0.5, specifies whether the control prints the columns section on each page, and the area being used by the columns section is not larger than half of the page.
    • ColumnsOnEveryPage=-1, specifies whether the control prints the column ( with the index 0 ) section on each page.
  • FitToPage = On, specifies that the control's content to be previewed / printed to a single page ( Fit-To-Page option ). The FitToPage option could be one of the following:
    • On, (Fit-To-Page) the control's content is printed to a single page ( version 6.1 )
    • p%, (Adjust-To) where p is a positive number that indicates the percent from normal size to adjust to. For instance, the "FitToPage = 50%" adjusts the control's content to 50% from normal size. ( version 8.0 )
    • wx, (Fit-To Wide) where w is a positive number that indicates that the control's content fits w pages wide by how many pages tall are required. For instance, "FitToPage = 3 x" fits the control's content to 3 pages wide by how many pages tall is are required. ( version 8.0 )
    • xt, (Fit-To Tall) where t is a positive number that specifies that the control's content fits t pages tall by how many pages wide are required. For instance, "FitToPage = x 2" fits the control's content to 2 pages tall by how many pages wide are required. ( version 8.0 )
    • wxt, (Fit-To) where w and t are positive numbers that specifies that the control's content fits w pages wide by t pages tall. For instance, "FitToPage = 3 x 2" fits the control's content to 3 pages wide by 2 pages tall. ( version 8.0 )
  • Print = Selection, prints only the selected items ( including the associated bars ). If the option is missing, the entire chart is printing.

For instance, the following VB sample specifies the new dates for the chart:

With Print1
        ' Use the DateStart and DateEnd options to specify the new range for printing the chart
        .Options = "DateStart = Oct 17 2005; DateEnd = 12/1/2005"
        Set .PrintExt = Gantt1.Object
        .Preview
End With

The options are separated by ';' character or newline sequence ( "\r\n" or vbCrLf, ... ), and specifies the name of the option, the '=' character and value of the option, like: "DateStart = Oct 17 2005; DateEnd = 12/1/2005" 

Another option to print an user selected area is is to right click the document in print preview, and define the new selected area by moving the mouse while the right button is clicked. The user selected area is painted in blue. This way you can print on the paper only the blue section in the preview document.

Does the GANTT control allow you to drag timebars (move them horizontally and resize them)?

No, instead the eXG2antt control allows. Please check the BarsAllowSizing property of the eXG2antt control.

Does the GANTT control allow you to doubleclick on a timebar so that I can display another form?

You need to add a handler for DblClick event. Next, use the BarFromPoint property to determine the key of the bar from the cursor. 

The following VB sample displays a message box when user double clicks a bar:

Private Sub Gantt1_DblClick(Shift As Integer, X As Single, Y As Single)
    With Gantt1.Chart
        Dim k As Variant
        k = .BarFromPoint(-1, -1)
        MsgBox k
    End With
End Sub

The following VFP sample displays a message box when user double clicks a bar:

*** ActiveX Control Event ***
LPARAMETERS shift, x, y

with thisform.Gantt1.Chart
local k
k = .BarFromPoint(-1,-1)
MessageBox(k)
endwith

Brain lock on PANEWIDTH in VFP. Can't get the syntax. What am I doing wrong here?

The PaneWidth property specifies the width of the control or chart area. 

The following VFP sample changes the width of the control's area:

with thisform.Gantt1.Chart
	.PaneWidth(0) = 256
endwith

The following VFP sample changes the width of the chart's area:

with thisform.Gantt1.Chart
	.PaneWidth(1) = 256
endwith

How do it get the dates to populates the columns 2 and 3 when I add the child items?

The control provides the CellCaption property to specify the value/caption for a cell.

Is there a way to compress the calendar at the top so that i can see a higher level for the year?

You can use the Zoom method. Use the Level property to access any level in the control's header. Each level has a Level object, where you can change the following properties: Label, Unit and Count. Please check also the UnitWidth property, that indicates the width in pixels of the minimal level.

How do you quickly clear out all the items and bars in order to repopulate the GANTT control?

The RemoveAllItems method removes all items. The bars and links related to an item, are removed when an item is removed. Use the Clear method to clear the columns collection. The RemoveAllItems method is called automatically when the Clear method is called.

But how do I determine that particular bar's new START and END dates?

The ItemBar property accesses properties for a specified bar. The ItemBar(exBarStart) property indicates the time where the bar begins. The ItemBar(exBarEnd) property indicates the time where the bar ends.

Does your control support overview, layout map feature?

Yes. Please check the OverviewVisible property.

How / where do I set "exBarStart" and "exBarEnd"? When i try to use them, they are undefined?

Open the control's help file ( click the Start button, click the Run item, and type exgantt.chm, and press enter ), and locate the ItemBar property in the Items collection. Click the ItemBarPropertyEnum type of the Property parameter. There you will find a table with all supported properties. The first column indicates the name of the constant, the second column indicates the value of the constant, and the last column describes what the property does.

Visually show task relationship is key to a good Gantt chart. Does yours supports it?

Yes. Please check the AddLink method that adds a link between two bars.

How do I align the caption in the bar?

Please check the Items.ItemBar(,, exBarHAlignCaption ) property. The exBarHAlignCaption option aligns the caption in the bar. Use the AddBar property to assigns a caption to a bar.

I need to distinguish between the user clicking in an open area of the chart (available days on the calendar) versus clicking on a bar?

Please check the Chart.DateFromPoint and Chart.BarFromPoint property. The DateFromPoint property determines the date from point. The BarFromPoint property determines the key of the bar from the point. Use the Items.ItemBar property to access the bar inside the item. The ItemFromPoint property retrieves the handle of the item from the point.

Is there any option to define my own bar?

The Bars.AddShapeCorner property defines a new bar based on an icon. Use the Images method or ReplaceIcon property to add new icons to the control's images collection.

How do I expand all items?

Use the Items.ExpandItem property to expand an item.

The following VB sample expands all items:

With Gantt1
    .BeginUpdate
    With .Items
        For Each h In Gantt1.Items
            .ExpandItem(h) = True
        Next
    End With
    .EndUpdate
End With

The following VFP sample expands all items:

with thisform.Gantt1
	.BeginUpdate
	with .Items
	for each h in thisform.Gantt1.Items
		.DefaultItem = h
		.ExpandItem(0) = .t.
	next
	endwith
	.EndUpdate
endwith

How can I change the font for some cells?

The CellFont property specifies the font being used in the cell. The ItemFont property specifies the item's font. If any of this properties are not set, the control's Font specifies the cell's font. Use the ItemHeight property to change the item's height.

I'd like to filter for a specific value across any of the control's fields. How can I do that?

The control supports filtering items using AND, OR, NOT operators between columns. The FilterCriteria property specifies the filter criteria. In your case, if you have three columns, the control's FilterCriteria property should be "%0 or %1 or %2". The "not %1" specifies that the second column ( column's index is 1 ) excludes the values selected in the drop down filter window.

How do I determine the bar from point?

The Chart.BarFromPoint property determine the key of the bar from point. The ItemFromPoint property determines the item from point.

The following VB sample displays the start data of the bar from the point:

Private Sub Gantt1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    With Gantt1
        Dim h As HITEM, c As Long, hit As HitTestInfoEnum
        h = .ItemFromPoint(-1, -1, c, hit)
        If Not (h = 0) Then
            Dim k As Variant
            k = .Chart.BarFromPoint(-1, -1)
            If Not IsEmpty(k) Then
                Debug.Print .Items.ItemBar(h, k, exBarStart)
            End If
        End If
    End With
End Sub

The following C++ sample displays the start data of the bar from the point:

#include "Items.h"
#include "Chart.h"

CString V2Date( VARIANT* pvtValue )
{
	COleVariant vtDate;
	vtDate.ChangeType( VT_BSTR, pvtValue );
	return V_BSTR( &vtDate );
}

void OnMouseDownGantt1(short Button, short Shift, long X, long Y) 
{
	long c = 0, hit = 0, h = m_gantt.GetItemFromPoint( -1, -1, &c, &hit );
	if ( h != 0 )
	{
		COleVariant vtKey = m_gantt.GetChart().GetBarFromPoint( -1, -1 );
		if ( V_VT( &vtKey ) != VT_EMPTY )
		{
			COleVariant vtStart = m_gantt.GetItems().GetItemBar( h, vtKey, 1 /*exBarStart*/ );
			OutputDebugString( V2Date( &vtStart ) );
		}
	}
}

The following VB.NET sample displays the start data of the bar from the point:

Private Sub AxGantt1_MouseDownEvent(ByVal sender As Object, ByVal e As AxEXGANTTLib._IGanttEvents_MouseDownEvent) Handles AxGantt1.MouseDownEvent
    With AxGantt1
        Dim c As Long, hit As EXGANTTLib.HitTestInfoEnum, h As Integer = .get_ItemFromPoint(-1, -1, c, hit)
        If Not (h = 0) Then
            Dim k As Object
            k = .Chart.BarFromPoint(-1, -1)
            If Not k Is Nothing Then
                System.Diagnostics.Debug.WriteLine(.Items.ItemBar(h, k, EXGANTTLib.ItemBarPropertyEnum.exBarStart))
            End If
        End If
    End With
End Sub

The following C# sample displays the start data of the bar from the point:

private void axGantt1_MouseDownEvent(object sender, AxEXGANTTLib._IGanttEvents_MouseDownEvent e)
{
	int c = 0;
	EXGANTTLib.HitTestInfoEnum hit = EXGANTTLib.HitTestInfoEnum.exHTCell;
	int h = axGantt1.get_ItemFromPoint(-1, -1, out c, out hit);
	if (h != 0)
	{
		object k = axGantt1.Chart.get_BarFromPoint(-1, -1);
		if (k != null)
			System.Diagnostics.Debug.WriteLine( axGantt1.Items.get_ItemBar( h, k, EXGANTTLib.ItemBarPropertyEnum.exBarStart ) );
	}
}

The following VFP sample displays the start data of the bar from the point:

*** ActiveX Control Event ***
LPARAMETERS button, shift, x, y

With thisform.Gantt1
	local h, c, hit
    h = .ItemFromPoint(-1, -1, c, hit)
    If (h # 0) Then
        local k
        k = .Chart.BarFromPoint(-1, -1)
        If !Empty(k) Then
            ? .Items.ItemBar(h, k, 1)
        EndIf
    EndIf
EndWith

I am evaluating your control and running into a problem with the concurrence of non-modal top-level windows (e.g. toolbars, message windows) with your control. The chart window (on the right hand side) has always the mouse captured. Is there any option to turn it off?

Please set the Chart.DrawDateTicker property on False. The DrawDateTicker property retrieves or sets a value that indicates whether the control draws a ticker around the current date while cursor hovers the chart's client area.

In VFP, I get "Function argument, value, type, or count is invalid", while I'm using the ItemBar property. Am I doing something wrong?

Let's say that your code looks like follows:
LOCAL h
SCAN
	_key="K_"+ALLTRIM(STR(projekte.ID))
	WITH THISFORM.myplan.Items
		h = .AddItem(ALLTRIM(projekte.project_name))
		.AddBar( h,"Project Summary" , DTOT(projekte.sdate),DTOT(projekte.edate), _key, "" )
		.ItemBar( h ,_key,3 ) = "my text"
	ENDWITH
ENDSCAN

The h variable indicates the handle of the newly created item. This value is always greater than 65000, so the VFP environment always fires an error when compiling the AddBar and ItemBar properties because it considers accessing an array, and its limit is 65000. Of course this problem is related to VFP ignoring the fact that it is calling a property! not an array, so our products provide a DefaultItem property that help VFP users to pass this error. So, in VFP the above code should look like follows:

SCAN
	_key="K_"+ALLTRIM(STR(projekte.ID))
	WITH THISFORM.myplan.Items
		.DefaultItem = .AddItem(ALLTRIM(projekte.project_name))
		.AddBar( 0,"Project Summary" , DTOT(projekte.sdate),DTOT(projekte.edate),_key, "" )
		THISFORM.myplan.Template = "Items.ItemBar( 0,`" + _key + "`,3 ) = `my text`"
	ENDWITH
ENDSCAN 

The difference ( marked in red ) is that the first parameter for properties like AddBar and ItemBar is 0, and before calling them the Items.DefaultItem property indicates the handle of the item being accessed. How it works? The control uses the value of the Items.DefaultItem property, when the first parameter of the ItemBar, AddBar and so on is 0. The AddItem property saves before the handle of the newly created item to the DefaultItem property, and so the VFP error is gone, and the code works like you expect.

Is there any property or method that can be used to specify the DATE range visible on the chart?

The ScrollRange property does the trick. In previous versions, you can simulate if you want to scroll the date between Jan 1, 2005 up to Dec 31, 2006. It seems that the chart can scroll an endless date and I only want to limit to scroll the chart date from Jan 1, 2005 to Dec 31, 2006. The control fires the DateChange event when the user scrolls the chart's area, or if the FirstVisibleDate property is changed. 

The following VB sample limits the scrolling area to Dec 31, 2006, from Jan 1, 2005.

Private Function LastVisibleDate(ByVal g As EXGANTTLibCtl.Gantt) As Date
    With Gantt1
        With .Chart
            Dim d As Date
            d = .FirstVisibleDate
            Do While .IsDateVisible(d)
                d = .NextDate(d, exDay, 1)
            Loop
        End With
    End With
    LastVisibleDate = d - 1
End Function

Private Sub Gantt1_DateChange()
    Dim dMin As Date, dMax As Date
    dMin = "1/1/2005"
    dMax = "31/12/2006"
    With Gantt1.Chart
        If .FirstVisibleDate < dMin Then
            .FirstVisibleDate = dMin
        End If
        If LastVisibleDate(Gantt1) > dMax Then
            .FirstVisibleDate = dMax - (LastVisibleDate(Gantt1) - .FirstVisibleDate) + 1
        End If
    End With
End Sub

How do I determine if two bars are intersected?

The ItemBar(exBarStart) and ItemBar(exBarEnd) properties specify  the starting and ending date of the bar. A bar is determined by the starting and ending date.

The following C++ function determines whether two bars are intersected:

BOOL Intersection( DATE aStart, DATE aEnd, DATE bStart, DATE bEnd )
{
	DATE am = MIN( aStart, aEnd ), aM = MAX( aStart, aEnd );
	DATE bm = MIN( bStart, bEnd ), bM = MAX( bStart, bEnd );
	if ( bM < am )
		return FALSE;
	if ( bm > aM )
		return FALSE;
	return TRUE;
}

where the MIN and MAX functions determines the minimum and maximum values like follows:

DATE MIN( DATE a, DATE b )
{
	if ( a < b )
		return a;
	return b;
}
DATE MAX( DATE a, DATE b )
{
	if ( a > b )
		return a;
	return b;
}

In VB the functions looks like follows:

Private Function Intersect(ByVal aStart As Date, ByVal aEnd As Date, ByVal bStart As Date, ByVal bEnd As Date) As Boolean
    Dim aMin As Date, aMax As Date
    aMin = MIN(aStart, aEnd)
    aMax = MAX(aStart, aEnd)
    Dim bMin As Date, bMax As Date
    bMin = MIN(bStart, bEnd)
    bMax = MAX(bStart, bEnd)
    If (bMax < aMin) Then
        Intersect = False
        Exit Function
    End If
    If (bMin > aMax) Then
        Intersect = False
        Exit Function
    End If
    Intersect = True
End Function

where the MIN and MAX functions looks like:

Private Function MIN(ByVal a As Date, ByVal b As Date) As Date
    If (a < b) Then
        MIN = a
        Exit Function
    End If
    MIN = b
End Function

Private Function MAX(ByVal a As Date, ByVal b As Date) As Date
    If (a > b) Then
        MAX = a
        Exit Function
    End If
    MAX = b
End Function

I've just noticed that when I expand an item, the item is not selected. Am I missing something?

By default, the control doesn't select the item being expanded or collapsed, when the user clicks the +/- buttons. Thought you can have the item selected, by handling the AfterExpandItem event like in the following sample:
Private Sub Gantt1_AfterExpandItem(ByVal Item As EXGANTTLibCtl.HITEM)
    Gantt1.Items.SelectItem(Item) = True
End Sub

Use the SelectItem property to select or unselect a specified item.

Do you have any option of saving or exporting a gantt to files eg. GIF, BMP, JPG, PNG?

The control provides the Copy method that saves the control's content to clipboard, in Enhanced Metafile (EMF) format. The Enhanced Metafile format is a 32-bit format that can contain both vector information and bitmap information. This format is an improvement over the Windows Metafile Format and contains extended features, such as the following:

Built-in scaling information 
Built-in descriptions that are saved with the file 
Improvements in color palettes and device independence 

The EMF format is an extensible format, which means that a programmer can modify the original specification to add functionality or to meet specific needs. You can paste this format to Microsoft Word, Excel, Front Page, Microsoft Image Composer and any application that know to handle EMF formats.

How can I arrange the levels to look like this?

The LevelCount property specifies the number of levels being displayed. The Level property retrieves the level object to access the Label the and Unit properties that specifies the label being displayed in the level, and the unit being displayed. The Count property specifies the number of units displays at once. The FirstVisibleDate property specifies the first date/time being visible in the chart's area.

1

The first level displays each month in the year, the next level displays the week numbers.

BeginUpdate
Chart
{
	FirstVisibleDate = "Feb 1 2006"
	BackColor = RGB(255,255,255)
	DrawGridLines = 2
	LevelCount = 2
	Level(0)
	{
		Label = "<b><%mmmm%></b>"
		Unit = 16
		DrawGridLines = True
	}
	Level(1)
	{
		Label = "<%ww%>"	
		Unit = 256
	}
}
EndUpdate

2

The first level displays the years, the second level displays the months in two digits.

BeginUpdate()
Chart
{
	MarkTodayColor = BackColor
	DrawGridLines = -1
	LevelCount = 2
	Level(1)
	{
		Label = "<%mm%>"
		Unit = 16
		DrawGridLines = True
	}
	Level(0)
	{
		Label = "<%yyyy%>"
		Unit = 0
	}
}
EndUpdate()

3

The first level displays the month, the second level displays the day, and the third level displays the 6, 14, and 22 hours.

BeginUpdate()
Chart
{
	FirstVisibleDate = "6/18/2006 14:00"
	DrawGridLines = True
	LevelCount = 3
	Level(2)
	{
		Label = "<%hh%>"
		Count = 8
		DrawTickLines = True
		DrawGridLines = True
	}
	Level(1)
	{
		Label = "<b><%mmm%></b> <%d%>"
		Unit = 65536
		Count = 24
		DrawTickLines = True
		DrawGridLines = False
	}
	Level(0).Label  = "<b><%mmm%></b> <%yyyy%>"
}
EndUpdate()

4

The level displays hours and minutes in chunks of 5 minutes. Here's the template

BeginUpdate()
Chart
{
	FirstVisibleDate = "09:00"
	UnitWidth = 32
	Level(0)
	{
		Label = "<%hh%>:<%nn%>"
		Count = 5
	}
}
EndUpdate()

5  

The first level displays the month, the year and the number of the week in the year , the second level displays the name of the week day, and the third level displays the day of the month. Here's the template:

BeginUpdate()
Chart
{
	LevelCount = 3
	Level(0)
	{
		Label = "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>"
		Unit = 256	'exWeek
	}
	Level(1).Label = "<%d1%>"
	Level(2).Label = "<%d%>"
}
EndUpdate()

The following VB sample displays your header using 3 levels as shown above:

With Gantt1
    .BeginUpdate
    With .Chart
        .LevelCount = 3
        With .Level(0)
            .Label = "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>"
            .Unit = EXGANTTLibCtl.UnitEnum.exWeek
        End With
        .Level(1).Label = "<%d1%>"
        .Level(2).Label = "<%d%>"
    End With
    .EndUpdate
End With

 The following VFP sample displays your header using 3 levels:

with thisform.gantt1
.BeginUpdate()
with .Chart
	.LevelCount = 3
	with .Level(0)
		.Label = "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>"
		.Unit = 256
	endwith
	.Level(1).Label = "<%d1%>"
	.Level(2).Label = "<%d%>"
endwith
.EndUpdate()	
endwith

 The following VB.NET sample displays your header using 3 levels:

With AxGantt1
    .BeginUpdate()
    With .Chart
        .LevelCount = 3
        With .Level(0)
            .Label = "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>"
            .Unit = EXGANTTLib.UnitEnum.exWeek
        End With
        .Level(1).Label = "<%d1%>"
        .Level(2).Label = "<%d%>"
    End With
    .EndUpdate()
End With

 The following C# sample displays your header using 3 levels:

axGantt1.BeginUpdate();
EXGANTTLib.Chart chart = axGantt1.Chart;
chart.LevelCount = 3;
chart.get_Level(0).Label = "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>";
chart.get_Level(0).Unit = EXGANTTLib.UnitEnum.exWeek;
chart.get_Level(1).Label = "<%d1%>";
chart.get_Level(2).Label = "<%d%>";
axGantt1.EndUpdate();

 The following C++ sample displays your header using 3 levels:

m_gantt.BeginUpdate();
CChart chart = m_gantt.GetChart();
chart.SetLevelCount( 3 );
chart.GetLevel(0).SetLabel(COleVariant( "<b><%mmm%>, <%yyyy%></b> <r>Week: <%ww%>" ));
chart.GetLevel(0).SetUnit(256);
chart.GetLevel(1).SetLabel(COleVariant( "<%d1%>" ));
chart.GetLevel(2).SetLabel(COleVariant( "<%d%>" ));
m_gantt.EndUpdate();

Is there any property to save the control's data?

The control provides the SaveXML method that saves the control's data to XML document. Use the LoadXML method to load XML documents saved using the SaveXML method. The SaveXML method may save data to a file , an XML document object, or a custom object that supports persistence like described here:
  • String - Specifies the file name. Note that this must be a file name, rather than a URL. The file is created if necessary and the contents are entirely replaced with the contents of the saved document. For example:

    Gantt1.SaveXML("sample.xml")

  • XML Document Object. For example:

    Dim xmldoc as Object
    Set xmldoc = CreateObject("MSXML.DOMDocument")
    Gantt1.SaveXML(xmldoc)

  • Custom object supporting persistence - Any other custom COM object that supports QueryInterface for IStream, IPersistStream, or IPersistStreamInit can also be provided here and the document will be saved accordingly. In the IStream case, the IStream::Write method will be called as it saves the document; in the IPersistStream case, IPersistStream::Load will be called with an IStream that supports the Read, Seek, and Stat methods.

How can I change the color for a bar?

The Color property of the Bar object specifies the color being used to paint the bar. This property changes the colors for all bars with the same name. For instance, if you have 3 "Task" bars, and you are changing the color for the "Task" bar, the color is applied to all "Task" bars in the chart. For instance, in order to provide "Task" bars with different colors, you can use the Copy method to copy the Task bar to a new bar, and use the Color to change the color of the bar. The following function generates a Task bar with specified color:
Private Function AddTask(ByVal gantt As EXGANTTLibCtl.Gantt, ByVal clr As Long) As String
    Dim sT As String
    sT = "Task:" & clr
    With gantt.Chart.Bars.Copy("Task", sT)
        .color = clr
    End With
    AddTask = sT
End Function

The function generates a new bar with the name "Task:color", where the color is the color being used, and retrieves the name of the new bar being added. The Copy method retrieves the bar being found with specified name, or creates a new bar if the name is not found in the Bars collection, so AddTask function gets you the name of the bar you should use to specify the color for the bar being added as in the following sample:

With Gantt1.Items
	Dim d As Date
	d = Gantt1.Chart.FirstVisibleDate
	.AddBar .FirstVisibleItem, AddTask(Gantt1, vbRed), d, d + 4, "Red"
End With

How can I disable highlighting the selected dates, in the chart area as I click in the chart's header?

The MarkSelectDateColor property specifies the color being used to mark the selected dates. If the MarkSelectDateColor property is the same as the BackColor property of the Chart object, the selected dates are not shown. 

Is there any property to specify non-working hours, as you have the NonworkingDays property and related?

The NonworkingHours property specifies the non-working hours in a day. The non-working hours are shown, if your chart displays hours or groups of hours in a day. The NonworkingDays property specifies the non-working days in a week. The non-working days are shown if the chart displays days or group of days.

I've seen in one of your samples that the left and right scroll buttons are displayed together. How can I do that?

The ScrollOrderParts does the trick. The left and right buttons are displayed together if you call ScrollOrderParts = "l,r". Using the ScrollOrderParts property you can customize the position of the buttons in the control's scroll bars.

Is there any property I can use to customize the items that appear in the drop down filter window?

The CustomFilter property of the Column object. specifies the list of custom filters that appear in the drop down filter window. For instance, if the CustomFilter = "Excel Spreadsheets (*.xls )||*.xls|||Word Documents||*.doc|||Powerpoint Presentations||*.pps|||Text Documents (*.log,*.txt)||*.txt|*.log" the drop down filter window shows the following pre-defined filters: 
  • Excel Spreadsheets (*.xls )
  • Word Documents
  • Powerpoint Presentations
  • Text Documents (*.log,*.txt)

So, if the user selects the Word Documents, the control filters the column for cells that matches the "*.doc" pattern.

I've seen that you can assign a picture to a link. How can I do that?

The Link(exLinkText) property specifies the HTML text being displayed on the link. The AddLink method adds a link between two bars. The HTMLPicture property adds a picture that can be used in HTML strings, using the <img> tag. For instance the following code Gantt1.Items.Link("Link", exLinkText) = " <img>excel</img><br><br><b>doc.xls" assigns a text to the link, and it shows like follows:

 

If the HTMLPicture property doesn't include any excel identifier, the image on the link is not displayed, so the <img> tag is ignored.

Is there any way to split the tasks when non-working dates shows up?

Use the Add("Task:Split") method to add a Task bar that displays Split bar when non-working area shows up.

How do I check if the cursor is between two items?

The HitTestInfoEnum.exHTBetween value indicates whether the cursor is between two items. For instance, you can provide a visual effect for the item while performing OLE drag and drop operations, when the cursor is in the top half of the item, using the exDragDropListTop, or in the second half using the exDragDropListBottom value. In the same way you can provide a visual effect when the cursor is over or between two items, using the exDragDropListOver and exDragDropListBetween values. The ItemFromPoint property retrieves the handle of the item from the cursor, and retrieves also a code (HitTestInfo parameter), to indicate the part in the item where the cursor is. So, the exHTBetween value indicates whether the cursor is between items. The exHTBetween is an OR combination with other predefined values, so you must call HitTestInfo AND 0x1000 to check if the cursor is between rows/items as in the following samples:

The following VB sample displays a message when the cursor is between two items:

Private Sub Gantt1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim i As HITEM, c As Long, h As HitTestInfoEnum
    i = Gantt1.ItemFromPoint(-1, -1, c, h)
    If Not (i = 0) Then
        If (h And exHTBetween) Then
            Debug.Print "The cursor is between two items."
        Else
            Debug.Print "The cursor is over the item."
        End If
    End If
End Sub

The following VB.NET sample displays a message when the cursor is between two items:

Private Sub AxGantt1_MouseMoveEvent(ByVal sender As System.Object, ByVal e As AxEXGANTTLib._IGanttEvents_MouseMoveEvent) Handles AxGantt1.MouseMoveEvent
    With AxGantt1
        Dim c As Integer, h As EXGANTTLib.HitTestInfoEnum
        Dim i As Integer = .get_ItemFromPoint(-1, -1, c, h)
        If Not i = 0 Then
            If (h And EXGANTTLib.HitTestInfoEnum.exHTBetween) Then
                Debug.Print("The cursor is between items.")
            Else
                Debug.Print("The cursor is over the item.")
            End If
        End If
    End With
End Sub

The following C# sample displays a message when the cursor is between two items:

private void axGantt1_MouseMoveEvent(object sender, AxEXGANTTLib._IGanttEvents_MouseMoveEvent e)
{
    int c = 0;
    EXGANTTLib.HitTestInfoEnum h;
    int i = axGantt1.get_ItemFromPoint(-1, -1, out c, out h);
    if (i != 0)
        if ( (h & EXGANTTLib.HitTestInfoEnum.exHTBetween) == EXGANTTLib.HitTestInfoEnum.exHTBetween )
            System.Diagnostics.Debug.Print("The cursor is between items.");
        else
            System.Diagnostics.Debug.Print("The cursor is over the item.");
}

The following C++ sample displays a message when the cursor is between two items:

void OnMouseMoveGantt1(short Button, short Shift, long X, long Y) 
{
	long c = 0, h = 0;
	long i = m_tree.GetItemFromPoint( -1, -1, &c, &h );
	if ( i != 0 )
		if ( h & 0x1000 /*exHTBetween*/ )
			OutputDebugString( "The cursor is between items.\n" );
		else
			OutputDebugString( "The cursor is over the item.\n" );
}

The following VFP sample displays a message when the cursor is between two items:

*** ActiveX Control Event ***
LPARAMETERS button, shift, x, y

local c, hit
c = 0
hit = 0
with thisform.Gantt1
	.Items.DefaultItem = .ItemFromPoint( x, y, @c, @hit )
	if ( .Items.DefaultItem <> 0 )
		if bitand(hit,0x1000) = 0x1000
			wait window nowait "The cursor is between items."
		else
			wait window nowait "The cursor is over the item."
		endif
	endif
endwith

Is there a possibility to increase the right instead the left pane width when the width of the Gantt increases by resizing?

Use the PaneWidth property to change the width of the left or right panel in the Gantt control.

The following VB sample resizes the chart area as soon as the Gantt control is resized:

Private Sub Form_Resize()
On Error Resume Next
    With Gantt1
        .BeginUpdate
        .Width = ScaleWidth - 2 * .Left
        .Height = ScaleHeight - 2 * .Top
        .Chart.PaneWidth(True) = .Width / Screen.TwipsPerPixelX / 2
        .EndUpdate
    End With
End Sub

The following VFP sample resizes the chart area as soon as the Gantt control is resized:

with thisform.Gantt1
        .BeginUpdate
        .Width = thisform.Width - 2 * .Left
        .Height = thisform.Height - 2 * .Top
        .Chart.PaneWidth(1) = .Width / 2
        .EndUpdate
endwith

The following VB.NET sample resizes the chart area as soon as the Gantt control is resized:

Private Sub AxGantt1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles AxGantt1.Resize
    With AxGantt1
        If (.IsHandleCreated) Then
            .Chart.PaneWidth(True) = .Width / 2
        End If
    End With
End Sub

The following C# sample resizes the chart area as soon as the Gantt control is resized:

private void axGantt1_Resize(object sender, EventArgs e)
{
    if (axGantt1.IsHandleCreated)
        axGantt1.Chart.set_PaneWidth(true, axGantt1.Width / 2);
}

I'm wondering if your Gantt control will print across multiple pages. Our contractors want to print out their job schedule (which may span months or years) across multiple pages both horizontally and vertically. A chart that shrinks to fit a single page doesn

Definitely it doesn't get printed to a single page. It prints on how many pages are required. If a simple page is required then the chart is printed to a single page, else it is printed on multiple pages.

How can I display currency/date format within the column?

There are several options in order to display a different content for the column. By default, the Items.CellCaption property indicates the value being shown in the cell.
  1. Column.FormatColumn property specifies a formula to display the column's new content, using predefined functions for numbers, strings, dates and so on.
  2. Change the Value parameter of the FormatColumn event which is fired if the Column.FireFormatColumn property is True. For instance the following sample displays  the second column using current currency format with 2 decimals. The Item parameter of the FormatColumn event indicates the item where the cell is hosted, the ColIndex indicates the column where the cell belongs, while the Value parameter indicates the cell's value before formatting and after. In case you need formatting multiple columns, you can distingue them using the ColIndex parameter.
    Private Sub Form_Load()
        With Gantt1
            .BeginUpdate
            .Columns.Add "A"
            .Columns.Add("B").FireFormatColumn = True ' Index of it is 1
            With .Items
                .AddItem Array("One", 1)
                .AddItem Array("Two", 2)
            End With
            .EndUpdate
        End With
    End Sub
    
    Private Sub Gantt1_FormatColumn(ByVal Item As EXGANTTLibCtl.HITEM, ByVal ColIndex As Long, Value As Variant)
        Value = FormatCurrency(Value, 2, vbUseDefault)
    End Sub

How can I drag icons from Windows Explorer and display in the control?

The OLEDropMode property of the control must be set on exOLEDropManual (1). If this property is set, the control fires the OLEDragDrop event which notifies that the user drags data to the control. The Files collection holds a collection of files being dragged. 

The  following VB sample copies the original icon being displayed in Windows Explorer and displays it on the control:

The sample uses the SHGetFileInfo API function to retrieve the handle of the icon ( HICON ) to be copied and displayed in the control.

How can I limit the scrolling range for the chart view?

If you want to limit just a margin of the chart, you can handle the DateChange event to specify the correct value for the FirstVisibleDate property of the Chart object like in the following sample:
Private Function Max(a, b)
    If (a < b) Then
        Max = b
    Else
        Max = a
    End If
End Function

Private Sub Gantt1_DateChange()
    With Gantt1
        Dim dLimit As Date
        dLimit = #1/1/2010#
        .Chart.FirstVisibleDate = Max(dLimit, .Chart.FirstVisibleDate)
        .ScrollPartEnable(exHChartScroll, exLeftBPart) = .Chart.FirstVisibleDate > dLimit
    End With
End Sub

The sample limits the FirstVisibleDate property of the chart so it won't be less than January 1st of 2010, and disables the left scroll button in the chart if FirstVisibleDate property is at limit.

The bars are shown if I run the application on my machine but they are not visible if I run on other machine. What is happening here?

The most probably the problem is that on one machine the date-time are read correctly, while on the other is not, and this is happen due different settings for Date-Time in the control panel. We would suggest checking the following:
  • check the type for DateStart and DateEnd parameters of the AddBar method. If this is not of DateTime type, make sure that the values being used are correctly formatted on the machine with the problem. For instance, the string "1/2/2001" on a machine with English DateTime set indicates the January the 2nd, while on a German machine, it means February the 1st.
  • check the Regional and Language options on your machine and the other machine. This way you can see the difference.

Suggestion: Use the DateTime type ( or equivalent for your developing language ) for DateStart/DateEnd parameters of the AddBar method of Items objects.

I am using multiple selection. How can I remove all selected items?

Here is 2 options to remove the selected items in the control:
  1. Collects the items to be removed, using the Items.SelectCount and Items.SelectedItem properties. Once the collection is completed, you can call the Items.RemoveItem for each element being found.
  2. While the Items.SelectCount property is greater than 0, call the Items.RemoveItem( Items.SelectedItem(0) ), so removes the first selected item until all all released.

The following VB sample shows the method 1:

Private Sub removeSelection1()

    Dim i As Long, h As Variant
    Dim cItems As New Collection
    
    Gantt1.BeginUpdate
    With Gantt1.Items
        For i = 0 To .SelectCount - 1
            cItems.Add .SelectedItem(i)
        Next
        For Each h In cItems
            .RemoveItem h
        Next
    End With
    Gantt1.EndUpdate
    
End Sub

The following VB sample shows the method 2:

Private Sub removeSelection2()
    
    Gantt1.BeginUpdate
    With Gantt1.Items
        While .SelectCount > 0
            .RemoveItem .SelectedItem(0)
        Wend
    End With
    Gantt1.EndUpdate

End Sub

I am using the EnsureVisibleItem/ScrollPos method but seems that it is not working?

You should call the DoEvents method before calling the EnsureVisibleItem method. For /NET you should use the Application.DoEvents method. For Delphi, you should use the Application.ProcessMessages.

A C++ replica for DoEvents could be:

static void DoEvents()
{
	MSG m = {0};
	while ( PeekMessage( &m, NULL, NULL, NULL, PM_REMOVE ) )
	{
		TranslateMessage( &m );
		DispatchMessage( &m );
	}
}

What is the best way to loop or enumerate through all the items in the control and extract cell data?

There are the several ways of enumerating the items/cells in the control. The following samples are in VB, but they can be easily converted to any other programming language. This samples shows you an idea how easily you can enumerate through the items.

A). Using the GetItems method of the control. The GetItems method gets the items as they are displayed, sorted and filtered to an array or vector. Also, the GetItems method collect the child items as well, no matter if the parent item is collapsed. The GetItems method returns an array. For instance, if your control contains 1 column, the GetItems will retrieves a one-dimensional array. A 2 columns will get a two-dimensional array, an so on. You can use the PutItems method to insert the array to the control.

B). Using the for each statement for Items property of the control. The Items property gets a collection of items as they were added. This method lists the items by index not by their positions. The items is represented by handles, so the handle can be used in the Cell properties to refer the cell. For instance, Items.CellCaption(Handle,Column) gets the cell from the Item with the specified handle on specified column. The following sample displays the cells in the first column as they were added:

With Gantt1
        Dim h As Variant
        For Each h In .Items
            Debug.Print .Items.CellCaption(h, 0)
        Next
End With

If you need to access multiple columns add the Debug.Print .Items.CellCaption(h, 1), Debug.Print .Items.CellCaption(h, 2) ... for each column you require.

C). A similar approach to B is using the Items.ItemCount and Items.ItemByIndex properties. This method lists the items by index not by their positions.

With Gantt1
    Dim i As Long
    With .Items
        For i = 0 To .ItemCount - 1
            Debug.Print .CellCaption(.ItemByIndex(i), 0)
        Next
    End With
End With

The Items. ItemByIndex retrieves the handle of the item giving its index. For instance, the first added item has the index 0, the second added item has the index 1, and so on.

D). Using the Items.NextVisibleItem property. This method gets the items as they are displayed, sorted and filtered.

With Gantt1
    With .Items
        Dim h As Long
        h = .RootItem(0)
        While Not h = 0
            Debug.Print .CellCaption(h, 0)
            h = .NextVisibleItem(h)
        Wend
    End With
End With

E). Using the Items.ItemChild and Items.NextSiblingItem property. This method enumerates recursively the items and its children. This method gets the items as they are displayed, sorted and filtered, including the children items that are not visible aka parent item is collapsed.

With Gantt1
    With .Items
        For i = 0 To .RootCount - 1
            RecItem Gantt1, .RootItem(i)
        Next
    End With
End With
Sub RecItem(ByVal c As Object, ByVal h As Long)
    If Not (h = 0) Then
        Dim hChild As Long
        With c.Items
            Debug.Print .CellCaption(h, 0)
            hChild = .ItemChild(h)
            While Not (hChild = 0)
                RecItem c, hChild
                hChild = .NextSiblingItem(hChild)
            Wend
        End With
    End If
End Sub

How do I enumerate all selected/active/focus items/rows/values?

The SingleSel property specifies whether the control supports single or multiple selected items. If the SingleSel property is True ( by default ), the user can select a single item/row only. The Items.FocusItem property indicates the handle of the item that has the focus. The control fires the SelectionChanged event when the control's selection is changed. The SelectCount property specifies the count of selected items/rows. If the SingleSel property is True, the SelectCount property can be 0 or 1.

The following code displays the selected values:

Private Sub enumSelection(ByVal g As Object)
    With g.Items
        For i = 1 To .SelectCount
            Debug.Print .CellCaption(.SelectedItem(i - 1), 0)
        Next
    End With
End Sub

Private Sub Gantt1_SelectionChanged()
    enumSelection Gantt1
End Sub

As the control supports multiple columns, the following code displays the selected values for all columns:

Private Sub enumSelection(ByVal g As Object)
    With g.Items
        Dim nColumns As Long
        nColumns = g.Columns.Count
        For i = 1 To .SelectCount
            Dim h As HITEM
            h = .SelectedItem(i - 1)
            For j = 1 To nColumns
                Debug.Print .CellCaption(h, j - 1)
            Next
        Next
    End With
End Sub

Private Sub Gantt1_SelectionChanged()
    enumSelection Gantt1
End Sub

Can I use arrays to load to your control?

Here's some ideas on how you can use arrays with the control.

A). Using the GetItems/PutItems to get or put the items/cells using arrays. The GetItems method gets the items/cells of the control to a safe array. The PutItems inserts the array of values to the control. For instance the following sample adds 3 columns and 1001 items from an array:

/COM version

With Gantt1
    .Columns.Add "C1"
    .Columns.Add "C2"
    .Columns.Add "C3"
    Dim v(2, 1000) As String
    v(1, 10) = "zece"
    .PutItems v
End With

In VB the arrays is zero-based, so 2 indicates actually 0, 1 and 2 ( 3 columns ).

/NET or /WPF version

With Exgantt1
    .Columns.Add("C1")
    .Columns.Add("C2")
    .Columns.Add("C3")
    Dim v(2, 1000) As String
    v(1, 10) = "zece"
    .PutItems(v)
End With

B1). You can use the PutItems method to insert a hierarchy, for single-column control. The following sample adds a hierarchy as Root\Child 1, Child 2\SubChild 1, SubChild 2

/COM version

With Gantt1
    .LinesAtRoot = exLinesAtRoot
    .Columns.Add "Nodes"
    .PutItems Array("Root", Array("Child 1", "Child 2", Array("SubChild 1", "SubChild 2")))
End With

/NET or /WPF version

With Exgantt1
    .LinesAtRoot = exontrol.EXGANTTLib.LinesAtRootEnum.exLinesAtRoot
    .Columns.Add("Nodes")
    .PutItems(New Object() {"Root", New Object() {"Child 1", "Child 2", New Object() {"SubChild 1", "SubChild 2"}}})
End With

B2). You can use the PutItems method to insert a hierarchy, for single-column control, as child items. The following sample adds an item New, and a sub-hierarchy Root\Child 1, Child 2\SubChild 1, SubChild 2

/COM version

With Gantt1
    .LinesAtRoot = exLinesAtRoot
    .Columns.Add "Nodes"
    .PutItems Array("Root", Array("Child 1", "Child 2", Array("SubChild 1", "SubChild 2"))), .Items.AddItem("new")
End With

/NET or /WPF version

With Exgantt1
    .LinesAtRoot = exontrol.EXGANTTLib.LinesAtRootEnum.exLinesAtRoot
    .Columns.Add("Nodes")
    .PutItems(New Object() {"Root", New Object() {"Child 1", "Child 2", New Object() {"SubChild 1", "SubChild 2"}}}, .Items.AddItem("new"))
End With

C). You can use the arrays to fill a multiple-columns control in Items.AddItem/Items.InsertItem methods as in the following sample:

/COM version

With Gantt1
    .Columns.Add "C1"
    .Columns.Add "C2"
    .Columns.Add "C3"
    With .Items
        .AddItem Array("Cell 1.1", "Cell 1.2", "Cell 1.3")
        .AddItem Array("Cell 2.1", "Cell 2.2", "Cell 2.3")
    End With
End With

/NET or /WPF version

With Exgantt1
    .Columns.Add("C1")
    .Columns.Add("C2")
    .Columns.Add("C3")
    With .Items
        .AddItem(New Object() {"Cell 1.1", "Cell 1.2", "Cell 1.3"})
        .AddItem(New Object() {"Cell 2.1", "Cell 2.2", "Cell 2.3"})
    End With
End With

How can I prevent updating the control while I do a Print and Print Preview?

The control provides the Print and Print Preview using the Exontrol's ExPrint component. Please check the printing FAQ for adding Print and Print Preview support in your programming language. 

In order to prevent updating the control during Print and PrintPreview you need to call the BeginUpdate of the control during the Refreshing event of the eXPrint,  and call the EndUpdate once the Refresh event of the eXPrint occurs, like in the following sample.

Private Sub Print1_Refreshing()
    Gantt1.BeginUpdate
End Sub

Private Sub Print1_Refresh()
    Gantt1.EndUpdate
End Sub

The ItemFromPoint(-1,-1) property seems that it is not working. What could be the problem?

The ItemFromPoint(-1,-1) property gets the handle if the item, index of the column and the hit-test position from the cursor position. Usually, the you think that the ItemFromPoint(-1,-1) is not working in debug mode, because you have set the breakpoint on the property itself, and you are moving the cursor position by the time the ItemFromPoint property is called. What you can do, is to set the break-point after calling the ItemFromPoint property is called, so the correct position of the cursor is taken when the property is invoked. In other words, please add the following code, and see that the handle of the item being clicked is displayed correctly, like in the following VB sample:

Private Sub Gantt1_Click()
    Dim c As Long, hit As EXGANTTLibCtl.HitTestInfoEnum
    Debug.Print Gantt1.ItemFromPoint(-1, -1, c, hit)
End Sub

The BeforeExpandItem event seems to be fired when user clicks the drop down filter button. What can be?

The BeforeExpandItem event is fired when an item is about to be expanded, by code or using the control's user interface ( such as clicking the +/- expanding button ). Also, the BeforeExpandItem event may occur for items with the ItemHasChildren property set on True, when the user clicks the filter drop down button. This is by design, to include not-loaded items in the drop down filter window. Usually, the BeforeExpandItem event is used to load virtually a hierarchy, for instance, when the user clicks the +/- expanding button.

The following methods, can be used to prevent firing the BeforeExpandItem event when the user clicks the drop down filter button:
  1. Use no ItemHasChildren property on True, in other words you can load on init time, the entire hierarchy collection
  2. Set the FilterList property of the Column object to exRootItems value (4), so no child items are collected in the drop down filter list
  3. Use a counter that's increased when MouseDown event occurs and it is decreased when MouseUp event is fired. You can use the ColumnFromPoint property to check if the user clicks the headers. During the BeforeExpandItem event you can prevent adding a sub-child if the counter is not zero.

Is there any option to check if a filter is applied to any of the columns in the control (hasfilter)?

The control's ClearFilter method ( or clicking the X button in the filter bar ) does the following:
  • set the Column.Filter property on empty, IF the Column.FilterType property is exNumeric, exCheck or exImage, else
  • set the Column.FilterType property on exAll. IF the Column.FilterOnType property is True, the Column.Filter is set on empty too, else the Column.Filter property remains.

The FilterType property of the Column object indicates the type of the filter to be applied on the column. Generally, you can check for exAll on FiterType unless you are not using the exNumeric, exCheck or exImage type of column's filters. 

The following VB function returns False, if no filter is applied, or True, if any filter is applied. This sample works ok, if no using any of exNumeric, exCheck or exImage types

Private Function hasFilter(ByVal g As Object) As Boolean
    Dim c As Object
    For Each c In g.Columns
        If Not (c.FilterType = 0) Then
            hasFilter = True
            Exit Function
        End If
    Next
    hasFilter = False
End Function

The following VB function returns False, if no filter is applied, or True, if any filter is applied. This sample works for all type of filters:

Private Function hasFilter(ByVal g As Object) As Boolean
    Dim c As Object
    For Each c In g.Columns
        Select Case c.FilterType
            Case 5, 6, 10                           ' exNumeric, exCheck, exImage
                hasFilter = Not (c.Filter.Length = 0)
            Case Else
                hasFilter = Not (c.FilterType = 0)  ' exAll
        End Select
        If (hasFilter) Then
            Exit Function
        End If
    Next
    hasFilter = False
End Function

How can I implement the Fit-To-Page feature when doing Print and PrintPreview for the control's chart?

Starting with the version 8.0, the control supports Fit-To-Page feature, using the FitToPage = On option.

The FitToPage option could be one of the following:

  • On, (Fit-To-Page) the control's content is printed to a single page ( version 8.0 )
  • p%, (Adjust-To) where p is a positive number that indicates the percent from normal size to adjust to. For instance, the "FitToPage = 50%" adjusts the control's content to 50% from normal size. ( version 8.0 )
  • w x, (Fit-To Wide) where w is a positive number that indicates that the control's content fits w pages wide by how many pages tall are required. For instance, "FitToPage = 3 x" fits the control's content to 3 pages wide by how many pages tall is are required. ( version 8.0 )
  • x t, (Fit-To Tall) where t is a positive number that specifies that the control's content fits t pages tall by how many pages wide are required. For instance, "FitToPage = x 2" fits the control's content to 2 pages tall by how many pages wide are required. ( version 8.0 )
  • w x t, (Fit-To) where w and t are positive numbers that specifies that the control's content fits w pages wide by t pages tall. For instance, "FitToPage = 3 x 2" fits the control's content to 3 pages wide by 2 pages tall. ( version 8.0 )

The following VB sample changes the UnitWidth property of the eXG2ant's Chart object so, the entire chart is printed to a single page:

With Print1
    Dim l As Long
    With Gantt1.Chart
        l = .UnitWidth
        .UnitWidth = (Print1.ClientWidth - .PaneWidth(False)) / .CountVisibleUnits()
    End With
    Set .PrintExt = Gantt1.Object
    .Preview
    Gantt1.Chart.UnitWidth = l
End With

The equivalent sample in dBASE Plus is:

local oPrint,oGantt
oPrint = form.exprint.nativeObject
oGantt = form.Activex1.nativeObject

local l
l = oGantt.Chart.UnitWidth
oGantt.Chart.UnitWidth = (oPrint.ClientWidth() - oGantt.Chart.PaneWidth(.f.)) / oGantt.Chart.CountVisibleUnits()

oPrint.PrintExt = form.Activex1.nativeObject
oPrint.Preview()

oGantt.Chart.UnitWidth = l

The sample has the disadvantage that once the user changes the Page's setup during Previewing the code is not re-executed, so the chart is displayed as it is on the screen. In order to update the UnitWidth property once the page's setup is changed, we need to handle the Refreshing and Refresh events of the eXPrint component as shown in the following VB sample:

Dim nUnitWidth As Long

Private Sub Print1_Refreshing()
    With Gantt1.Chart
        nUnitWidth = .UnitWidth
        .UnitWidth = (Print1.ClientWidth - .PaneWidth(False)) / .CountVisibleUnits()
    End With
End Sub

Private Sub Print1_Refresh()
    Gantt1.Chart.UnitWidth = nUnitWidth
End Sub

Private Sub Preview_Click()
    With Print1
        Set .PrintExt = Gantt1.Object
        .Preview
    End With
End Sub

The sample changes the UnitWidth property of the Chart during the Refreshing event, so the chart fits to page, and restores the UnitWidth's value when the Refresh event is invoked. 

The following VB/NET sample changes the UnitWidth property so the chart fits to page:

Dim nUnitWidth As Long

Private Sub Exprint1_RefreshingEvent(ByVal sender As System.Object) Handles Exprint1.RefreshingEvent
    With ExGantt1.Chart
        nUnitWidth = .UnitWidth
        .UnitWidth = (Exprint1.ClientWidth - .get_PaneWidth(False)) / .CountVisibleUnits()
    End With
End Sub

Private Sub Exprint1_RefreshEvent(ByVal sender As System.Object) Handles Exprint1.RefreshEvent
    ExGantt1.Chart.UnitWidth = nUnitWidth
End Sub

Private Sub Preview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Preview.Click
    Exprint1.PrintExt = ExGantt1
    Exprint1.Preview()
End Sub

I can not find the Items.ItemByIndex property. How can I use it?

The Items.ItemByIndex(index) property gets the handle of the item/row giving its index.

If you can not locate the ItemByIndex property in the Items collection you should look for Items.get_ItemByIndex(index), Items[index] or Items(index) instead.

The tooltip is not hidden, when a message box is displayed. How can I programmatically hide the tooltip?

The tooltip is automatically hidden when user moves the mouse or a key is pressed. In case a message box or a form is shown, none of them is happen, so the tooltip may still be shown. For that, you can call the PostMessage .hwnd, 512, 0, 0 before showing your message or dialog like in the following sample. The hWnd indicates the handle of the control ( hWnd property ).
Private Sub Gantt1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If (Button = 2) Then
        With Gantt1
            Dim i As Long, c As Long, hit As HitTestInfoEnum
            i = .ItemFromPoint(-1, -1, c, hit)
            If Not i = 0 Then
                PostMessage .hwnd, &H200, 0, 0
                MsgBox .Items.CellCaption(i, c)
            End If
        End With
    End If
End Sub

I have two controls, how can I synchronize the scroll position?

The ScrollPos property changes the control's scroll position ( horizontal or vertical scroll position ). The OffsetChanged event occurs when the control's scroll horizontal or vertical position is changed, in other words all it is required is calling the ScrollPos during the OffsetChanged like in the following sample. Because the ScrollPos property invokes the OffsetChanged, you must use a member flag ( iSyncing ) to prevent recursive calls:
Private iSyncing As Long

Private Sub Gantt1_OffsetChanged(ByVal Horizontal As Boolean, ByVal NewVal As Long)
    If (iSyncing = 0) Then
        iSyncing = iSyncing + 1
            Gantt2.ScrollPos(Not Horizontal) = NewVal
        iSyncing = iSyncing - 1
    End If
End Sub

Private Sub Gantt2_OffsetChanged(ByVal Horizontal As Boolean, ByVal NewVal As Long)
    If (iSyncing = 0) Then
        iSyncing = iSyncing + 1
            Gantt1.ScrollPos(Not Horizontal) = NewVal
        iSyncing = iSyncing - 1
    End If
End Sub

This sample synchronizes the vertical  / horizontal scroll bars of both controls, so when the user scrolls one of the control's content, the other component is syncing as well. 

In order to synchronize the date in the chart portion of the control ( right side scroll bar ), you need to handle the DateChange event like in the following sample:

Private Sub Gantt1_DateChange()
    If (iSyncing = 0) Then
        iSyncing = iSyncing + 1
            With Gantt2
                .BeginUpdate
                .Chart.FirstVisibleDate = Gantt1.Chart.FirstVisibleDate
                .EndUpdate
            End With
        iSyncing = iSyncing - 1
    End If
End Sub

Private Sub Gantt2_DateChange()
    If (iSyncing = 0) Then
        iSyncing = iSyncing + 1
            With Gantt1
                .BeginUpdate
                .Chart.FirstVisibleDate = Gantt2.Chart.FirstVisibleDate
                .EndUpdate
            End With
        iSyncing = iSyncing - 1
    End If
End Sub

This snippet of code changes the control's FirstVisibleDate property when the other's control is calling the DateChange eventd.