It is not currently possible to draw on a hidden graphicbox, then transfer the image from the hidden graphicbox to a visible graphicbox. If it were possible, it would be achieved by using GETBMP on the hidden graphicbox to get a named Liberty BASIC bitmap, then using DRAWBMP on that named bitmap to draw it into the visible box. Since this will not work, the alternative is to use GDI functions to do the drawing in memory.
Drawing with the Graphics Device Interface (GDI) is a subject that would easily fill an entire book. This tutorial is NOT a tutorial on drawing with GDI. It presents a method to draw in memory, then place the image on the screen in Liberty BASIC. It doesn't attempt to explain the individual GDI drawing functions.
It is assumed that the reader understands the fundamentals of making Windows API calls. For more information on making API calls, and for using GDI functions, please examine one of the many Windows API reference books that are available in libraries and bookstores, or check the Microsoft Developers Network Library here:
You may also check my website and electronic books:
THE DEVICE CONTEXT
GDI doesn't draw on a window, it draws on a device context (DC). A DC is an interface used by GDI so that Windows can draw on any of the variety of hardware that might be installed on a computer. Windows can also draw on a memory device context, and that is what we'll use for this method.
MEMORY DRAWING - STEP BY STEP
Here is an outline of the steps we'll be using.
- create a window with a graphicbox
- put the pen DOWN in the graphicbox
- use GetBmp to get a Liberty BASIC bitmap from the graphicbox
- obtain the handle of the graphicbox with the hwnd() function
- obtain the handle of the Liberty BASIC bitmap with the hbmp() function
- get a DC for the graphicbox with GetDC
- create a memory DC with CreateCompatibleDC
- select the LB bitmap into the memory DC with SelectObject
- issue GDI drawing commands to the memory DC
- select the default bitmap back into the memory DC, freeing the LB bitmap
- use DRAWBMP to display the bitmap in the graphicbox - flushing if desired
- as many times as needed, select the bitmap into the memory
DC, draw on it with GDI functions, deselect it from the memory DC and display with DRAWBMP
When the program ends:
- delete the created DC with DeleteDC
- release the graphicbox DC with ReleaseDC
- delete the LB bitmap with UNLOADBMP
MEMORY DRAWING - THE THEORY
Using the GETBMP command allows us to get a named, Liberty BASIC bitmap that we can display with DRAWBMP or save with BMPSAVE. We can get a Windows handle to this bitmap with the HBMP() function. Once we have a Windows handle, we can select the bitmap into a memory device context and use GDI functions to draw on it. After deselecting the LB bitmap out of the memory device context, we can draw the altered bitmap in our graphicbox with DRAWBMP or we can save it to disk with BMPSAVE.
USING GDI - THE DISADVANTAGES
The most obvious disadvantage of drawing with GDI rather than using Liberty BASIC's own drawing commands is that the API drawing functions are more complicated, and they require device contexts to be gotten, created, released and destroyed. Using GDI also requires that pens, brushes and fonts be created, selected into the device context, and destroyed when they are no longer needed.
USING GDI - THE ADVANTAGES
Using GDI functions allows us to draw in memory, which presents many possibilities, such as flicker-free animation, and the ability to draw many objects before allowing the user to view them. In other words, the drawings can be presented as a finished picture, and the user doesn't see each step as it is drawn. There is one other big advantage to using GDI functions. There are many more graphics possibilities with GDI functions than with Liberty BASIC drawing commands. There are functions to floodfill, to create other objects such as arcs and round rectangles, to draw text that is filled with patterns, to draw with different RASTER OPERATIONS (this is how sprites are done) and on and on.
DRAWING IN MEMORY - A SIMPLE SAMPLE
The following code will run in Liberty BASIC 3.x. It is well commented.
nomainwin 'graphicbox size includes borders, 'so requires 202x202 graphicbox to 'display a drawing area 200x200 graphicbox #1.g, 10,10,202,202 open "Memory Drawing" for window_nf as #1 #1 "trapclose [quit]" #1.g "down" 'use getbmp to get an LB bitmap #1.g "getbmp mem 0 0 200 200" h=hwnd(#1.g) 'handle of graphicbox hMem=hbmp("mem")'handle of LB bitmap 'get a device context for graphicbox CallDLL #user32, "GetDC",_ h As long,_ 'handle of graphicbox hDC As long 'returns device context 'create a device context in memory 'that has the same attributes as the 'device context for the graphicbox CallDLL #gdi32,"CreateCompatibleDC",_ hDC As long,_ 'device context of graphicbox memDC As long 'returns memory device context 'select the LB bitmap into the 'memory device context CallDLL #gdi32,"SelectObject",_ memDC As long,_ 'handle of memory DC hMem As long,_ 'handle of LB bitmap oldObject As long 'returns handle of previous 'bitmap in DC 'draw some graphics with GDI functions: CallDLL #gdi32, "Rectangle",_ memDC As long,_ 'memory DC 10 As long,_ 'upper left x 10 As long,_ 'upper left y 60 As long,_ 'lower right x 80 As long,_ 'lower right y r As boolean 'next call requires this struct struct Point, x as long, y as long 'same as LB's PLACE command CallDLL #gdi32, "MoveToEx",_ memDC As long,_ 'memory DC 40 As long,_ 'x 20 As long,_ 'y Point As struct,_ 'returns previous x and y r As boolean 'same as LB's GOTO command CallDLL #gdi32, "LineTo",_ memDC As long,_ 'memory DC 140 As long,_ 'x 70 As long,_ 'y r As boolean 'fill a string variable t$="Memory Drawing" 'get length of variable ln=len(t$) 'draw the text CallDLL #gdi32, "TextOutA",_ memDC As long,_ 'memory DC 10 As long,_ 'x location 130 As long,_ 'y location t$ As ptr,_ 'string of text ln As long,_ 'length of string r As long 'you must deselect the bitmap from 'the memory DC each time you want to 'display it with DRAWBMP ' 'select the previous bitmap back 'into the memory DC to do this CallDLL #gdi32,"SelectObject",_ memDC As long,_ 'memory DC oldObject As long,_ 'original bmp in memDC hMem As long 'returns bmp to deselect 'now, simply draw it with DRAWBMP 'and flush #1.g "drawbmp mem 0 0; flush" wait [quit] 'be sure to unload the bmp unloadbmp "mem" 'release the DC for the graphicbox CallDLL#user32,"ReleaseDC",_ h As long,_ 'graphicbox handle hDC As long,_ 'DC handle result As long 'delete the memory DC from memory CallDLL #gdi32, "DeleteDC",_ memDC As long,_ 'memory DC handle r As boolean close #1:end