Here is some code that Joske posted on CodingMonkeys http://www.codingmonkeys.com/index.php?topic=877.0
I corrected and tweaked the code to add some features. Eventually, I will rewrite this to be a general purpose fundtion plotter. This was written for IBPro, but compiles fine in EBasic.
/*
flicker_free_graph.eba by jos de jong
with help from the ibasic forums (see codingmonkeys.com)
tweaked by John Siino
this version of flicker free graph does take a certain scale factor as constant,
and depending on that calculates the boundaries xmin, xmax, ymin, ymax of the graph
when the graph is resized or moved
you can move the graph by dragging the mouse or with the arrow keys
you can zoom the graph with keys + and -
*/
'DECLARATIONS
$INCLUDE "windows.inc"
DECLARE IMPORT, LoadCursor ALIAS LoadCursorA(hInstance AS INT,lpCursorName AS POINTER),INT
DECLARE IMPORT, GetCursorPos(lppoint:POINTER)
DECLARE IMPORT, ScreenToClient(HWND:uint, lppoint:POINTER)
WINDOW figure, plotwin
'axes of the graphics screen
DOUBLE xmin, xmax, ymin, ymax
'factors such that xscreen = x * xfactor + xshift and yscreen = y * yfactor + yshift
DOUBLE xfactor, xshift, yfactor, yshift
DEF MouseDownL, MouseDownR, MouseStartX, MouseStartY:INT
CONST Black=0
Figure_Load()
Refresh_Scale()
Plot_Graph()
SETFOCUS plotwin
WAITUNTIL figure=0
END
'_______________________________________________________________________
SUB Figure_Load()
'load window figure with subwindow plotwin
string figtxt
figtxt = "Figure - Move by dragging mouse or with arrow keys, zoom with + and -"
'load the window (outside the screen)
OPENWINDOW figure, -600,100,500,400, @MINBOX|@MAXBOX|@SIZE|@NOAUTODRAW, 0, figtxt, &RoutineFigure
OPENWINDOW plotwin, 0,0,200,200, @NOCAPTION | @NOAUTODRAW, figure, "plot", &RoutinePlotWin
'create this window with a sunken border
_SetWindowLong(plotwin.hwnd,-20,512)
_SetWindowPos(plotwin.hwnd,NULL,0,0,0,0,39)
Resize()
CfgSetDefault()
'center the window in the screen so it is visible now
CENTERWINDOW figure
RETURN
ENDSUB
'_______________________________________________________________________
SUB RoutineFigure()
'handling of messages from window figure
SELECT @MESSAGE
CASE @IDCLOSEWINDOW
'close the figure window
CLOSEWINDOW plotwin
CLOSEWINDOW figure
CASE @IDSIZECHANGED
Resize()
Refresh_Scale()
Plot_Graph()
ENDSELECT
RETURN
ENDSUB
'_______________________________________________________________________
SUB RoutinePlotwin() :'handling of messages from window plotwin
SETTYPE @HITWINDOW, WINDOW
SELECT @MESSAGE
CASE @IDPAINT
Refresh_Scale()
Plot_Graph()
CASE @IDLBUTTONDN
'move axes
_SetCapture(*@HITWINDOW.hwnd)
GetCursorPos(&@MOUSEX)
ScreenToClient(*@HITWINDOW.hwnd, &@MOUSEX)
MouseStartX = @MOUSEX
MouseStartY = @MOUSEY
SETCURSOR plotwin, @CSCUSTOM, LoadCursor(NULL, IDC_SIZEALL) :'cursor "move"
CASE @IDLBUTTONUP
_ReleaseCapture()
SETCURSOR plotwin, @CSARROW :' cursor back to normal cursor
CASE @IDMOUSEMOVE
if (_GetCapture() = *@HITWINDOW.hwnd)
GetCursorPos(&@MOUSEX)
ScreenToClient(*@HITWINDOW.hwnd, &@MOUSEX)
'Left mousebutton down. move the plot with the mouse movement
'xmin -= (@MOUSEX-MouseStartX) / xfactor
'xmax -= (@MOUSEX-MouseStartX) / xfactor
'ymin -= (@MOUSEY-MouseStartY) / yfactor
'ymax -= (@MOUSEY-MouseStartY) / yfactor
xshift += (@MOUSEX-MouseStartX)
yshift += (@MOUSEY-MouseStartY)
MouseStartX = @MOUSEX
MouseStartY = @MOUSEY
'replot
Refresh_Scale()
Plot_Graph()
ENDIF
CASE @IDKEYDOWN
'check keypresses
'for the keycodes, see the usersguide Appendix, Virtual key codes
SELECT @WPARAM
CASE 0x25
'left arrow is pressed. move the graph to the left
xshift -= 20
Refresh_Scale()
Plot_Graph()
CASE 0x27
'right arrow is pressed. move the graph to the right
xshift += 20
Refresh_Scale()
Plot_Graph()
CASE 0x26
'up arrow is pressed. move the graph up
yshift -= 20
Refresh_Scale()
Plot_Graph()
CASE 0x28
'down arrow is pressed. move the graph to down
yshift += 20
Refresh_Scale()
Plot_Graph()
ENDSELECT
CASE @IDCHAR
'check keypresses
'for the keycodes, see the usersguide Appendix, Virtual key codes
SELECT @WPARAM
CASE ASC("+")
CASE& ASC("=")
'+ key is pressed. zoom the graph in
xfactor *= 1.2
yfactor *= 1.2
Refresh_Scale()
Plot_Graph()
CASE ASC("-")
CASE& ASC("_")
'- key is pressed. zoom the graph out
xfactor /= 1.2
yfactor /= 1.2
Refresh_Scale()
Plot_Graph()
ENDSELECT
ENDSELECT
RETURN
ENDSUB
'_______________________________________________________________________
SUB Plot_Graph() :'this sub repaints the graph
INT L,T,W,H, hdc, hdcMem, hbmMem, oldBmp, oldBrush, oldPen, oldFont
DOUBLE xscreen, yscreen
GETCLIENTSIZE(plotwin, L,T,W,H) :'get size of window
'Create an off-screen DC for double-buffering
hdc = _GetDC(plotwin.hwnd)
hdcMem = _CreateCompatibleDC(0)
hbmMem = _CreateCompatibleBitmap(hdc, W, H)
oldBmp = _SelectObject(hdcMem, hbmMem)
oldBrush = _SelectObject(hdcMem, _CreateSolidBrush(RGB(255,255,255)))
oldPen = _SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(255,255,255)))
'set specific font
INT textW, textH, fontsize, fontwt
STRING fontface
fontface = "Courier New" : fontsize = 12 : fontwt = 600
SETFONT plotwin, fontface, fontsize, fontwt, 0
GETTEXTSIZE(plotwin, "A", textW, textH) :'find the desired text Height
oldFont = _SelectObject(hdcMem, _CreateFont(textH,0,0,0,fontwt, 0,0,0,0,0,0,0,0, fontface))
_SetTextColor(hdcMem, RGB(0,0,255))
_SetBkMode(hdcMem, TRANSPARENT)
_SetTextAlign(hdcMem,TA_UPDATECP)
'empty window -> draw white, filled rectangle
_Rectangle(hdcMem, 0, 0, W, H)
'Paint axes with black frontpen
_DeleteObject(_SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(0,0,0))))
_MoveToEx(hdcMem, xmin * xfactor + xshift, 0 * yfactor + yshift, NULL)
_LineTo(hdcMem, xmax * xfactor + xshift, 0 * yfactor + yshift)
_MoveToEx(hdcMem, 0 * xfactor + xshift, ymin * yfactor + yshift, NULL)
_LineTo(hdcMem, 0 * xfactor + xshift, ymax * yfactor + yshift)
'paint the function with red frontpen
_DeleteObject(_SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(255,0,0))))
xscreen = 0 : yscreen = -myfunction((xscreen-xshift)/xfactor) * yfactor + yshift
_MoveToEx(hdcMem, xscreen, yscreen, NULL)
FOR n=0 TO w+5 STEP 2
xscreen = n : yscreen = -myfunction((xscreen-xshift)/xfactor) * yfactor + yshift
_LineTo(hdcMem, xscreen, yscreen)
NEXT n
'Print some text with blue frontpen
_DeleteObject(_SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(0,0,255))))
STRING mystring : mystring = "Sin(x)"
_MoveToEx(hdcMem, 10, 19 * H / 20, NULL)
_TextOut(hdcMem, 0, 0, mystring, len(mystring))
'Print axes labels with black frontpen
_DeleteObject(_SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(0,0,0))))
_MoveToEx(hdcMem, 19 * W / 20, yshift, NULL)
_TextOut(hdcMem, 0, 0, "x", len("x"))
_MoveToEx(hdcMem, xshift, H /40, NULL)
_TextOut(hdcMem, 0, 0, " y", len(" y"))
'Print axes tick marks with black frontpen
_DeleteObject(_SelectObject(hdcMem, _CreatePen(PS_SOLID,1,RGB(0,0,0))))
FOR n=0 TO w+5 STEP 1
_MoveToEx(hdcMem, -n * xfactor + xshift, yshift - H / 50, NULL)
_LineTo(hdcMem, -n * xfactor + xshift, yshift + H / 50)
_MoveToEx(hdcMem, n * xfactor + xshift, yshift - H / 50, NULL)
_LineTo(hdcMem, n * xfactor + xshift, yshift + H / 50)
_MoveToEx(hdcMem, xshift - H / 50, -n * yfactor + yshift, NULL)
_LineTo(hdcMem, xshift + H /50, -n * yfactor + yshift)
_MoveToEx(hdcMem, xshift - H / 50, n * yfactor + yshift, NULL)
_LineTo(hdcMem, xshift + H /50, n * yfactor + yshift)
NEXT n
'Transfer the off-screen DC to the screen
_BitBlt(hdc, 0, 0, W, H, hdcMem, 0, 0, SRCCOPY)
'Free-up the off-screen DC
_DeleteObject(_SelectObject(hdcMem, oldFont))
_DeleteObject(_SelectObject(hdcMem, oldBrush))
_DeleteObject(_SelectObject(hdcMem, oldPen))
_DeleteObject(_SelectObject(hdcMem, oldBmp))
_DeleteDC(hdcMem)
_ReleaseDC(plotwin.hwnd, hdc)
RETURN
ENDSUB
'_______________________________________________________________________
SUB myfunction(value:DOUBLE),DOUBLE
'calculate a functionvalue
RETURN sin(value)
ENDSUB
'_______________________________________________________________________
SUB Refresh_Scale()
'calculate the boundaries xmin, xmax, ymin, ymax for painting in the screen plotwin
'this depends on the scale of the graph and the size of the window plotwin
INT L,T,W,H
GETCLIENTSIZE plotwin, L,T,W,H
'xfactor = W / (xmax - xmin)
'yfactor = -H / (ymax - ymin)
'xshift = -xmin * xfactor
'yshift = -ymax * yfactor
xmin = (0-xshift) / xfactor
xmax = (w-xshift) / xfactor
ymin = (0-yshift) / yfactor
ymax = (h-yshift) / yfactor
RETURN
ENDSUB
'_______________________________________________________________________
SUB Resize()
'resize figure window with its subwindow
INT L,T,W,H
GETCLIENTSIZE figure, L,T,W,H
SETSIZE plotwin, 0,0,W,H
RETURN
ENDSUB
'_______________________________________________________________________
SUB CfgSetDefault()
'set default values for the properties of the figure
INT L,T,W,H
GETCLIENTSIZE plotwin, L,T,W,H
'xmin=-5
'xmax=5
'ymin=-5
'ymax=5
xfactor = 40
yfactor = 35
xshift = W/2 :'start the axis at half the width of the plotwin
yshift = H/2
RETURN
ENDSUB
Here's a quick addition to make it even easier for the mouse wheel fans like myself.
Just add this in the declaration section:
SETID "IDMOUSEWHEEL",522
and add this just before the last ENDSELECT in the RoutinePlotwin():
CASE @IDMOUSEWHEEL
IF (@WPARAM & 0x10000000)
'Wheel rotated downwards. Zoom the graph in
xfactor *= 1.2
yfactor *= 1.2
Refresh_Scale()
Plot_Graph()
ELSE
'Wheel rotated upwards. Zoom the graph out
xfactor /= 1.2
yfactor /= 1.2
Refresh_Scale()
Plot_Graph()
ENDIF
Now you can just turn the wheel backwards for zooming in and forwards to zoom out.
Barney
good idea barney!
Feel free to use it as you see fit.
Barney
Hi to all.. :)
I just found this old topic with this great example for double buffered window.
I search trough net to find something useful for universal program (in C or C++) which cover
double buffering and cannot found nothing concrete.... :-\
Hi again... :)
After long search and looking into Creative source code i am still confused and don't
know how exactly is window double-buffered in CB/EB/IWB by GDI functions...
which enable call any graphich functions anywhere from code.
Is here anyone who can put me in right directions?
thanks in advance.. ;)
Aurel
Aurel
double buffering is easy and it is explained in detail w/examples in my tutorial for creating a custom control.
The sections you are mainly interested in are 16 and 17
http://www.ionicwind.com/forums/index.php?board=69.0
Larry
I have read all your excellent tutorial about GDI,double buffering and all this things work fine
BUT
in all this codes your point is how to use drawing with GDI inside WM_PAINT event(message),right?
And as we all know CB/EB/IWB window is by default double-buffered and don't need WM_PAINT to
draw something on window ,do i have right ?
So if originel IWB window don't need to use WM_PAINT for any drawing where is this double buffering
created? Becuse we can use any drawing function anywhere in the code.
Is this something conected with DIB bitmaps or something like this ,or is maybe hiden class which
contain double buffering capability...
Quote from: aurelCB on June 08, 2013, 03:55:45 PM
...
in all this codes your point is how to use drawing with GDI inside WM_PAINT event(message),right?
And as we all know CB/EB/IWB window is by default double-buffered and don't need WM_PAINT to
draw something on window ,do i have right ?
...
wrong!
That's why IWBasic is so nice to work with. It hides all that from you.
IWB has a hidden message handler that normally handles WM_PAINT messages.
You can create the IWB window with the ownerdrawn flag and you can write your own code to handle WM_PAINT.
The same goes with all the other messages that are normally handled internally by IWB.
Remember that there is a RETURN 0 at the end of the IWB message handles?
By returning zero you are telling the hidden handler to process the message instead of the user.
Some messages get handled internally anyway regardless of whether or not you return 0 but that is by the design of IWB.
When you create an IWB window you create a structure WINDOW which is unique to IWB. one element of that structure is .hwnd which is the actual windows handle. another element is .hdc which is the handle to the device context for that window.
To the MS operating system there is no difference between a window, as we know it in IWB, and a control. They are both created with the same api command. That's why my tutorial supplies you with EXACTLY what you need for the question you are asking. It is doing out in the open for you to see what is hidden from view in IWB.
Larry...
I understand what you are trying to tell me and from your answer i only can see
that this technique of hiding looks like some sort of secret.
And you tell me that in your examples you open this secret and that there is a answer to my
question but is not if i work only on api level this things not work as i espected.
And let me clear something to..
I don't wont clone IWB doublebuffered window than just simplify things to use and avoid need
to use classic
CASE WM_PAINT
ooohh is to late here...good night... ;)
Aurel
You asked how to create a double buffered window.
I answered that.
Double buffering is accomplished in response to a WM_PAINT message being sent by the operating system.
So, with my previous response I showed you where to find an example of where to find an example.
So everyone understands, I understand you are asking about this because you are wanting to enhance the GUI capabilities of another basic language you are currently using. As a result I'm not going to spend a lot of my time writing code to show you exactly how to better a competitor.
So, I will only tell you what you need that can be gleaned from reading my control tutorial.
The following ignores any "secrets" of IWBasic.
When any window or control is created via API one of the required parameters is the "class".
Before a window/control can be used the "class" has to be defined and registered (there's an API for that:RegisterClassEx). One of the pieces of information required during the registration process is the name of the message handler to be used for all windows/controls of that class.
You then have to supply the code for the message handler.
Then minimum you can get by with would be:
MyWndProc(hwnd, uMsg, wParam, lParam)
{
switch (uMsg)
{
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Since there are no other CASE statements, messages will be passed straight through to the OS default window message handler.
But you want to double buffering so you are going to have to write code in response to the WM_PAINT message so the above starts to look like this:
MyWndProc(hwnd, uMsg, wParam, lParam)
{
switch (uMsg)
{
case WM_PAINT:
/* code like in my control tutorial */
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
If you want to allow the initialization of something you can add code in a WM_CREATE case or any other message that the OS sends.
That's about it for me on the subject.
As much as you program you should be able to figure it out from there.
Larry
I understand you and yes this is connected with another compiler but i don't have in plan to
add this in that another compler than use this in exe shape of my new interpreter.
And maybe i am not quite clear,when i say Creative and source code,CB have little bit different way
of double buffered window than IWB because is interpreted and is everything created automatically.
However thanks on respond... ;)
I don't use CB and don't know anything about its internals.
hm..
then maybe i ask on wrong place ,i think that you maybe have CB src.
Do i can ask on CB board ???
Quote from: aurelCB on June 09, 2013, 12:02:35 AM
hm..
then maybe i ask on wrong place ,i think that you maybe have CB src.
Do i can ask on CB board ???
Sure