The Source for ToolBook and VBTrain.Net News
From Platte Canyon Multimedia Software Corporation.
VBTrain.Net Tips and News
The biggest recent news for ToolBook developers is that Click2learn's merger with Docent has spawned SumTotal Systems. We bring you the details plus a few comments. It is time to make sure that you have moved to Instructor 2004. We offer special pricing to bring this about for customers in the U.S. and Canada.
Now is also the time to sign up for the 2004 edition of the ToolBook & VBTrain.Net User's Conference in June. We list the amazingly low pricing and phenomenally high quality of presenters as well as other details below. For those who can't make it to Colorado Springs or who can't get enough power development tips, we will begin offering one-day TBCON events before the major training conferences, starting with San Francisco in October.
We're adding so many great things to Learning & Mastering Instructor 2004 that we're still working on it. But we update you with the outline and projected schedule.
We share details from our recent shows in Germany and Atlanta and include the usual collection of ToolBook and .NET tips and tricks. Enjoy!
Many of you likely already received an email to this effect from Click2learn, but the short and sweet is that the new company name is SumTotal Systems, Inc. Right now, it looks like the new company will have offices in Mountain View , California (Docent's headquarters) and Bellevue , Washington (Click2learn's headquarters). This is in addition to other offices around the world. Andrew Eckert of Docent will be CEO and Kevin Oaks of Click2learn will be President. Here is the link for the official release:
From a developer perspective, we are thrilled with the visibility given to ToolBook on the new SumTotal web site as well as in private conversations that we have had with key players. Here's the ToolBook page on the new site:
As part of a joint "housewarming party" by Platte Canyon and SumTotal Systems, we are pleased to offer customers in the U.S. and Canada $150 off any full version of ToolBook and $100 off any upgrade through the end of March. Customers in other areas please check with your local reseller or Click2learn regional office to see if they have similar offers. The special deal of a $100 credit for full versions and a $50 credit for upgrades that can be applied to your TBCON registration or any Platte Canyon product or training class is still good as well. Here are the sale prices for Instructor (Assistant prices listed on our site as well):
Here is the link to our online store:
We have a flyer coming in the mail, but don't even wait to see it before signing up. We have an amazing lineup with the leading ToolBook and VBTrain.Net experts from around the world converging on Colorado Springs to share their expertise with you. This will be our 6th year and we are still going strong.
The list of sessions is getting too long to put in The EnterPage, so please click this link (and remember that there will be EVEN more by conference time):
Pricing is very similar to last year and well below the price for other conferences, despite the fact that all registrations include meals plus the great events on Sunday, Monday, and Tuesday nights. Sign up quickly, though, since registration prices go up by $50 on May 1st and again on June 1st.
Preconference Workshops ( http://www.tbcon.com/tbconPreconSessions.aspx ):
Hope to see you in Colorado Springs in June!
If you can't make it to Colorado Springs in June or don't want to wait a whole year between conferences, we now have the answer for you. Platte Canyon will be hosting one-day TBCON events before the major training conferences throughout the year. Right now, we have confirmed the Sunday before Training - Fall in San Francisco ( October 10, 2004 ) and the Sunday before Training - Spring in New Orleans ( February 27, 2005 ). Look for more to come. We will provide eight hours of technical sessions on ToolBook and VBTrain.Net topics. Attendees will choose the exact topic covered out of a large list of possible topics! For larger groups, we will split into separate ToolBook and VBTrain.Net groups. Price is $285 per person, which includes lunch, snacks, and beverages. Here's a link for more details or to sign up:
We're still hard at work on the latest version of our Learning & Mastering CD. We're shooting to have it shipping by TBCON in June. We hope that you'll find it worth the wait. Here's the outline:
We had the pleasure of seeing some old friends and meeting some new ones at Training - Spring in Atlanta at the beginning of March. We did quite well in the e-Assessment Shootout (with our new Exam Engine product) despite having our laptop crash when trying to read the CD of questions right as the shootout started. We found quite a bit of interest in ToolBook as well our Tracker.Net, Exam Engine, and our VBTrain.Net controls. We'll be back at next year's event in New Orleans .
We had a great time at the special ToolBook & VBTrain.Net event on February 9 in Karlsruhe , Germany . A big thanks to all the attendees as well as to Oliver Pincus of afelio GmbH for taking care of the logistics. Here is group photo:
It was a special pleasure to finally meet longtime ToolBook List contributor Cecil Cheah. Cecil has been adding .NET to his repertoire and has graciously allowed us to host his new VBTrain.Net tutorials:
John Ballard has also added some VBTrain.Net forums alongside his popular ToolBook forums at:
The Learntec exhibition itself was very large with quite elaborate displays. We ran into even more old friends from the ToolBook list as well as potential new customers. Luckily their English was better than our German!
ToolBook Tips and News
by Jeff Rhodes
CBT Question Editor
The first news on the Plug-In Pro front is that we now have a completely functional evaluation version. The only catch is that it only loads itself into books of 10 pages or less. I encourage those of you who haven't experienced the power of the Plug-In Pro to download the evaluation version at:
As we work on our Learning & Mastering CD as well as custom applications, we frequently need to edit existing question objects. Either the content has changed or we copied an existing page and question rather than dragging a new one. While there is nothing wrong with the standard question editors, it can be cumbersome to select an answer, click the Edit button, edit the answer in a popup window, click OK, go to another tab to change the weight, another to change the feedback, etc.
Enter the CBT Question Editor. You click that button on your Plug-In Pro palette and it finds all questions on the page and displays them one at a time in a special editor. You can then edit up to six answer and change their text, feedback, weight, delayed feedback, and many other properties all on one screen. A HUGE timesaver.
Here's link to the help topic for this editor so you can see what it looks like: http://www.plattecanyon.com/help/pluginpro/Editing_CBT_Questions.htm
More information on Plug-In Pro is available at:
by Jeff Rhodes
Initializing and Running ActiveX Controls
Making an ActiveX control run involves referencing it, initializing it, and then, if necessary, calling one of its methods. As a first example, the handler below uses the Windows Media Player (the object reference to it is already stored in the screenMoviePlayerID) to show a "screen movie" in a viewer. Notice how the code builds the file name of the video file based on a property of the calling page. It then sets the extFileName property to that path before opening the viewer containing the player. We don't need to explicitly call the extPlay() method since the control has been configured to automatically play.
to handle DCC_showScreenMovie page pageID system object screenMovieViewerID, screenMoviePlayerID system string s_bookPath system logical s_usingVideo local string fileName if s_usingVideo = TRUE fileName = screenMovieFileName of pageID if fileName <> null fileName = s_bookPath & fileName if isOpen of screenMovieViewerID = FALSE open screenMovieViewerID extFileName of screenMoviePlayerID = \ fileName show screenMovieViewerID end if end if end if end DCC_showScreenMovie
Another, more sophisticated, example is shown below. This code from the "Flash ActiveX Example" in the L&M CD loads the proper Flash movie (there is one per background type) by setting the extMovie property. It then calls the extSetVariable() method to set the variable that which buttons are enabled, the animation level, and the sound. It then calls another method [extTCallLabel()] to tell the player to configure itself based on the variable.
to handle updateInterface system word s_FlashButtonSettings system string s_bookPath local object l_FlashNavButtonsID, l_FlashUIButtonsID local string l_navButtonMoviePath, l_uiButtonMoviePath l_FlashNavButtonsID = ShockwaveFlash "navButtons" of self l_navButtonMoviePath = s_bookPath & "flash\nav" & \ (name of backdrop of parent of self) & ".swf" extMovie of l_FlashNavButtonsID = l_navButtonMoviePath get extSetVariable("tbButtonState", \ s_FlashButtonSettings) of l_FlashNavButtonsID -- determines enabled, animation level, etc. get extTCallLabel("/", "setButtonState") of \ l_FlashNavButtonsID -- the above sets up the player if checked of button "nextPageButtonAnimating" of self \ = TRUE get extTCallLabel("/", "nextAnimated") of \ l_FlashNavButtonsID end if l_FlashUIButtonsID = ShockwaveFlash "uiButtons" of self if visible of group "uiButtons" of self = TRUE show l_FlashUIButtonsID bounds of l_FlashUIButtonsID = \ resetShockwaveUIBounds of self l_uiButtonMoviePath = s_bookPath & \ "Flash\uibuttons.swf" extMovie of l_FlashUIButtonsID = l_uiButtonMoviePath get extSetVariable("tbButtonState", \ s_FlashButtonSettings) of l_FlashUIButtonsID -- determines enabled, animation level, etc. get extTCallLabel("/", "setButtonState") of \ l_FlashUIButtonsID else hide l_FlashUIButtonsID bounds of l_FlashUIButtonsID = \ hideShockwaveUIBounds of self end if end updateInterface
by Jeff Rhodes
Automatically Setting the Properties of a Web Graphic Placeholder
I've recently been enhancing a "storyboarding" application as part of a contract with the U.S. Army. I showed the initial version last year at TBCON and will show the "latest and greatest" this year. As part of that task, we store the name of the image in a database (entered by the subject matter expert via a .NET front end application). When we read the database on the ToolBook side, we want to get our hands on the graphic, set the associated properties of the Web Graphic placeholder, import or replace the resource, and then show that graphic as the normal graphic of the placeholder. Here's the system book script.
to handle story_updateImage string columnName, string columnValue, object pageId -- look for button of the correct name -- set its ASYMI_ImageRef property, -- import or replace graphic system book storyBookId local string mediaDir local object buttonId local string graphicPath local string relativePath local object resID local string bs, errorString, objString, comString if isObject(button columnName of pageId) = TRUE buttonId = button columnName of pageId if columnValue <> null show buttonId mediaDir = "media" relativePath = mediaDir & "\" & columnValue ASYMI_ImageRef of buttonId = relativePath graphicPath = ASYM_ParsePath(name of \ storyBookId, \"Path") & relativePath if fileExists32(graphicPath) = 1 -- see if resource exists objString = "bitmap" && QUOTE & \ relativePath & QUOTE -- e.g., bitmap "media/test.gif" bs = ASYM_BlockSuspend() resID = objString -- Will generate an error if invalid -- resource since resID is typed as object errorString = ASYM_RestoreSuspend(bs) if errorString <> null -- doesn't already exist comString = "import bitmap resource" \ && QUOTE & graphicPath & QUOTE \ && "as" && QUOTE & relativePath \ & QUOTE -- e.g., import bitmap resource -- graphicPath as relativePath execute comString resId = objString else -- replace resource replace resource resID with graphicPath end if normalGraphic of buttonId = resId send ASYM_Reset to buttonId end if else ASYMI_ImageRef of buttonId = null hide buttonId end if end if end story_updateImage
Those of you who are really observant will see that the script above is a more advanced version of the one that I covered in the last EnterPage issue. That one set the ASYM_ImageRef property but did not import/replace the resource or set the normalGraphic.
Look for this capability to be added to the Plug-In Pro 7.
by Cindy Kessler
Creating Actions with OpenScript
Editor's note: this is an actual email from Cindy to Jeff and Chris on Saturday, February 21, 2004 as she was working on a new section in the soon-to-be-released Learning & Mastering ToolBook Instuctor 2004 CD.
Ok guys, I must confess (but don't tell anyone)...I'm having fun with "Creating Actions with OpenScript." Tim's document is SO clean and well-organized it's a pleasure to work from.
Anyway, had to share...
With the script below, the user just has to create a comboBox, name it "topics," and create dropdown items for it. Then run the script.
The script creates a field for each topic, creates a display field, and sets up an action sequence on the comboBox to essentially "showTextInDisplayField" [Editor's note: this is a system book function we use in the Learning & Masting series] based on the topic selected from the comboBox. So all the user has to do is type topic information in each field.
Oh my, isn't THAT cool!
local actionArray comboId = comboBox "topics" topicList = dropDownItems of comboBox "topics" numTopics = textlineCount(topicList) -- Create displayField draw field from 2400,600 to 5000,1000 name of selection = "displayField" -- Create the variable and set property var1 = ASYM_NewDataStructure("") var1 = ASYM_SetDataElement(var1, "name", "displayText") varList = ASYM_NewDataStructure("") varList = ASYM_SetDataElement(varList, "0", var1) ASYM_EA_Variables(ASYM_Select) of comboId = varList step num from 1 to numTopics topicTitle = textline num of topicList fieldName = chars 1 to 32 of topicTitle -- create a field for the topic draw field from 0,0 to 1320, 240 fieldId = selection name of fieldId = fieldName text of fieldId = topicTitle -- make the if or elseIf condition litRef = ASYM_EA_SDK_MakeLiteralRef(topicTitle) paramRef = ASYM_EA_SDK_MakeParameterRef(1) opRef = ASYM_EA_SDK_MakeOperatorRef("=", paramRef, \ litRef) if num = 1 act = ASYM_EA_SDK_MakeIfAction(opRef) else act = ASYM_EA_SDK_MakeElseIfAction(opRef) end if actionArray[num * 2 - 1] = act -- make set variable action propRef = ASYM_EA_SDK_MakePropertyRef(comboId, fieldId, \ "text") var = ASYM_EA_SDK_MakeVariableRef(varList, "displayText") act = ASYM_EA_SDK_MakeSetVariableAction(var, propRef) actionArray[num * 2] = act end step -- Make End If act = ASYM_EA_SDK_MakeEndAction("if") actionArray[numTopics * 2 + 1] = act -- set text of displayField to variable value act = ASYM_EA_SDK_MakeSetPropertyAction(comboId, field \ "displayField", "text", var) actionArray[numTopics * 2 + 2] = act -- apply array send ASYM_EA_ApplyActionArray comboId, "ASYM_Select", \ actionArray, "true"
We won't tell anyone Cindy. ;-)
VBTrain.Net Tips and News
by Jeff Rhodes
He's off to the Colorado Science Fair in April.
Putting on the developer hat instead of the proud parent hat, let's talk about dynamically adding event handlers at runtime. For the front end of the storyboarding application mentioned above, we wanted to have "presets" available via a right-click menu. So rather than typing in "Click on a button to see its associated information" a hundred times, the subject matter expert could right-click and choose an "instructions" phrase from a popup menu. These phrases are stored in the database and can be updated at any time. With multiple instruction fields, 11 content fields, etc., I didn't want to write individual code for each control. Instead, I wanted one ContextMenu object per type (one for instructions, another for content, another for media, etc.) and then keep track of which control the user clicked on so as to put the selected text into the right spot.
On the way into the form, I read the database to determine the menu choices and populate the menu (we'll show the Instructions menu in this example):
InstructionsContextMenu.MenuItems.Clear() numItems = instructionsPresetTableViewId.Count For menuCounter = 0 To (numItems - 1) rowId = instructionsPresetTableViewId(menuCounter) menuText = String.Concat(rowId(0), "_", rowId(3)) InstructionsContextMenu.MenuItems.Add(menuText, _ AddressOf PresetSelected) Next
The instructionsPresetTableViewId is a DataView object that contains the sorted list of available presets. The AddressOf keyword says to call the PresetSelected handler whenever the menu item is selected. The rowId(0) is the primary key of the row, which we will use to find the data we need. The rowId(3) is the title of the preset but not necessarily its text (which is in a different column and could be quite long).
Next, we loop through all the TextBoxes on the form and use this code to add the appropriate MouseDown handler based on the name of the control.
ElseIf textBoxName.ToLower.IndexOf("instruction") > -1 _ Then AddHandler currentField.MouseDown, \ AddressOf instructionsTextBoxMouseDown
currentField is the reference to the TextBox. This code says to call the instructionsTextBoxMouseDown handler whenever there the user clicks on the TextBox. Here's that code.
Private Sub instructionsTextBoxMouseDown(ByVal sender As _ Object, ByVal e As System.Windows.Forms.MouseEventArgs) If e.Button = MouseButtons.Right Then Dim textBoxId As TextBox = CType(sender, TextBox) If HasTypingError = False OrElse Not _ CurrentTextBox Is textBoxId) Then CurrentTextBox = textBoxId CurrentTable = instructionsPresetTableId InstructionsContextMenu.Show(Me, _ Me.PointToClient(Me.MousePosition)) End If End If End Sub
This code checks to see if it is a right-click and then checks a property to see if there is a typing error. This is needed because there is also a right-click menu with a list of spelling suggestions that needs to take priority over this preset menu. If there is no error, then we store the reference to WHICH TextBox this is in the CurrentTextBox property (since there are lots using the same menu), keep track of which table of data has the presets, and then show the popup menu in the right spot.If the user selects a menu item, we go to the PresetSelected handler as discussed above.
Private Sub PresetSelected(ByVal sender As Object, _ ByVal e As System.EventArgs) Dim menuId As MenuItem = CType(sender, MenuItem) Dim menuText As String = menuId.Text Dim menuArray As String() = menuText.Split(CChar("_")) Dim keyId As Integer = CInt(menuArray(0)) Dim rowId As DataRow = CurrentTable.Rows.Find(keyId) Dim textToLoad As String = rowId(2).ToString LoadPresentContent(textToLoad) End Sub Private Sub LoadPresentContent(ByVal textToLoad As String) If IsNothing(CurrentTextBox) = False Then With CurrentTextBox If .SelectedText <> "" Then .SelectedText = textToLoad Else If .SelectionStart > 0 Then Dim selNum As Integer = .SelectionStart Dim newText As String = .Text newText = String.Concat _ (newText.Substring(0, selNum), _ textToLoad, _ newText.Substring(selNum)) .Text = newText Else .AppendText(textToLoad) End If End If End With End If End Sub
The PresetSelected handler figures out the preset text that we need (notice how it finds the proper row of data using the primary key and the Rows.Find() method of the DataTable object). It then calls LoadPresentContent. It does some gyrations to figure out whether to replace selected text with the preset, insert it into a specific spot, or append it to the end. Notice that these handlers are used by all of the dozens of preset menus in the application.
MORE NEWS AND INFORMATION
Here are the upcoming conferences and events that we have firmed up at this time:
ASTD International Conference and Expo
ToolBook & VBTrain.Net User's Conference
TBCON One-Day Event
Training Fall, incorporating Online Learning
TBCON One-Day Event
We've been doing quite a bit of consulting as well as concentrating on the Learning & Mastering ToolBook Instructor 2004. After that, look for Plug-In Pro 7 and Tracker.Net 3. On the longer-term is an updated Question object and Exam Engine.
The EnterPage is distributed four times a year, with occasional special issues. Individuals who have expressed interest in Platte Canyon Multimedia Software Corporation or its products receive The EnterPage. Suggestions for articles or proposals for article submissions are welcome. Send information to EP@plattecanyon.com. Back issues of the EnterPage are available at http://www.plattecanyon.com/enterpage.aspx.
To subscribe or unsubscribe, please send a message to EP@plattecanyon.com. Please include your name and company with new subscriptions.
All content copyright Platte Canyon Multimedia Software Corporation, 2004.