Our programs are really good at collecting data, but
making sense of all that data and turning it into useful information can
be a challenge. Reports are good and graphs are great but real-time
information collected into one place is better.
iDash allows you to add a dashboard to your program.
The goal of a dashboard is to display all the real-time information to
your user that they need to make decisions in a single window. They need
to be able to organize this data, and view it in a way that makes sense to
them.
Because a dashboard is highly customizable it's no good just creating a
window, putting some graphs on it, and calling it done. Rather the
dashboard becomes a container, containing many individual Widgets,
and the user has complete control over which widgets are displayed, their
size and their order.
iDash is designed to be used in Clarion 8 or later and supports both
Legacy and ABC template sets.
iDash contains iWidget
A widget is simply a way of displaying data, which can be included on a
dashboard. There are many kinds of widgets including your own custom
widgets, a Simple Text Widget (included with iWidget) and widget support
built into other tools.
iWidget provides the framework for creating your own widgets, or for using
widgets provided by other tools. It is an extensible framework which
allows other 3rd party developers to add widget support to their products.
The Dashboard control displays widgets. In order to
have widgets to display you need to create them in your app. The purpose
of this section is to explain the concepts behind a widget, and how a
widget is constructed.
Widget Procedure Template
Widgets are created using the
Widget
Procedure Template type. For best results click the
New
Procedure button, enter a procedure name, then go to the
Defaults tab and select
Widget
Procedure. If you add a widget procedure from the Templates tab
then you will need to set the prototype manually as well.
The widget procedure can take any number of parameters. It returns a
*iWidget1 and hence the default prototype is
(),*iWidget1
If you are making use of a widget supplied as a template, then you can
now add that widget to the procedure as an Extension template. For
example a
Simple Text Widget is included as
part of the iWidgets template. Other templates exist which add the
widget either as an Extension (like
Draw Gauges) or as a Control template (like
Insight
Graphing). Control templates can be added to the Window Designer
in the usual way.
[1]
The requirements of a widget procedure can be fulfilled by an extension
template, or it can be coded directly into the widget procedure. Since
templates just do what you can do by hand the rest of this section will
assume you are not using a template. For usage of a specific template
see the documentation on that template.
The procedure itself has some options for generating some of the code
for you. It can help you create a VIEW structure (if you are reading
data out of files), as well as create methods in the class for opening
tables, closing tables and so on.
One possible point of confusion here is worth mentioning. Widgets are
represented in the application tree as "procedures". While there is a
tiny bit of procedure code in a widget procedure, the bulk of the code
is actually a new class type. The class usually has the same name as the
procedure, but the two are fundamentally separate.
[1]
The window is not generated into the Widget itself. The designer is
provided simply as a convenient way to add control templates.
Creating a Widget Procedure
- Click in the New Procedure button to add a procedure to the
application. Give the procedure a name.
- On the Defaults tab select "Widget Procedure"
Simple Text Widget
Although you can code your own widgets (
described
below) it is likely that at least at first you will make use of
widgets which are template based. The Simple Text Widget extension
template is included with iWidget.
The simple text widget, as the name implies, allows you to display a
title and value in the widget space. The value might be a global
variable or some calculated value. The widget calculates the font size
to use based on the text being displayed and the space available to
display it.
Displaying a Global Variable
To create a widget using the Simple Text Widget
extension which can display the contents of a global variable follow
these steps;
- Create a new Widget procedure in your application as described
above.
- Set the prototype of the procedure to
(String pText, *? pVariable),*iWidget1
- Go to the Extensions tab and add the Simple Text Widget
extension to the procedure.
- On the Text tab set the Text to
pText
- On the Variable tab set the Variable to
pVariable
- Set the rest of the settings on the Box, Text and Value tab to
your preferred settings.
You can now add this widget to your Dashboard control as many times as
you like using as many different variables.
Bear in mind that this approach works particularly well when the value
you are wanting to display might best be calculated on a background
thread. For example you might have a background thread fetching an
exchange rate from a web service, putting the result in a global
variable. It can also be used for calculations which are "expensive"
(time-wise) but which can run on a background thread from time to
time.
In other words the widget is able to separate the calculation of the
data from the display of the data.
Displaying a Value
calculated from the database
Assuming you are not calculating on a background
thread it's also possible to calculate values directly from the
database and use these in the widget. Here are the steps for doing
that;
- Create a new Widget procedure in your application as described
above.
- Set the prototype of the procedure to
(),*iWidget1
- Go to the Data Pad and add the tables (including any sub tables
required) to the View Table section.
- Go to the procedure Actions. On the options tab tick on the
options;
Generate VIEW
Generate Open/Close Files Methods
Generate Save/Restore Files Methods
- Still in the procedure actions, go to the View tab, and enter
the filter for the view there.
- Still in the procedure Actions, go to the View Fields tab and
add in all the fields you will need to use in your calculations.
- Go to the Extensions tab and add the Simple Text Widget
extension to the procedure.
- Set the settings on the Box, Text and Value tab to your
preferred settings. Leave the Variable setting blank.
- In the Widget Class Properties
embed point add a field
Total Long
- In the LoopThroughView Method, Before
Loop embed point clear the total
Self.Total = 0
- In the Inside VIEW Loop embed point add the calculation. For
example;
self.total += (LIN:Price * LIN:Quantity)
Note that in this case Lin:Price
and Lin:Quantity should be added to
the View Fields as per step 6 above.
- In the Local Objects / CapeSoft Objects
/ ThisWidget / Reset embed point add code to trigger the
view, and to place the result in the ValueControl
Self.LoopThroughView()
Self.Value = self.Total
Tip: You could also change the self.Text
if you wanted to at the same time.
Bear in mind that normal Clarion database access is possible in the
widget as well. So you could, for example, use a
PROP:SQL
statement to execute a SQL Stored Procedure, fetching the result and
displaying it in the widget.
Graph Widget (requires Insight Graphing 2)
Version 2.19 (and later) of
Insight Graphing contains support for iDash. If you wish to create
a graph widget, which used Insight, the follow these steps;
- Create a new Widget procedure in your application as described
above.
- Go to the Window for the procedure. Choose "Simple Window" as the
window type. [1]
- Add an Insight Graph control to the window. Don't worry about the
size of the control - it's not used.
- You can now edit the settings for the graph via Right-click /
Actions on the control on the window, or via the procedure's
Extensions tab. [2]
- It's a good idea to set the graph object name to something unique
on the Advanced tab.
- Remember you can pass parameters into the procedure, but you can't
have any local variables. So if you want the graph to use parameters
then add new properties to the graph by going to the Source of the
procedure, or add them to the local data pad.
[1] The
window itself is never actually generated or used. It's simply a
place-holder for the graph control.
[2]
There is one point of possible confusion. The widget procedure has
support for creating a view for you, and so in the Data Pad you will see
the
View Table set as
<ToDo>. You can ignore this completely - it is not used
by the Insight control (which creates it's own view.) So leave the
View Table as
<ToDo>
and add any tables the Insight Graph uses to the
Other
Files section.
Graphing From a Queue
It's fairly common to create Insight Graphs that
graph their data from a Local Queue. Since this is a Widget, not a
procedure you can't directly create a queue in the widget. However it
is still possible to graph from a queue by making the Queue a property
of the widget.
The
\examples\iDash\Insight\demo.app
contains a procedure as an example of this technique. The process is
as follows;
- Declare a widget property in the Local Data Pad (or declare it
in embed code.)
Column Name (anything you like, the example uses GraphQueue)
Data Type: Type
Base Type: the Type of your Queue. The example uses WidgetQType
which is available for your use if you like.
- On the app tree, right-click on the widget procedure and choose
source. Go to the .Init method (ThisGraph1.Init) and add a line
there;
self.GraphQueue &= new WidgetQType
The name and Type match the names selected above.
- Typically the Queue needs to be loaded at some point. If the
data is dependent on other widget properties (date ranges and so
on) then add your queue code to the Graph.iWidget1.Reset
method.
- Now you can set the graph template parameters as you would
usually do. Common settings are;
a) the Point Name and Point Number on the X-Axis tab
b) adding the Queue to the Data Tab.
c) For the set setting the Setting the Description (Set tab),
Values (Y-Axis tab) and Override Set number (Advanced Tab)
Gauge Widget (requires Draw 4)
Draw Version 4 and later supports created Gauges,
and includes support for creating iDash widgets.
- Make sure the Draw Global Extension is added to the application.
- Create a new Widget procedure in your application as described
above.
- Go to the Extension tab, and add the DrawGaugeWidget extension to
the widget.
- Complete the gauge template settings as desired.
For some ideas on how to set up the widget see the example
\examples\idash\gauges
Widget Interface
In programming in general it is often useful to
separate one thing from another. In the case of iDash the Dashboard
control, and the Widgets (which can go onto the dashboard control) are
separate "things". By keeping these two things separate it's possible
for the whole system to be more flexible, and it allows for the
Dashboard and Widgets to be developed separately.
Although these two parts are separate they have a common understanding
of their roles. In Clarion this understanding is known as a INTERFACE.
In practice this just means that you can create any widget class you
like and as long as it implements the sub-set of methods defined by the
interface, it will work fine in the dashboard.
If you are not a class programmer then don't worry - you don't really
need to understand any of this. The appropriate embed points are
provided to you, and as long as you put your code in the correct place,
you won't need to worry about the terminology or the underlying
technology.
The interface is declared in iWidget.Inc
.The interface is numbered so that if the interface is ever extended a
new interface will be created, and thus backward compatibility will be
preserved.
iWidget1 INTERFACE
ApplyOptions PROCEDURE ()
Display PROCEDURE ()
GetOption PROCEDURE (String pName), ?
Init PROCEDURE (Long pParentRegionControl)
Kill PROCEDURE ()
Hide PROCEDURE ()
Move PROCEDURE (Long pX, Long py, Long pWidth, Long
pHeight)
Reset PROCEDURE (byte pForce=0)
Resize PROCEDURE (Long pX, Long py, Long pWidth, Long
pHeight)
SetOption PROCEDURE (String pName, ? pValue)
TakeEvent PROCEDURE (),Long
Unhide PROCEDURE ()
END
A widget class can declare more than these methods (and likely will) and
it can add it's own properties and so on. But as long as it Implements
this Interface above it can be used on the dashboard. The dashboard
control will communicate with it's widgets by calling these methods at
appropriate times.
Embedding Inside the Widget (Creating
your own Widget)
Inside the procedure a Class is declared. This class
either Implements iWidget1, or is based on a class that implements
iWidget1.
[1]
For the purposes of this documentation a trivial widget with a single
Image control will be created. This image will take a name, which can be
passed in when the widget is first created.
As the widget will be taking in a String parameter set the prototype to
something like
(String pImageName),*iWidget1
Note that widgets do not have local data, and you should not declare or
use any local data. A single dashboard may contain many of the same
widget (called with different parameters) so it has to be completely
self-contained. Since we don't have any local data, all the data we want
to declare becomes a property of the class.
To see the generated code, and to add the code you want to add,
right-click on the procedure in the application tree, and choose
"Source". This will allow you to see the generated code and also to
enter your own code in the correct places.
Add two properties to the class, something that will hold the Field
Equate to the image control and one to hold the passed-in name.
ThisWidget
Class(),TYPE,Implements(iWidget1)
ImageControl Long
ImageName String(255)
End
You will notice that the generated code at the top of the procedure
looks like this;
aWidget &= NEW ThisWidget
RETURN aWidget.iWidget1
The only place you should embed code here is just before the RETURN
statement. And the only thing you should do in this embed point is
assign parameters into properties. The name of the object at this point
(and only this point) is
aWidget. This is
also the ONLY point at which you can reference the parameters. So pretty
much the only code you need here is moving parameters into properties of
the class. For example;
aWidget.ImageName = pImageName
After this opening part of the code you will see each of the interface
methods declared (in alphabetical order).
Not all of the methods require code - some of the methods can be left
empty.
Rather than go through them in alphabetical order though I'm going to
describe them in their "natural" order, starting with INIT.
INIT
The INIT method is called when the widget is first
created. And by contrast the KILL method is called when the widget is
killed.
In our example we will use the INIT method to create the Image control
[2].
ThisWidget.iWidget1.Init PROCEDURE (Long
pParentRegionControl) ! Probably
REQUIRED
CODE
self.ImageControl =
CREATE(0,Create:Image,pParentRegionControl{prop:parent})
You will notice that the Dashboard control passes you the equate of a
region control which form the boundary of your widget. If you want to
store this for later use (into a property) you can, however that is
not required.
It is however required that the controls you create have the same
parent as the
pParentRegionControl
KILL
The balancing code to the Init method goes into
the .Kill method;
ThisWidget.iWidget1.Kill PROCEDURE () ! Probably
REQUIRED
CODE
DESTROY(self.ImageControl)
RESET
The Reset method is called when the dashboard
feels the widget needs updating. This includes a call as the widget is
first displayed. This is usually the place where you adjust the output
of the widget based on the current values. For example;
ThisWidget.iWidget1.Reset PROCEDURE (byte
Force=0) ! Probably REQUIRED
CODE
self.ImageControl{prop:text} =
self.ImageName
end
One interesting thing to note here is that you should avoid changing
control properties if they don't need to be changed, and if the
control is not visible then it almost certainly does not need to be
changed. Reset will be called when the user changes Tab controls, so
you only need to update widgets that are visible.
RESIZE
The size of the widget is determined by the
dashboard control. It contains a default size, and also allows the end
user to resize specific widgets so that it best fits what they are
trying to see. When a widget is resized then the .Resize method is
called.
ThisWidget.iWidget1.Resize PROCEDURE (Long pX,
Long py, Long pWidth, Long pHeight) ! REQUIRED
CODE
SetPosition(self.ImageControl,px,py,pWidth,pHeight)
MOVE
Widgets can also be moved around on the dashboard,
and when a control moves the .Move method is called. A move is
different to a resize because the control is being moved, but the size
is remaining the same, and for some widgets this may be quite
different code. In many cases though (including this example) the
actual code in move ends up being the same as in resize. In that case
a simple call to resize will suffice;
ThisWidget.iWidget1.Move PROCEDURE (Long pX, Long
pY, Long pWidth, Long pHeight) ! REQUIRED
CODE
self.iWidget1.resize(pX,pY,pWidth,pHeight)
DISPLAY
The Display method is called when the widget needs
to redraw itself.
ThisWidget.iWidget1.Display PROCEDURE () ! REQUIRED
CODE
display(self.ImageControl)
HIDE & UNHIDE
The Hide and Unhide methods are called when the
widget is being hidden, or unhidden.
ThisWidget.iWidget1.Hide PROCEDURE () ! REQUIRED
CODE
If self.ImageControl{prop:hide} = false
Hide(self.ImageControl)
End
ThisWidget.iWidget1.Unhide PROCEDURE () !
REQUIRED
CODE
If self.ImageControl{prop:hide} = true
Unhide(self.ImageControl)
End
SETOPTION
The SetOption method allows the Dashboard to
change values in the widget. The option and value are passed in as a
pair and typically the class will use the name to identify the
property being changed.
ThisWidget.iWidget1.SetOption PROCEDURE (String
pName, ? pValue) ! Optional
CODE
case lower(pName)
of 'imagename'
self.ImageName = pValue
end
Exactly what you do with the options is up to you - there is no
prescribed behavior for this method, it's simply used as a generic way
to pass the widget instructions.
GETOPTION
The opposite to SetOption is GetOption and again
there is no proscribed behavior for the method.
ThisWidget.iWidget1.GetOption PROCEDURE (String
pName) ! Optional
ReturnValue Long
CODE
case lower(pName)
of 'imagename'
ReturnValue = self.ImageName
end
RETURN ReturnValue
The point of the SetOption and GetOption methods is to allow the
Dashboard control to communicate with a widget, even if the exact
properties of the widget are unknown. These methods thus ensure future
compatibility with widgets as yet unwritten.
APPLYOPTIONS
When the dashboard is setting multiple options all
together it will complete the set of calls with a call to
ApplyOptions. This can be advantageous when a reset (after each
option) would be expensive. The most likely code you would put into
ApplyOptions is a simple call to reset.
ThisWidget.iWidget1.ApplyOptions PROCEDURE () !
Optional
CODE
self.iWidget1.Reset(true)
TAKEEVENT
If your object needs to respond to events, then
you can add code to the TakeEvent method.
ThisWidget.iWidget1.TakeEvent PROCEDURE () ! Optional
ReturnValue Long
CODE
case event()
End
RETURN ReturnValue
In this simple example no events matter so no code needs to be added.
Notes:
[1]
Unfortunately it cannot both be
derived from
a class that implements iWidget1 AND implements iWidget1 itself. Equally
it cannot override interface methods defined by the parent class. For
this reason, if you are making a class outside of the Widget Procedure
Template, it is a good idea that you restrict the code in the interface
methods to just calling a same-named method in the class itself. Then
the code in the class can be overridden by derived classes. An example
of this is the
WidgetBaseClass which is
included in
iWidget.Inc and
iWidget.Clw.
If you are making a widget class from scratch then deriving from
WidgetBaseClass is recommended.
[2] A
single widget can consist of many controls - as many as you want or
need. This example contains just 1 but see the source of the
TextWidgetClass
in
iWidget.Clw for an example of a
widget that uses many controls.
Events and Windows
As mentioned earlier the Widget itself has no window
of its own, and hence no ACCEPT loop of its own. At first glance this
means that widgets themselves may be limited, however this is not the
case.
It's important to remember that the widget is just an object, and even
though the code for the object is in the Widget "procedure type", the
object itself is being hosted by the Dashboard control (which is itself
on a window.) So the object is always running inside an ACCEPT loop, and
events are indeed flowing.
The Dashboard control will pass all window events, and specific field
events, though to all the active widgets on the dashboard. So you can
think of your widget as "running inside the Dashboard window" and
conceptually you'll be on the right track.
Calling a Widget, not
from the Dashboard
Widgets can sometimes include calculations which can
be useful outside of the dashboard procedure. This can lead to the
concept of calling widgets, almost like Source procedures, to calculate
values. While the basic concept is simple, the actual usefulness of this
depends a lot on the widget itself.
To call a widget from source code is relatively
straight-forward. The widget procedure itself returns an iWidget1
interface. So, for example;
widget &iWidget1
code
widget &= AverageShipTime()
dispose(widget)
Of course the AverageShipTime widget may or may not
take parameters, so use those as necessary in the call above. The
dispose call is necessary or the program will leak memory.
The actual code which goes between the initial call
and the dispose depends a lot on the actual widget.
widget.reset(true)
This line typically resets all the values for the
widget. In other words it usually "does the calculation". Then something
like
val = widget.GetOption('result')
would return the contents of the result property.
Of course if the widget is mostly visual (like a
gauge or graph) then this approach is more complex - requiring a region
control on the window on which to place the visual aspects of the
widget.
If Widgets are one half of the product, then the iDash
control is the other. The iDash control can be placed on any window and it
in turn acts as a host to any number of widgets.
Creating a Dashboard Window
You can create a new dashboard window by
- Click in the New Procedure button to add a procedure to the
application. Give the procedure a name.
- On the Defaults tab select "Dashboard control on a window"
- Add the iDashboard Table to the Other Files section of the
procedure data pad.
Alternatively you can take an existing window and place the iDash
Control Template on the window. Press "Cancel" when offered the List Box
Formatter, and you may need to click on the window 3 times after that to
get the Sheet control to appear.
The window consists of two controls - the Widget List control on the
left, and the Sheet control on the right. You can add as many Tabs to
the Sheet as you like, and you can remove any excess tabs that you don't
need.
Add the Dashboard procedure to your Main Menu and/or Toolbar so that it
can be opened when the program runs.
Adding a Widget to the Dashboard
Once the dashboard control has been added, the next
step is to add one or more widgets to the dashboard. This is done via
the Extensions tab, on the iDash Control properties.
Go to the Widgets tab and click on Insert to add a Widget. Note that to
do this your application must already have one or more Widgets defined.
If you haven't created any widgets yet then review the
Widgets
section in the documentation first.
Set the following (required) settings for the Widget;
- Widget Procedure
Select from the list of Widget Procedures. remember that the same
widget procedure can be used multiple times on the same dashboard
(presumably with different parameters) if you wish.
- Parameters
Add in any parameters which the widget procedure needs here.
- Equate
Although widget procedures can be used many times on the same
dashboard, each widget needs a unique Equate.
- List Text
This is the text that will appear in the widget list on the window.
This field is an expression, so if you are entering a fixed text
string then use quotes.
There are other template settings you can set for the widget, for a full
list of template settings set the
Template
Documentation.
Runtime Behavior
When the program is run, and the user opens the
Dashboard procedure they will naturally see the dashboard. There are a
number of behaviors built in to the dashboard control that allows them
to customize the way the dashboard looks.
Widget Flow
When the widget layout changes (widgets turned on
or off, widgets resized, or the order of widgets changed) or the sheet
control size changes, then the widgets on the sheet control will
automatically reflow.
Widgets are drawn left to right, top to bottom, in the order in which
they are set (or the order the user has chosen.) Since the widgets may
be of different sizes the widget will be drawn in the first available
space which is large enough to accommodate the widget. If there is no
space available to accommodate the widget (for example if the widget
is big, and the dashboard is small) then the widget will not be drawn.
Turning Widgets On and Off
The widget list on the left of the dashboard
window contains the list of all the widgets you have added to the
Widgets tab in the template settings. A user can turn a widget on or
off by double-clicking on the widget in the list.
They can also right-click on a list item and choose Hide
or Show (depending on the current state of
the widget.)
Some widgets may also support right-clicking on the widget itself and
choosing Hide.
Adding Widgets to the Summary
If the Dashboard control has a
Summary
tab set then the user can right-click on a widget, or on the
widget list, and choose
Add to Summary.
when they do this a copy of the widget will appear on the summary tab,
and will appear in the list under the Summary heading.
Note that the widget on the summary is a copy of the widget, the
original widget remains on the tab as before.
Changing Widget Order
Widgets can be re-ordered simply by dragging on a
widget and moving it to after another control on the tab. The reorder
of the controls will be reflected in the list on the left, and the
dashboard will then reflow. Note that when the widgets are different
sizes the flow may not be what the user was expecting. See the flow
rules above for how the flow works.
Changing Widget Size
If you mouse-over the bottom-right corner of a
widget then the cursor will change to a resizing cursor. You can then
resize the widget to one of the available alternate sizes. The current
sizes available are;
- Normal (This size is set by the values entered on the template Grid tab)
- Double Top - The widget is twice as wide as normal
- Double Left - The widget is twice as high as normal
- Double - The widget is twice normal size
- Quad - The widget is four times normal size
Reset Fields
Displaying the widgets is great but it is desirable
that the widgets reset themselves when things occur. For example if you
have a text widget, showing the value in a global variable, then you
want the widget to refresh automatically when the value changes. Or
perhaps you allow your user to enter a date, or date range, on the
dashboard window (using regular ENTRY controls) and you want the widgets
dependent on those dates to update automatically when a date changes. To
allow for this to happen the template supports Reset Fields. If the
value in a Reset field changes then widgets dependent on that field will
update.
The check of the resets is done on every event in the window. So if you
change a value somewhere else in the program, then it's a good idea to
POST an event to the Dashboard. (See
note
below)
Reset fields can be added at the widget level. If you find that a single
variable will reset all the widgets then this can be set on the Resets
tab (outside of the Widgets tab.)
When a field is reset you have the option of calling SetOption (one or
more times) so that the widget can be made aware of the new setting. For
example if a local date changed, then a widget Fromdate and ToDate
Options may need changing. Setting Options is entirely dependant on the
widget itself, and what it needs from the dashboard.
Dashboard Control Template
Settings
Options Tab -
Thread Global Variable
For various reasons
[1]
[2] it's useful for the thread
number of the Dashboard control to be known. It is recommended that
you create a global variable (NOT Threaded, type LONG) and set it
here. If you are in a Multi-DLL system then add the variable to the
Data DLL and in other apps declare it as EXTERNAL. In this
documentation this variable is referred to as
DashboardThread.
[1]
When data changes in the application you can send an
Event:Reset
to the dashboard window. For example;
Post (Event:Reset , , DashboardThread)
This will cause the dashboard window to examine the Reset
fields for each widget and (if necessary) refresh the affected
widgets.
[2]
If the Dashboard is on a non-MDI window, and thus floating outside
your Frame, it will need to be directed to close when the Frame
closes. this is done by sending it an Event:CloseWindow when an
Event:CloseWindow is handled in the Frame. For example
Post(Event:CloseWindow , , DashboardThread)
Grid Tab
You can adjust the "Normal Size" of the widgets,
and the gap between widgets, on the Grid tab.
Variations
You have a fair bit of control over the "look" of
the dashboard. Here are some suggestions for alternate looks;
- Adjust the size of the List and sheet controls as desired
- Remove the Summary tab from the sheet control (and set the Summary
Tab template setting to blank).
- Only use one tab on the sheet, and set the sheet to be a WIZARD
control.
- Turn off the MDI child attribute to allow the window to float
"outside" your application. [1]
- Change the size, or completely hide the Widget List control. [2]
[1] If
you do this then you will need to post an Event:CloseWindow to the
Dashboard window when your program closes. If you have set the Thread
Global Variable then this is very simple to do from the frame.
[2]
Placing a Splitter control between the list and the sheet is also a
useful addition to the window. Splitter controls are available in
ResizeAndSplit.
This section is for writes of Clarion templates that
wish to take existing templates and add support to them so that the
template can be used as a widget. If you are not a template writer then
feel free to skip over this section.
Run the supplied installation file. All the necessary
files will be installed, and the templates will be registered (assuming
that option was on.)
If you need to register the templates manually be aware that two TPL files
need to be registered. They are iDash.TPL
and iWidget.TPL.
This product is supplied as source files that are
included in your application. There are no additional files for you to add
to your distribution.