FB II Compiler
Handle window's refresh
To do a refresh, you have two choices, as far as I know:
1. Rebuild the window as if you were drawing it from scratch (you may want to clip the drawing area to the invalid rectangle though for a tidier refresh).
2. As soon as you build your window, copy the window contents to an offscreen gWorld and then copy the contents back to your window whenever you need to do a refresh.
These are just quick thoughts to get you started. I'm sure others will fill in the details.
You should not be drawing into the window immeditaletly after you build it. Instead, put all of your drawing code at the place in your program where you get update events. Then things will work like they should.
There are different ways to do this, but if your graph is fairly static, then perhaps the best thing is to turn it into a "picture field." FB redraws a picture field automatically whenever the window gets uncovered.
The first step is to "record" the picture that you want to put into the field. This is done by surrounding the drawing commands with a PICTURE ON statement and a PICTURE OFF statement, like so:
(x1,y1)-(x2,y2) represents the rectangle containing the graph. pictHandle& receives a handle to the recorded picture--you'll use that later.
PICTURE ON (x1,y1)-(x2,y2)
'[commands which draw the complete graph]
PICTURE OFF , pictHandle&
This "recording" can take place in any window, visible or invisible, as long as the window's clipping region doesn't exclude the rectangle (x1,y1)-(x2,y2). The drawing is not actually displayed during "recording," even if the window is visible.
Once you've got a handle to a recorded picture, you can make a picture field for it, as follows:
The (x1,y1)-(x2,y2) define the rectangle where the picture will appear. If this rectangle is the same width and height as the one you used when you recorded the picture, then the picture will display at the same scale: otherwise, the picture will be scaled to whatever dimensions you provide (but see the "just" parameter in the description of the PICTURE FIELD command, for more variations on this).
p$ = "&" + MKI$(pictHandle&)
PICTURE FIELD #1, p$, (x1,y1)-(x2,y2), _framed
The "#1" is a picture field ID (this may differ in your program), and the "_framed" is one of several framing options you can provide (see the description of PICTURE FIELD for more).
Now your graph will refresh itself automatically.
If you want to _change_ the picture, in a picture field that you created previously (and haven't yet closed), then use PICTURE FIELD with only its first two parameters. For example:
'[assume newPict& is a handle to (another) recorded picture]
When you're "done" with a picture (i.e., it's no longer being displayed in a Picture Field, and you don't intend to use it again later), then you should dispose of it by calling KILLPICTURE(thePictHandle&). This will free the memory that the picture was taking up, and will also allow you to re-use the variable "thePictHandle&" to store the handle of another picture. But you should definitely _not_ call KILLPICTURE while the picture's still being displayed in a picture field.
p$ = "&" + MKI$(newPict&)
PICTURE FIELD #1, p$
You can get rid of a picture field altogether by executing EDIT FIELD CLOSE #fieldID (yeah, I know it's not an Edit Field, but I didn't write the language); or by closing the window itself. This doesn't dispose of the recorded picture that was in the field: you still need to call KILLPICTURE to do that.
Good God - another person writing stats programs in FB and in a Psychology Dept as well! It is a strange world.
Refreshing took me a while to understand.
The trick is - dont draw anything to your window after FN pGbuild(_windowGraph).
Rather - create a FN plotStuff.
and at _wUpdate
long if gWhichWindow = _windowGraph
A split second after your window is built a window refresh event is generated. You need to only draw things to a window in response to one of these events. (There are actually times with PG that this is not the best way - but unless you are playing with the window resources then stick to this rule)
As Tedd would say - PG rules!
Creating a GWorld for the duration of the refresh can save you memory in the proper circumstances. If you have many windows open at a time, having to keep one GWorld for each one could add up to a lot of memory. In addition, depending on your circumstances, it might be possible to make the program automatically switch back to drawing in the window if it can't get enough memory. This would allow your program to run in less memory, but improve performance for those who had more.
However, creating one GWorld per window, doing all your drawing into the GWorld, then just copybitsing into the window on refreshes is a much "snappier" and smoother technique. IF you can afford the memory, I'd do it that way.
When I do this type of thing, I make use of GWorld. I first draw the graphic in the window (while user is watching) and then slam a copy to GWorlds. Any refreshing come directly from GWorld and the user is not presented with a complete redraw. It is fast! I only dispose of the GWorld copy when the window is gone.