document contains answers to FAQ's regarding our Windows
programming tools products: The Charting Tools, Real-Time
Tools, and Graphics Class Libraries for MFC. Additional
technical queries should be sent to: firstname.lastname@example.org,or directed to the support
staff at telephone #(508) 359-6639 or FAX #(508)
960-2729. Please be prepared with the your name, product
name, and product registration number when you call, as
these items are required to obtain technical support.
The top 10 most
common questions we get are answered in new demos that we
have made available on this web site. Click here to go to that page.
Many of the following technical questions pertain to the
Charting Tools, Real-Time Graphics Tools, or both. Those
specific to the RT Tools are listed under the RT section
Currently our technical FAQs are organized into the
|I have X & Y
axes in my graph. If I change the scale
of either of them through the pop-up
editing dialog, or through code
(WGChangeAxisRange), I "lose"
the other axis and its labels (it
disappears). Why? |
|How can I create multiple axes
where the y-axes are stacked vertically on top of one another,
where each y-axis has a different scale and displays a different
|How do I create
multiple Y axes in my graph window? I
want both Y axes to beon the left hand
side of the graph, beyond the origin of
the X axis.|
I want on Y axis to be on the left edge
of the plotting area, and the other on
|How can I get my
second Y-axis to "track"
appropriately or "cleanly" when
I change the range of my first Y axis,
and/or my X-axis intercept with the
second Y axis?|
|When an axis range
is changed with WGChangeAxisRange
function, the axis labels are not updated
|If the range of one
axis is changed, other axis change
I change axis range, intercept, and
distance between tick marks, the graph
looks bad, with incorrect number of tick
The axis intercept
is not automatically recalculated or changed when
you change any axis range, so in some cases
changing the axis range may make the current
intercept settings be out of the displayed range.
Therefore, you also need to change the axis
intercept at the time that the axis range is
changed, either through the axis editing dialog
or through code (WGChangeAxisIntercept).
|How can I create multiple
axes where the y-axes are stacked vertically on
top of one another, where each y-axis has a
different scale and displays a different plot?|
DEMO PROGRAM: SuprZoom
How do I create multiple
Y axes in my graph window? I want both Y axes to
be on the left hand side of the graph, beyond the
origin of the X axis. |
I want on
Y axis to be on the left edge of the plotting
area, and the other on the right.
call WGSetXYIntercept and WGDrawYAxis for
each axis. The intercept can be beyond the
extents of the axes. For example, if the X axis
is scaled from 0.0 to 10.0. the Y axis can
intercept the X axis at -1.0 and be drawn there
without a problem.
Note that plots and axes are order dependent,
meaning that a plot will be drawn with respect to
the last (x,y) pair of axes created before the
plot call (i.e. WGLinePlot).
DEMO PROGRAMS: BARDEMO, MULTAXES
You'll need to use
a value for the X intercept that is an even
multiple of the tick spacing.
This only happens
if the labels are not numeric but string - they
cannot be updated automatically. The user has to
change the content of the labels array.
This is normal
behavior for axes created with identical ranges.
If you want a different behavior, create axes
with slightly different initial ranges, for
example, 1 - 10.0 and 1 - 10.0001. The difference
will not be visible to the user, but the axes
will be independent.
|When I change axis range,
intercept, and distance between tick marks, the
graph looks bad, with incorrect number of tick
The order of calls
is wrong. In general, if you change range,
intercept, and tick marks, call WGChangeAxisRange
first, WGChangeAxisTicks second, and WGChangeAxisIntercept
last. If you want the plot to be immediately
updated, set bUpdate to TRUE only for the last
There are two
procedures to consider when updating a graph with
A.) This method
can be used when you want to update the graph
with a data set that contains the same
number of elements as the original data set.
Simply assign new values to the data set pointers
and update the graphical objects associated with
the data set with WGRedrawObject.
B.) To update a
graph with a new data set containing a different
number of elements than the original data set,
use the following sequence:
If the data set is
different, or changes size - use WGReconnectDataSet
(see DYNDEMO). If only the contents of data array
changes, use WGRedrawObject.
You must use huge
pointers for the underlying data arrays
associated with a data set.
Users of the
Charting Tools often try to display thousands and
even millions of points in a single graph. The
result is a graph which takes a long time to plot
and which looks "smeary" on the screen
with extremely thick lines. When large sets of
data are displayed in a graph, the data should be
"compressed" so that it displays well
on an output device like a CRT. This demo program
demonstrates how to use the function WGCompressData
to reduce large sets of data into smaller, more
displayable data sets.
It does not
matter, because locking only worked in real mode
of Windows. Nothing is actually locked or
unlocked in protected mode.
I noticed many of your demo
programs use GlobalAlloc,
followed by GlobalLock
when allocating memory, and only GlobalFree
to free the blocks. Isn't it
important to also unlock the block with GlobalUnlock?|
played a role in real-mode Windows applications
(which no one writes), its usefulness in
protected mode applications is minor. When using
a block that is not discardable, which is usually
the case, GlobalLock merely converts your handle
to a selector:offset. The selector value does not
change; GlobalLock does not fix the memory object
in the physical address space. Conversely,
GlobalUnlock just returns your handle if the
block is not discardable, nothing else!
If your segment is
discardable, then you should call GlobalUnlock as
appropriate. All it does in this case is
decrement the lock count in the blocks arena, as
reported by GlobalFlags.
The global lock
count mechanism for protected mode only affects
the lock count of discardable objects and the
default data segment. It should not be used as an
indicator of the number of times GlobalLock was
internally by our Windows products is allocated
as GHND, which combines the GMEM_MOVEABLE and
GMEM_ZEROINIT flags creating movable memory that
is initialized to zero. These memory blocks are
It is recommended
by Microsoft that in 32-bit applications you
should use other dynamic allocation functions
such as calloc or HeapAlloc instead of
Using the Resource Editor, insert a new dialog
box resource into your application's resource
file. Change the ID of the dialog box from
IDD_DIALOG1 to a string "Dialog1".
Include resource.h in your main program file
(where you initialize your dialog.
In your main program file (where you are creating
the graph) initialize your new dialog by using
the Windows API function DialogBox.
DialogBox((hInst, "Dialog1", hwnd, (DLGPROC)
Define a dialog
box procedure DialogProc and add its prototype to
the top of your program file. The prototype looks
BOOL CALLBACK DialogProc (HWND hDlg, UINT
wParam, LPARAM lParam);
In the DialogProc
callback function definition, create the page
window as a child of the dialog. The graph will
be created on the page window.
BOOL CALLBACK DialogProc (...)
10, 10, 600, 400);
The key is passing
the handle to the dialog box, hDlg, in as
the handle to the parent window and using the
page window style: WS_CHILD | WS_CLIPCHILDREN |
WS_VISIBLE. If you already have a dialog box and
you want to put graph in it then just follow Step
Sample programs are
available for download from our Web site and are
provided for both RT/CT Tools and the GCL, as
well as additional instructions for adding
printing support for the graph.
PROGRAMS: CTDIALOG.ZIP, RTDIALOG.ZIP
Use the member
function WGCreatePage from class
QCPageWnd, and pass in handle to dialog box
window as pParent parameter. The demo program
referenced below contains a .DOC file with
Normally a dialog
for editing an object appears if you double-click
on the object with the mouse. If you have to call
the dialog from your program, without clicking
the mouse, you can do it for any object as in the
// First, select object:
WGSelObject (pGrDesc, // graph descriptor
hScroll); // object handle
// now call the undocumented function that
will bring up the dialog:
// If you are using the Real-Time Tools,
call WREditObject instead.
You can only call WGCleanup
(or WRCleanup) one time during the life of
your program, immediately before program
termination. Do not call WGCleanup at any
other point in your program, as it is incorrect
and will cause GPF's. If you want to perform the
sequence above, call WGClosePage at the
end of the sequence in place of WGCleanup,
before starting again with WGCreatePage.
You may want to call WGFreeDataSet also,
but it is not necessary.
This means that
there is an older version of our DLL in the path.
Delete old DLLs.
files in the MFC demo.
Create page is
called too early, before the view window receives
its WM_SIZE message.
This can happen if
the values of X are not sorted, or the same value
occurs more than once.
It will not change
only if the metafile is imported with the same
aspect ratio as the original page. In general,
the appearance of metafiles can be very different
in different applications.
The page must not
be made a child of the frame window because the
frame window is covered by the view window.
This happens on
some systems connected to a Novell network. Edit
the INSTALL.CFG file on the disk and replace the
directory for upgrade:"
DEFAULTDIR: c:\qcw32, prompt="Enter the
drive and directory
where you wish the Charting Tools to be
DEFAULTDIR: c:\qcw32, prompt="Enter the
drive and directory
where you wish the Charting Tools to be
|Problems with VB Setup
Wizard - I created a program
and attempted to make an executable file out of
the program. In the process I needed a file
"qcbased.lib". I am assuming that this
file is associated to your products. The problem
is that I don't have that file anywhere on my
computer. I have re-installed the software, but I
cannot seem to find the files. I was wondering
what needs to be done to obtain that file. I need
it to make an executable file out of my Visual
The problem here
is that the 16-bit Charting Tools DLL is named
"QCBASED.DLL" but the corresponding
library is named "QCWD.LIB". Yet the
Setup Wizard expects these corresponding files to
have the same name but with different extensions.
Simply make a copy of QCWD.LIB and name it
QCBASED.LIB. I think that will take care of it.
however, that if you are trying to make a setup
for a 32-bit executable, that these files are not
used anywhere and really aren't needed, although
the Setup Wizard expects them b/c of what's in
our .BAS files (16-bit and 32-bit declarations)
Concerning packaging the
.exe file and support files: I use Microsoft VB
5.0 to build the app and then "Application
Setup Wizard" to make a distribution.
Suddenly I get asked for "GDI file" and
"User" and I can't seem to find out
what the Wizard wants me to give here. This
didn't happen when I'd built my application with
"home-made" graphics so I only presume
its something to do with the included .BAS files.
Can you help me?|
These two files
"GDI file" and "User" are not
QC files and refer to the Windows GDI.DLL and
USER.DLL files. Setup Wizard uses dependency
files (.DEP) to determine what DLLs are needed in
an application program, but current versions of
VB cannot generate .DEP files for linked DLLs, so
you need explicitly know that files you need.
These two are found on anyWindows 95 (and NT)
machine (as GDI32 and USER32. GDI and USER,
without the 32 suffix, are found on Windows 3.1
If you look in our
WGGLOBAL.BAS file, you will see references to
GDI32 and USER32 in the 32-bit declaration
section, and references to GDI and USER in the
16-bit declaration section. It is very possible
that the Setup Wizard is picking up on these
16-bit declarations in the file, even though they
are not used for a 32-bit application. So, you
can remove the 16-bit section of declarations
entirely from WGGLOBAL.BAS, since you have a
32-bit application and the DLLs listed in the
16-bit declaration section are never used, or, as
an alternative, you can explicitly tell the Setup
Wizard where these files are located.
Yes and no. We
have two routines to label axes with time/date
formats: WGLabelAxisMonth, WGLabelAxisDayWk.
We do not have a routine to automatically label
axes in the MM/DD/YY format. Use WGLabelAxisStrings
to label axes with any type of labels that can be
represented as strings.
Give the WGChangeFont
routine a try. It has an orient parameter where
you can specify an angle. I believe this function
will work for axes labels, both text and numeric,
even though it is not documented as such.
How do I add or remove items (both symbols and text) from a legend if I hide
or show a particular [line plot, etc.] object
that is included in the legend? Calling WGShowObject with TRUE or FALSE will not affect
the legend display to reflect the visible objects
in the graph.|
True, calling WGShowObject
on a plotting object will not affect the
visibility of specific items in a legend window.
There are 2 alternative methods for handling the
display of objects in the legend window:.
A.) Forgo the use
of our WGLegend... routines and manually
create a legend window yourself with a
combination of a rectangle (WGRectangleNorm),
lines (WGLineNorm), symbols (WGPolygonNorm),
and text (WGTextNorm).
B.) The routine WGChangeString
can be used to modify the text strings found in
the legend window. If you are using line plot
objects, you can accomplishing hiding and/or
showing the line object and legend symbols by
changing the line style to PS_NULL, by making a
call to WGChangeLineStyle. Changing the
line style back to something other than PS_NULL
will again make the line plot visible in the
graph and its associated symbol visible in the
The sample code
below creates a legend window that initially
contains 3 items; one of the line plots is hidden
in both the graph and legend by using a line
style of PS_NULL. In addition, 4 legend strings
are initially defined, but the 4th string text is
// set line style of actual plot to RED
WGSetLineStyle(pGrDesc, hdc, PS_NULL, 2, C_GREEN);
hLine2 = WGLinePlot(pGrDesc, hdc, hData4, FALSE, TRUE);
hStr1 = GlobalAlloc(GPTR, 4 * LG_MAXLEN);
lpLegendStr = (LPSTR)GlobalLock (hStr1);
// Initialize legends
lstrcpy(lpLegendStr, "Measured Values");
lstrcpy(lpLegendStr + LG_MAXLEN, "Predicted Values");
lstrcpy(lpLegendStr + 2 * LG_MAXLEN, "Residuals");
lstrcpy(lpLegendStr + 3 * LG_MAXLEN, "");
hLegend = WGLegendPtr(pGrDesc, hdc, 0.01, 0.79, 0.61, 0.99,
C_BLACK, 2, C_BLUE, C_LIGHTGRAY, OR_HORZ, lpLegendStr);
Now, based on a
user action, the graph is updated to display the
4th plotting object - a line plot, and the 4th
legend string is updated using WGChangeString.
The last parameter in WGChangeString in
this case specifies which legend string to
WGChangeLineStyle(pGraph1, hLine2, PS_SOLID, 0);
WGRedrawObject(pGraph1, hLine2, TRUE);
WGChangeString(pGraph1, hLegend, "Fourth", 3);
WGRedrawObject(pGraph1, hLegend, TRUE);
There is no simple
way to remove items from a legend, but there is a
work-around. You will be able to temporarily
remove an item from a legend (and the graph), but
you will not be able to get the legend to redraw
to take up the space left by the missing legend.
What you need to
do is hide the line plot object as ususal with
WGShowObject. Then, to remove the item (string +
line) from the legend, call WGChangeLineColor for
the line object, changing it to be the same as
the bg color for the legend, and then redraw both
the line plot object and the legend object. Some
pseudo code that I tested under C in the demo
program BIGDEMO is:
WGChangeLineColor(pGraph2, hLine, C_WHITE, 0);
WGRedrawObject(pGraph2, hLeg, TRUE);
WGRedrawObject(pGraph2, hLine, TRUE);
I added this code
to execute in response to a right mouse click,
and it successfully removed the line from the
graph, and removed both the line symbol and the
string from the legend rectangle. The same idea
can be used to add the items back in again.
The 3 supported
metafile types and their descriptions are:
MF_PL Placeable metafile
MF_ENH Enhanced metafile
Graphs saved as
metafiles can be imported by various
applications. In general, the placeable metafile
type is the best to use for both 16-bit and
32-bit applications, since a number of
application programs support the import of this
type. The MF_WIN type is an older type that
placeable has improved upon. The enhanced
metafile type is a new type, which can be
imported only into 32-bit applications which
support this format.
metafile is a standard Windows metafile that has
an additional 22-byte header. The header contains
information about the aspect ratio and original
size of the metafile, permitting applications to
display the metafile in its intended form. Some
popular applications can import only placeable
metafile format has been introduced in Win32 API.
It is not supported for 16-bit programs and it is
not implemented in Win32s API.
You should have
received a registration card inserted right in
the front of the manual (page 1). The
registration card is a tear-off card found on the
bottom of a cardboard page that has our licensing
agreement printed on it. If you fill out and send
in the card, you will then be added to our
registration database, which entitles you to
technical support and puts you on our mailing
list for receiving new product update and
revision announcements. You can also register on-line at our web
Yes, you can use
RGB colors for line plots, etc. First create the
object as usual using one of the pure colors
(i.e. C_BLUE) and after the object is created,
make a call to WGChangeLineColorRGB
This is not a bug.
The Windows API does not support line styles
other than SOLID with line widths greater than 1.
I believe this limitation is removed under
Windows NT through a different implementation,
but we have not made any adjustments in our
Use the WGRectangle
function to create a "highlight"
rectangle. Then be sure to create this rectangle
with this function before you create your
data plot (with WGLinePlot, for example),
so that the rectangle will be drawn behind the
data plot object. You can change the size and/or
the position of this highlight rectangle at a
later time with a call to WGChangeObjectCoord.
I want to plot values, sampled by an a/d, real
time. These values are stored and then plotted on
a static plot when the measurement is finished. I
would like to use either cursors or zooming to
select an area of the static plot. However the
functions which switch on the zoom or cursors are
not declared in the file WRGLOBAL.BAS. They are
declared in VBGLOBAL.BAS, but both files cannot
be included in the same project because of the
double declaration of many functions. |
will help you to understand why you can't easily
use zooming and data cursors in a Real-Time
application. A Charting Tools application uses
the VBHOOK.DLL for mouse events, etc., which
includes the implementation for both the zooming
and data cursor routines. Since RT Graphs can not
properly be zoomed, and since data cursors can
not "trace" real-time data sets, both
zooming and data cursors are not supported for
real-time graphs. A RT Tools application uses the
VBRTHOOK.DLL, which does not include zooming and
data cursor routines for that reason. The problem
comes in cases like yours, where the application
is truly a RT application, but uses both
real-time graphs and static graphs together
(which is perfectly correct, yet rare).
Since VBRTHOOK is the hook file used for this
app., you do not have immediate access to the
zooming and cursor routines for your static
The resolution to
this is a modification of the VBRTHOOK.DLL to
include zooming and cursor support, and adding
the function declarations for these routines to
the WRGLOBAL.BAS file. You are correct in your
assessment that both the WRGLOBAL.BAS file and
the VBGLOBAL.BAS file cannot be used together in
a VB project, since they have duplicate
functions. The steps you need to perform to get
things working are quite straightforward, and a
general outline is as follows:
1.) Copy the
function declarations for the zooming and cursor
routines out of VGLOBAL.BAS (the 32-bit or 16-bit
section) and add them to the declaration section
of WRGLOBAL.BAS. Be sure to change the library
name referenced in each declaration from
VBHOOK32.DLL to VBRTHK32.DLL (or VBHOOK.DLL to
2.) Implement zooming in VBRTHK32.DLL by:
- copying the code used for zooming and data
cursors from the VBHOOK.C file into the
VBRTHOOK.C. Be sure to include VBCURSOR.H. Most
of the code is in the WGGraphMouseEvent
routine, and in some additional support functions
at the end.
3.) Rebuild the VBRTHK32.DLL with the changes,
copy it to the proper directory, and everything
should work fine.
- be sure to add VBCURSOR.C to the project file
Yes. Link QCWINIT
and HOOK with your DLL instead of your .EXE file.
FALSE) to initially create the object and make it
invisible. Then, at a later time, use WGShowObject(...,
TRUE) to display the specified object.
to add annotations (text strings or arrows, etc.) to
graph at run-time, after the graph is already built (i.e.
outside of the graph building routine)?
Same as above, but
using WGText, WGTextNorm, WGArrow,
WGArrowNorm, etc. routines to draw
annotations. The position of objects can be
changed with the functions WGChangeObjectCoord
HGOBJ hLine1, hArrow1;
hLine1 = WGLine(...) // create line object in graph
hArrow1 = WGArrow(...) // create arrow object in graph
WGShowObject(pGrDesc, hLine1, FALSE) // make line invisible
WGShowObject(pGrDesc, hArrow1, FALSE)// make arrow invisible
// later time(based on user action)
WGShowObject(pGrDesc, hLine1, TRUE)
WGShowObject(pGrDesc, hArrow1, TRUE)
// now the line and arrow will be visible
For additions, see
the question above. Deletions can be done with
WGDeleteObject, as well.
Objects cannot be
actually added after the graph is built. The way
around this is to create some extra dummy objects
and make them invisible (WGShowObject).
When needed, position them correctly (WGChangeObjectCoord)
and make them visible.
|How to make a line plot
(etc.) appear only after the user selects data to
plot and sets the plot object parameters?|
Create a line plot object in your graph building
routine, it may be based on a dummy empty data
set. Keep its handle for future actions.
2. Make this object invisible
3. When the user selects data
arrays, create the new data set based on them.
4. Connect this data set to the
hidden plot object with WGReconnectDataSet
(see example in DYNDEMO).
5. Select the line plot object
6. Call WGEditObject as
in HOOK.C - this will bring up the dialog.
7. Finally, make the object
visible with WGShowObject.
No, but this can
be accomplished quite easily. Create an
additional data set to be used for the
"sampled" line marker plot, and define
the data such that it only contains the data
points (x and y values) of the points you want
marked. You can the plot this with either the
WGLineMarkerPlot function or use WGScatterPlot in
conjunction with WGLinePlot on the original data
For every object
create small descriptors containing the values of
the parameters used to create it. Save the
current state of every object in these
descriptors. When building the graph again, use
these saved values.
Currently there is
no way to change the printer output orientation
through code; You MUST invoke the printer dialog
(WGPrinterSetup) to change the printer
orientation, or change the output orientation of
your default printer. We use the common printer
dialog to set printer settings. Calling WGPrinterSetup
invokes this dialog, which is the default
dialog that is associated with the selected
printer driver. From this dialog, you can change
the default printer settings, including the
orientation. If you don't call WGPrinterSetup before
printing, the output will use the default
settings and the printer specified as DEFAULT
(Control Panel, Printers). Also, calling WGSetPrintOptions
(or WGPrintOptionsDlg) will allow you
to set other printer parameters associated with
the Quinn-Curtis page window.
You have two
options for printing with our tools - to print a
single graph (WGPrintGraph) or to print
all of the graph windows "contained" on
a page window (WGPrintPage). Therefore, to
print multiple graphs on a single output page,
create them using separate calls to WGCreateGraph,
in the same page window (1 call to WGCreatePage)
and use WGPrintPage or select Print
Current Page from the Page Menu.
Save it as a
metafile (or to clipboard) and the import it into
instead of WGCreatePage.
Use WGLine or
WGLineNorm (call WGSetLineStyle first
to set line attributes). The line will eventually
become partially erased by your real-time plot
updates, so use WGRedrawObject(...,
...,hLine) at periodic update (timer) intervals
to refresh the line.
Yes. As explained
in the FAQ above, that static plots may be erased
when the real-time plot is updated with new data.
You can periodically refresh the static data
plots by calling WGRedrawObject.
or WGSetTextParams first. All of the
demo programs referenced in the doc. under WRSetButtonControl
- ACQDEMO, FETALMON, SCADA, use one of the
two functions. (WGChangeTextColor does not
work for button controls, so you can't change the
color after the button control is already built
without closing and recreating it, or looking at
the source code and writing directly into the
This is not
supported without closing and re-creating the
graph with different settings for the scroll bar
control. You also have the option, if you have
the source code, to look at the creation of the
scroll bar control and determine how to write the
limit and range parameters to the scroll bar
WGChangeLineStyle, where parameter n will
correspond to the channel number (trace #).
Yes. Multiple Y
axes are supported in a RT Graph - i.e. two
different scrolling graphs (plots) can be plotted
against two Y axes with different scales. To
accomplish this, the sequence of calls is
basically the same as
explained above for the Charting
Simply create the X axis and the first Y axis,
then plot a data set using WRSetScrollGraph,
then create the second Y axis by setting its
intercept and drawing it, then plot your second
EXAMPLE (Modified SWEEPDEM, DrawP1G2 routine)
// First Sweep Graph
WGSetPlotArea(pGrDesc, hdc, 0.2, 0.18, 0.90, 0.82, C_GRAY);
WGScalePlotArea (pGrDesc, 20.0, -2.0, 0.0, 2.0);
WGSetXYIntercepts (pGrDesc, 20.0, -2.0);
hAxisX = WGDrawXAxis(pGrDesc, hdc, 5.0, 5, POS_MIDDLE);
hAxisY = WGDrawYAxis(pGrDesc, hdc, 1.0, 1, POS_LEFT);
WGLabelAxis(pGrDesc, hdc, hAxisX, POS_BELOW, NF_DECIMAL,
WGLabelAxis(pGrDesc, hdc, hAxisY, POS_LEFT, NF_DECIMAL,
1, LL_ON, NULL);
WRSetSweepGraph (pGrDesc, ...);
// Second Sweep Graph
WGScalePlotArea (pGrDesc, 20.0, 0.0, 0.0, 10.0);
WGSetXYIntercepts (pGrDesc, 0.0, 0.0);
hAxisY2 = WGDrawYAxis(pGrDesc, hdc, 0.5, 1, POS_RIGHT);
WGLabelAxis(pGrDesc, hdc, hAxisY2, POS_RIGHT, NF_DECIMAL,
1, LL_ON, NULL);
WRSetSweepGraph (pGrDesc, ...);
There is a bug in
MFC 4.2 which interferes with timer callbacks. IN
the RT Tools, the grid lines and alarm lines are
updated in our DLLs using timer messages. This
bug and the work around is documented in the
Microsoft Knowledge Base article Q154652, dated
The work around to
the problem is to override PreTranslateMessage in
the thread that owns the timer. In a simple MFC
program this means overriding the
PreTranslateMessage member function of the
CWinApp derived class.
Make the page
window a child of the form. Use the WS_CHILD
styles + WS_CLIPCHILDREN + WS_VISIBLE as in the
call to WGCreatePage in mdidemo and in
many of the RT example programs. Pass in the
form's handle, i.e. form1.hwnd, as the
second (hwParent) parameter to WGCreatePage,
and use the above styles in the dwWinStyle parameter.
You can also make the graph a child of a picture
box, etc., in the same manner.
Child windows are
not resized automatically. When a parent window
receives the WM_SIZE message, it must resize its
child windows. This can be accomplished by using
the Windows API routine SetWindowPos. See
the example in MDIDEMO.
This can happen if
you choose PAGE_EXACT for page positioning and
set cx and cy to very small values with intention
to resize the page window later. Set these
parameters to reasonable values.
1. Create page as
2. Create graph with range > 1.0, for example,
rY1 = -0.5, rY2 = 1.5. There are limitations on
the ranges - they cannot exceed approximately
2.5, or an integer overflow may occur.
3. Create your own scrolling bar control and the
procedure for it, and to change the graph
position in the window use our function WGChangeGraphPos.
1. Before calling WGText
use the function WGGetTextSizeNorm to get
the text height in relative coordinates.
2. Knowing the plotting area height in relative
coordinates (difference between rY2 and rY1 that
you used in WGSetPlotArea) and the Y-axis
range, recalculate the text height to physical (Y
3. Call WGText with rY adjusted by 1/2 of
the text height in physical coordinates.
You can make text
size relative - use calculated values instead of
fixed ones in WGSetTextByName. The
calculations should be based on ratio of initial
window size and screen size.
VB can move
strings around. To prevent it, make them static.
Make a call to WGEnableDialogs(FALSE) to
globally turn off the default editing with the
C - Edit HOOK.C or RTHOOK.C, and
comment out the call to WGEditObject or WREditObject
found in the WM_LBUTTONDBLCLK case of the the
Delphi - Edit HOOK.PAS or
RTHOOK.PAS, and comment out the call to WGEditObject
or WREditObject found in the
WM_LBUTTONDBLCLK case of the the routine WGGraphMouseEvent.
Use the function
WGSetMouseEventAction to enable built-in and user defined mouse
Use the function WGSetMouseEventAction to enable built-in and user defined mouse
No, you do not
need the source code to change the default mouse
cursor from the QC double arrow to the
"normal" arrow pointer or anything
else. In fact, it is quite easy.
For users of the C
Tools: simply modify the resource (.RC) file that
is included in the project. For most of our demos
this file is DEMO.RC. Open this file in the
Visual C++ editor as a text file, locate the
comment it out. Alternatively you could delete
the cursor from the resource file, or speicify
your own customized cursor (.CUR) on this line.
See the Charting Tools manual document, index
For users of the
VB Tools: You need to modify the resource file
that is compiled into the VBHOOK DLL and then
rebuild the DLL. Open this file (VBHOOK32.RC) in
Visual C++ editor as a text file, locate the
and comment it
out. Alternatively you could delete the cursor
from the resource file, or speicify your own
customized cursor (.CUR) on this line. See the
Charting Tools manual document, index item
We do not have an
automatic way to zoom out on a graph that has
already been zoomed in upon, but you can restore
the original settings or zoom out fairly easily.
There are two methods for zooming out on a graph
A.) You zoom
"out" on a Charting Tools graph window
in the same way that you zoom "in" - by
using the mouse. Simply click the mouse button
used for zooming outside of the plotting area
(area bounded by the axes), drag to the other end
of the window, and release the mouse button
outside of the plotting area. This will perform a
zoom "out", changing the axes ranges,
etc. to encompass a larger range.
B.) To actually
restore original settings, first save the
original graph axis settings (range, intercept,
and ticks, if necessary) before any zooming is
performed. You can save the values directly or
retrieve them with calls to the WGGetAxis...
series of routines. Then, after zooming is
completed, you can "zoom out" and
restore the original settings by calling the
appropriate WGChangeAxis... function with
the saved values, to restore the original graph.
A good option to provide the user with would be a
button, used to restore the original settings at
To restore the
axes settings to their original values (i.e. zoom
"out") when the user is done zooming,
call WGChangeAxisRange, and WGChangeAxisIntercept,
if necessary, with the original axis settings.
The original axis settings should be stored in
variables at the time that they were created with
WGDrawXAxis or WGAutoAxes. In the
graph building routine, when an axis is created
with one of these two routines, call WGGetAxisRange(...
min, max) to retrieve the min and max values (can
do for intercept, also). Store these values in
your variables for later use, to restore the
graph to original settings as described above (WGChange...).
You can use a
scroll bar in conjunction with changing the range
of the x-axis in a graph to pan the graph.