|
| |
This
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: support@quinn-curtis.com,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
below.
Currently our technical FAQs are organized into the
following categories:
- Axes
 | 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
plot? |
 | 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.
(-OR-)
I want on Y axis to be on the left edge
of the plotting area, and the other on
the right? |
 | 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
accordingly. |
 | If the range of one
axis is changed, other axis change
automatically. |
 | When
I change axis range, intercept, and
distance between tick marks, the graph
looks bad, with incorrect number of tick
marks. |
Datasets
Dialog
Errors
Installation
Labels
Legend
Misc.
Objects
Printing
RT
Sizing
Text
User Interface
Zooming
Top

Axes
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.
(-OR-)
I want on
Y axis to be on the left edge of the plotting
area, and the other on the right. |
Basically just
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
marks. |
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
call.
Top

Datasets
There are two
procedures to consider when updating a graph with
new data:
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:
WGDefineDataSet(new)
WGReconnectDataSet
WGFreeDataSet(old)
DEMO PROGRAMS:
DYNDEMO, NEWDATA
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.
DEMO PROGRAM:
COMPDATA
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? |
While 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
called.
Memory allocated
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
not discardable.
It is recommended
by Microsoft that in 32-bit applications you
should use other dynamic allocation functions
such as calloc or HeapAlloc instead of
GlobalAlloc.
Top

Dialog
Step 1:
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)
DialogProc);
Define a dialog
box procedure DialogProc and add its prototype to
the top of your program file. The prototype looks
like:
BOOL CALLBACK DialogProc (HWND hDlg, UINT
message, WPARAM
wParam, LPARAM lParam);
Step 2:
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 (...)
{
...
switch (message){
WM_INITDIALOG:
WGCreatePage(""PAGE1"",
hDlg, hInst,
""First Graph""
StartGraphs1,
PageMenu",
C_LIGHTGRAY,
MM_PROPORT,
WS_CHILD |
WS_CLIPCHILDREN |
WS_VISIBLE,
PAGE_EXACT,
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
2.
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.
DEMO
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
complete instructions.
DEMO PROGRAM:
GCLDIALG.ZIP
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
following example:
// First, select object:
WGSelObject (pGrDesc, // graph descriptor
hScroll); // object handle
// now call the undocumented function that
will bring up the dialog:
WGEditObject (WGGetGraphWindow(pGrDesc));
// If you are using the Real-Time Tools,
call WREditObject instead.
Top

Errors
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.
Recompile all
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.
Top

Installation
This happens on
some systems connected to a Novell network. Edit
the INSTALL.CFG file on the disk and replace the
following:
____________________________________________
IF
LOCATE("WCT32D.DLL")
DEFAULTDIR: "$locatedir$",
prompt="Please enter
directory for upgrade:"
ELSE
DEFAULTDIR: c:\qcw32, prompt="Enter the
drive and directory
where you wish the Charting Tools to be
installed:"
ENDIF
____________________________
with
DEFAULTDIR: c:\qcw32, prompt="Enter the
drive and directory
where you wish the Charting Tools to be
installed:"
 | 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
Basic program. |
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.
Remember, also,
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
systems.).
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.
Top

Labels
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.
Top

Legend
 |
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
legend window.
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
NULL (""):
// 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
change:
void UpdateGraph(void)
{
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.
Top

Misc
The 3 supported
metafile types and their descriptions are:
MF_WIN Standard
Windows metafile
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.
A placeable
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
metafiles.
The enhanced
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
site.
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
software.
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.
 | (VB ONLY)
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. |
Some background
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
graph.
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
VBRTHOOK.DLL).
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
before rebuilding.
Yes. Link QCWINIT
and HOOK with your DLL instead of your .EXE file.
Top

Objects
Use WGShowObject(...,
FALSE) to initially create the object and make it
invisible. Then, at a later time, use WGShowObject(...,
TRUE) to display the specified object.
<OR>
How
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
and WGChangeObjectCoordNorm.
EXAMPLE:
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
...
do graphs
...
// later time(based on user action)
WGShowObject(pGrDesc, hLine1, TRUE)
WGShowObject(pGrDesc, hArrow1, TRUE)
// now the line and arrow will be visible
DEMO PROGRAM:
SHOWHIDE
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? |
1.
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
using WGShowObject
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
using WGSelObject
|