exschedule - faq

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

  • Open the Run dialog on your Windows, and type exg2antt.chm, to run the exg2antt's help file. By default, the setup installs the CHM file into your system folder, so you can open the control's help / documentation by typing the control's name followed by .chm extension in the Run dialog box.
  • Locate and Run the ExG2antt.chm shortcut from the component's folder.
  • For How-To questions, you can run the ExHelper.exe shortcut located in the component's folder.
  • For How-To questions, you can locate and run the HOWTODO.chm shortcut from the component's folder.

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 - ExSchedule FAQ page

Frequently Asked Questions - ExSchedule 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.

Performance tips

If you have performance issues with the control, please consider the followings:

  • (valid for all versions) Use the BeginUpdate/EndUpdate when multiple changes are performed, like loading a set of events. The BeginUpdate methods prevents the control from painting until the EndUpdate method is called. In other words, when a change occurs, the control 's is updated once, when the last EndUpdate method is encountered.

  • (valid for all versions) If you have a large database, that includes events from different years, loads events from the browsing year only. You can use the Year( Calendar.Date ) to get the browsing year, or the year displayed in the calendar panel of the control. The LayoutEndChanging(exCalendarDateChange) event is fired once a new date/year is browsed. Handle the LayoutEndChanging event when exCalendarDateChange operation occurs, get the year using the Calendar.Date property and loads if necessary the events of the new year. You can use a hash table to save the years being loaded, to prevent loading the same year twice. Also, you should use the best code to load or retrieve the events from your database, so it won't be a time consuming.  In the same way, you can improve the speed if necessary to load only the required events, for instance for a month, and so on, not really need to load the events for the entire year.

  • (valid for versions prior to 7.1.1.0) Set the properties: DefaultEventLongLabel, DefaultEventShortLabel, DefaultEventTooltip  to "", empty string. These properties support expressions and built-in HTML tags, and as soon as a new event is added, the LongLabel, ShortLabel and ToolTip properties of the event are initialized and parsed with the associated value, which could be a time consuming. Newer versions, does not require setting the DefaultEventLongLabel, DefaultEventShortLabel, DefaultEventTooltip properties

For instance, the following VB6 sample loads events from a database, using ADO:

Dim d As Long
d = GetTickCount()
With Schedule1
    .BeginUpdate
        .DefaultEventLongLabel = "<%=%5%><br><%=%256%>"
        .DefaultEventShortLabel = .DefaultEventLongLabel
        .DefaultEventTooltip = .DefaultEventLongLabel
        .Events.Clear
        Dim rs As Object
        Set rs = CreateObject("ADOR.Recordset")
        Dim iCount As Long
        iCount = 0
        With rs
            .Open "Event", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\xScheduler.mdb", 3, 3
            Schedule1.Calendar.Selection = Fix(rs("StartDateTime").Value)
            While Not .EOF() And iCount < 2000
                With Schedule1.Events.Add(rs("StartDateTime").Value, rs("EndDateTime").Value)
                    Dim v As Variant
                    v = rs("Subject").Value
                    .Caption = IIf(IsNull(v), "", v)
                    .Editable = exEditCaption
                    iCount = iCount + 1
                End With
                rs.MoveNext
            Wend
        End With
    .EndUpdate
End With
d = GetTickCount() - d
MsgBox (Schedule1.Events.Count & " events loaded in " & d & " msec")

The time to load 2000 events, using ADO, in VB6  is 63 milliseconds.

For instance, the following MS Access sample loads events from a database, using DAO:

Dim d As Long
d = GetTickCount()
With Schedule1
    .BeginUpdate
        .DefaultEventLongLabel = "<%=%5%><br><%=%256%>"
        .DefaultEventShortLabel = .DefaultEventLongLabel
        .DefaultEventTooltip = .DefaultEventLongLabel
        .Events.Clear
        Dim rs As Object
        Set rs = CurrentDb.OpenRecordset("Event", dbOpenTable)
        Dim iCount As Long
        iCount = 0
        With rs
            Schedule1.Calendar.Selection = Fix(rs("StartDateTime").Value)
            While Not .EOF() And iCount < 2000
                With Schedule1.Events.Add(rs("StartDateTime").Value, rs("EndDateTime").Value)
                    Dim v As Variant
                    v = rs("Subject").Value
                    .Caption = IIf(IsNull(v), "", v)
                    .Editable = exEditCaption
                    iCount = iCount + 1
                End With
                rs.MoveNext
            Wend
        End With
    .EndUpdate
End With
d = GetTickCount() - d
MsgBox (Schedule1.Events.Count & " events loaded in " & d & " msec")

The time to load 2000 events, using DAO in MS Access, is 265 milliseconds.

In conclusion, we have did a simple sample that counts the number of records from a table using ADO ( in VB6 ) vs DAO ( MS Access ). 

The following VB6 sample HAS nothing to do with our component, JUST counts the number of records in a large table:

Dim d As Long
d = GetTickCount()
Dim rs As Object
Set rs = CreateObject("ADOR.Recordset")
Dim iCount As Long
With rs
    .Open "Event", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\xScheduler.mdb", 3, 3
    While Not .EOF()
        iCount = iCount + 1
        rs.MoveNext
    Wend
End With
d = GetTickCount() - d
MsgBox ("Enumerate " & iCount & " records in " & d & " msec") 

The time to count 88132 records, using ADO, in VB6 is is 421 msec.

The following MS Access sample HAS nothing to do with our component, JUST counts the number of records in a large table:

Dim d As Long
d = GetTickCount()
Dim rs As Object
Set rs = CreateObject("ADOR.Recordset")
Dim iCount As Long
With rs
    .Open "Event", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\xScheduler.mdb", 3, 3
    While Not .EOF()
        iCount = iCount + 1
        rs.MoveNext
    Wend
End With
d = GetTickCount() - d
MsgBox ("Enumerate " & iCount & " records in " & d & " msec") 

The time to count 88132 records, using ADO, in VB6 is is 702 msec.

Here's the definition for the GetTickCount API function

Private Declare Function GetTickCount Lib "kernel32" () As Long
        

Is it possible to place the calendar panel on another place?

By default, the calendar panel can be:
  • auto hide the calendar panel. Ability to hide the calendar section while the cursor is not in it (OnResizeControlEnum.exResizePanelRight Or OnResizeControlEnum.exCalendarFit Or OnResizeControlEnum.exCalendarAutoHide)
  • hide completely the calendar section (exHideSplitter)
  • specify the alignment of the calendar, as on the left or right side of the schedule view (OnResizeControlEnum.exChangePanels Or OnResizeControlEnum.exCalendarFit) 
  • full or partially view of the calendar panel (exResizePanelRight) 
  • disabling the control's vertical split bar ( so user can not resize the fixed panel ) (OnResizeControlEnum.exResizePanelRight Or OnResizeControlEnum.exDisableSplitter Or OnResizeControlEnum.exCalendarFit)

All these, can be changed using the OnResizeControl property.

In case, you need to place the calendar panel to some other place, you need to use the Calendar.Parent property as shown bellow. The Calendar.Panel allows to specify the handle of the window that hosts the calendar panel. In this case, the OnResizeControl property has no effect. Using the Calendar.Parent property you can move the calendar panel from the scheduler to any other window/place. 

Here's how you can place the scheduler and the calendar to different places:

  • Insert two eXSchedule components to the same form, with names: Schedule1 and Schedule2
  • Handle the Load event of the form/dialog and call the following code
    Private Sub Form_Load()
        Schedule1.Calendar.Parent = Schedule2.hWnd
    End Sub

This way the second scheduler component acts as a host for the calendar panel of the first schedule component. Any action on the schedule or calendar will be reflected on both. When a window hosts the calendar panel, it fits the entire client area. In case you re-size the window that hosts the calendar panel, you can re-assign the Calendar.Parent property, so the calendar panel updates its size so it fits the new client area of the host.

Is it possible to count the events within specified date?

The control provides the DateEvents property that gives a collection/safe array of Event objects in the specified date. Using the DateEvents property you can count the number of events / appointments within a date.

The following VB6 sample enumerates the Event objects found in the selected date ( calendar panel selection )

With Schedule1
    Dim c As Variant
    For Each c In .DateEvents(.Calendar.SelDate(0))
        Debug.Print c.Start
    Next
End With

The following VB6 sample counts the number of Event objects within each group found within the giving date:

With Schedule1
    Dim c As Variant
    Dim e As New Dictionary, d As Variant
    For Each c In .DateEvents(.Calendar.SelDate(0))
        e(c.GroupID) = CLng(e(c.GroupID)) + 1
    Next
    Dim i As Variant
    For Each i In e
        Debug.Print "GroupID: " & i & " contains " & e(i)
    Next
End With

The sample uses the Dictionary object of Microsoft Scripting Runtime.

Hww do I set the caption for a recently added event?

There are several ways of setting the caption within the event. The ShortLabel, LongLabel, ExtraLabel and BodyBackgroundExt properties of the Event object may specify a caption to be displayed in the event. The AddEvent event notifies your application once a new event is added to the scheduler. The AddEvent event is fired also when the user adds the events by code. The LayoutStartChanging(exScheduleCreateEvent) / LayoutEndChanging(exScheduleCreateEvent) events notify your application once the user starts creating an event by dragging the mouse over the control. 

The following VB6 sample changes the event's caption when a new event is added to the scheduler:

' AddEvent event - Notifies your application once the a new event is added.
Private Sub Schedule1_AddEvent(ByVal Ev As EXSCHEDULELibCtl.IEvent)
    With Schedule1
        With Ev
            .ShortLabel = "short"
            .LongLabel = "long"
            .ExtraLabel = "extra"
            .BodyBackgroundExt = "root[text=`back`,align=0x11]"
        End With
    End With
End Sub

The following VB6 changes the caption just for the events added by the user:

Dim iCreateEvent As Long

Private Sub Schedule1_LayoutStartChanging(ByVal Operation As EXSCHEDULELibCtl.LayoutChangingEnum)
    If (Operation = exScheduleCreateEvent) Then
        iCreateEvent = iCreateEvent + 1
    End If
End Sub

Private Sub Schedule1_LayoutEndChanging(ByVal Operation As EXSCHEDULELibCtl.LayoutChangingEnum)
    If (Operation = exScheduleCreateEvent) Then
        iCreateEvent = iCreateEvent - 1
    End If
End Sub

Private Sub Schedule1_AddEvent(ByVal Ev As EXSCHEDULELibCtl.IEvent)
    If Not (iCreateEvent = 0) Then
        With Schedule1
            With Ev
                .ShortLabel = "short"
                .LongLabel = "long"
                .ExtraLabel = "extra"
                .BodyBackgroundExt = "root[text=`back`,align=0x11]"
            End With
        End With
    End If
End Sub

The sample changes the iCreateEvent member when the exScheduleCreateEvent event occurs, so we know that the user creates a new event at runtime.

How can I specify multiple colors to be shown on the event?

The BodyBackgroundExt property of the Event object can be used to specify multiple captions, icons, pictures, frames, patterns on the same event. 

Easy samples:

  • "[pattern=6]", shows the BDiagonal pattern on the object's background.

  • "[frame=RGB(255,0,0),framethick]", draws a red thick-border around the object.

  • "[frame=RGB(255,0,0),framethick,pattern=6,patterncolor=RGB(255,0,0)]", draws a red thick-border around the object, with a patter inside.

  • "[[patterncolor=RGB(255,0,0)](none[(4,4,100%-8,100%-8),pattern=0x006,patterncolor=RGB(255,0,0),frame=RGB(255,0,0),framethick])]", draws a red thick-border around the object, with a patter inside, with a 4-pixels wide padding:

  • "top[4,back=RGB(0,0,255)]", draws a blue line on the top side of the object's background, of 4-pixels wide.

  • "[text=`caption`,align=0x22]", shows the caption string aligned to the bottom-right side of the object's background.

  • "[text=`<img>flag</img>`,align=0x11]" shows the flag picture and the sweden string aligned to the bottom side of the object.

  • "left[10,back=RGB(255,0,0)]", draws a red line on the left side of the object's background, of 10-pixels wide.

  • "bottom[50%,pattern=6,frame]", shows the BDiagonal pattern with a border arround on the lower-half part of the object's background.

  • "root[text=`caption <b>2`,align=0x22](client[text=`caption <b>1`,align=0x20])", shows the caption 1 aligned to the bottom-left side, and the caption 2 to the bottom-right side

Complex samples:

Now, lets say we have the following request to layout the colors on the objects:

We define the BodyBackgroundExt property such as "top[30%,back=RGB(253,218,101)],client[back=RGB(91,157,210)],none[(0%,0%,10%,100%)](top[90%,back=RGB(0,0,0)])", and it looks as:

so, if we apply to our object we got:

Now, lets say we have the following request to layout the colors on the objects:

We define BodyBackgroundExt property such as "left[10%](top[90%,back=RGB(0,0,0)]),top[30%,back=RGB(254,217,102)],client[back=RGB(91,156,212)]", and it looks as:

so, if we apply to our object we got:

 

The Exontrol's eXButton WYSWYG Builder helps you to generate or view the EBN String Format, in the To String field as shown in the following screen shot: 

The To String field of the EBN Builder defines the EBN String Format that can be used on BodyBackgroundExt property.

The EBN String Format syntax in BNF notation is defined like follows:

<EBN> ::= <elements> | <root> "(" [<elements>] ")"
<elements> ::= <element> [ "," <elements> ]
<root> ::= "root" [ <attributes> ] | [ <attributes> ]
<element> ::= <anchor> [ <attributes> ] [ "(" [<elements>] ")" ]
<anchor> ::= "none" | "left" | "right" | "client" | "top" | "bottom"
<attributes> ::= "[" [<client> ","] <attribute> [ "," <attributes> ] "]"
<client> ::= <expression> | <expression> "," <expression> "," <expression> "," <expression>
<expression> ::= <number> | <number> "%"
<attribute> ::= <backcolor> | <text> | <wordwrap> | <align> | <pattern> | <patterncolor> | <frame> | <framethick> | <data> | <others>
<equal> ::= "="
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<decimal> ::= <digit><decimal>
<hexadigit> ::= <digit> | "A" | "B"  "C" | "D" | "E"  "F"
<hexa> ::= <hexadigit><hexa>
<number> ::= <decimal> | "0x" <hexa>
<color> ::= <rgbcolor> | number
<rgbcolor> ::= "RGB" "(" <number> "," <number> "," <number> ")"
<string> ::= "`" <characters> "`" | "'" <characters> "'" | " <characters> "
<characters> ::= <char>|<characters>
<char> ::= <any_character_excepts_null>
<backcolor> ::= "back" <equal> <color>
<text> ::= "text" <equal> <string>
<align> ::= "align" <equal> <number>
<pattern> ::= "pattern" <equal> <number>
<patterncolor> ::= "patterncolor" <equal> <color>
<frame> ::= "frame" <equal> <color>
<data> ::= "data" <equal> <number> | <string>
<framethick> ::= "framethick"
<wordwrap> ::= "wordwrap"

Others like: pic, stretch, hstretch, vstretch, transparent, from, to are reserved for future use only.

The schedule/calendar does not show the new selection while I am using programmatically the Selection property of the Calendar object?

This is usually happens when the Selection property uses expressions and the browsing year is different than what you have selected. For instance, Calendar.Selection = "value in (#5/4/2002#,#5/5/2002#)", indicates that you want to select the #5/4/2002# and #5/5/2002# dates, but still the scheduler displays the current year ( another year than 2002 )

Instead using a code like:

Calendar.Selection = "value in (#5/4/2002#,#5/5/2002#)"

you shall use a code like:

.Calendar.Selection = #5/4/2002#
.Calendar.Selection = "value in (#5/4/2002#,#5/5/2002#)"

The difference, is that the second code, calls additionally the Calendar.Selection = #5/4/2002# ( selects a date within the year being used in the expression ), which makes the controls to display/browse for a new year, the year being used in the Selection's expression.

How can I scroll the control's content using the PageUp / PageDown keys?

By default, the PageUp/PageDown keys advances the selected date to the prev/next month. You can change this behavior by handling the KeyDown event by doing the following:
  • Set the KeyCode parameter to 0, so no further/default action for specified key is performed. In case you are using a programming language that does not support changing the value of the parameter passed by reference ( like uniPaas 1.5 (formerly known as eDeveloper), DBase, and so on ), you can use the EventParam(0) = 0 or Template = "EventParam(0) = 0", ...
  • Update the DayViewOffsetY property with the height of a day in the schedule view.

The following sample implements PageUp/Page Down keys to vertical scrolling the view by page:

Private Sub Schedule1_KeyDown(KeyCode As Integer, Shift As Integer)
    If KeyCode = 33 Then    ' PageUp
        KeyCode = 0 ' Schedule1.EventParam(0) = 0
        With Schedule1
            .DayViewOffsetY = .DayViewOffsetY - .DayViewHeight
        End With
    Else
        If KeyCode = 34 Then    ' PageDown
            KeyCode = 0 ' Schedule1.EventParam(0) = 0
            With Schedule1
                .DayViewOffsetY = .DayViewOffsetY + .DayViewHeight
            End With
        End If
    End If
End Sub

I am unable to force the headers to stay on top while still able to vertically scroll through the day. What can be done?

The exViewSingleRowLockHeader(3) of ShowViewCompact property specifies that the control locks the date header, so it is visible while user scrolls the view. If ShowViewCompact property is exViewSingleRowLockHeader, you should specify the height of a day within the schedule view by using the DayViewHeight property, so the vertical scroll bar will be shown. The following sample handles the LayoutEndChanging event, so the DayViewHeight property should be updated once the user selects a new date in the calendar panel.

The following VB sample shows how you can lock the control's header:

' LayoutStartChanging event - Notifies your application once the control's layout is about to be changed.
Private Sub Schedule1_LayoutStartChanging(ByVal Operation As EXSCHEDULELibCtl.LayoutChangingEnum)
    Schedule1_LayoutEndChanging (Operation)
End Sub

' LayoutEndChanging event - Notifies your application once the control's layout has been changed.
Private Sub Schedule1_LayoutEndChanging(ByVal Operation As EXSCHEDULELibCtl.LayoutChangingEnum)
    If (Operation = exCalendarSelectionChange Or Operation = exLayoutCalendarAutoHide) Then
        With Schedule1
            .DayViewHeight = 2016
        End With
    End If
End Sub

With Schedule1
	.BeginUpdate 
	With .Calendar
		.SelectDate(#5/20/2012#) = True
		.Select exSelectWeek
	End With
	.ScrollBars = exVertical
	.ShowViewCompact = exViewSingleRowLockHeader
	.DayViewHeight = 2016
	.AllowMoveSchedule = exDisallow
	.AllowResizeSchedule = exDisallow
	.AllowToggleSchedule = exDisallow
	.AllowExchangePanels = exDisallow
	.AllowMoveTimeScale = exDisallow
	.AllowResizeTimeScale = exDisallow
	.AllowMultiDaysEvent = False
	.TimeScales.Item(0).MinorTimeRuler = "00:10"
	.DayStartTime = "00:00"
	.DayEndTime = "24:00"
	.OnResizeControl = OnResizeControlEnum.exCalendarAutoHide Or OnResizeControlEnum.exCalendarFit Or OnResizeControlEnum.exResizePanelRight
	.EndUpdate 
End With

The LayoutStartChanging/LayoutEndChanging events keeps the height of the day to be larger than control's client area, so we have enough space for each timeslot. The LayoutStartChanging/LayoutEndChanging events change the DayViewHeight property when the user changes the selection in the control's calendar panel.

How can a double click event be triggered?

The control provides events like Click or DblClick that notifies once the user clicks / double clicks the control. By default, the control's edits the current event once the user clicks it. You can change the AllowEditEvent property to exDisallow to prevent editing the current event once the user clicks it: 

The following VB sample displays the event from the cursor, if any:

Private Sub Schedule1_Click()
    Dim e As EXSCHEDULELibCtl.Event
    With Schedule1
        Set e = .EventFromPoint(-1, -1)
        If Not e Is Nothing Then
            MsgBox e.Start & " " & e.End
        End If
    End With
End Sub

In VBA/MSAccess, you need to replace the EXSCHEDULELibCtl with EXSCHEDULELib, else you will be prompted for a compiler error: "Can't find project or library".

Copyright 1999-2017 Exontrol. All rights reserved.