Using WX-C In FreeBasic - Part 2

Written by dumbledore

if you are skimming at the moment, here's a quick summary of this article: OMG YOU CAN PRINT IN FREEBASIC !!! (with colors and usb printers, oh my.)

INTRODUCTION

for the second installment of wx-c tutorials, i've decided (by popular request) to explain how to use wx-c to interface with the printer. since fb has no direct way to print things, this can be a good solution if you're looking for a way to print things out. be aware that this method is not a replacement for qb's lprint, but is far more flexible.

1.   INITIALIZING

this time i'm going to throw some code at you, assuming you have a basic understanding of how wx-c works (if not, refer back to my first tut)

'$include: "wx-c/wx.bi" #define wxCLOSE_BOX &h1000 #define FALSE 0 #ifndef TRUE # define TRUE NOT(FALSE) #endif option escape option explicit

next, we'll have to use a (possibly) scary number of functions ;)

declare sub App_OnInit( ) declare sub App_OnExit( ) declare sub button0_event( byval event as wxEvent ptr, byval iListener as long ) declare function onBeginDocument( byval as integer, byval as integer ) as integer declare sub onEndDocument( ) declare sub onBeginPrinting( ) declare sub onEndPrinting( ) declare sub onPreparePrinting( ) declare function hasPage( byval as integer ) as integer declare function onPrintPage( byval as integer ) as integer declare sub getPageInfo( byval as integer ptr, byval as integer ptr, _ byval as integer ptr, byval as integer ptr )

if you're staring at that and going "omgwtfbbq, where the heck did he get all those parameters from!?", the answer is actually pretty simple: i borrowed them from the wx-c headers. doing this is (contrary to popular belief :P) a good habit, since there are no official docs on using wx-c.

'(taken from inc/wx-c/printer.bi) type Virtual_NoParams as sub ( ) type Virtual_ParamsInt as function (byval as integer) as integer type Virtual_OnBeginDocument as function (byval as integer, byval as integer) as integer type Virtual_GetPageInfo as sub (byval as integer ptr, byval as integer ptr, byval as integer ptr, byval as integer ptr)

we will need functions declared like this to use in the registervirtual() function of the printer, or else the whole program will crash (!).

now we need to declare our globals:

dim shared wx_app as wxapp ptr,wx_frame as wxframe ptr, myprintout as any ptr

2.   CREATING THE FRAME

this should look terribly familiar, if you've read the first tut, so i'm not going to comment on this particular block of code.

sub App_OnInit( ) wx_frame = wxFrame( ) wxFrame_Create( wx_frame, 0, -1, "My WX-C Project", wxSize( 440, 312 ), _ wxSize( 378, 384 ), wxDEFAULT_FRAME_STYLE or wxCLOSE_BOX xor _ wxMAXIMIZE_BOX xor wxRESIZE_BORDER, _ "frame" ) wxWindow_SetBackgroundColour( wx_frame, wxSystemSettings_GetColour( 15 ) ) '' '' create widget button0 '' dim as wxButton ptr button0 button0 = wxButton( ) wxButton_Create( button0, wx_frame, -1, "button0", wxSize( 0, 0 ), _ wxSize( 370, 350 ), 0, 0, 0 )

this next part is something new i'm introducing you to rather quickly: events. the basic idea is that when the event you specify occurs, the widget's assigned "handler function" aka "callback function" is called to handle the event. in this case, we're telling wx-c that when we click the button, we want the function "button0_event" to be executed. (visual wx-c developer does that for you ;), but you need the latest cvs version :*( )

wxEvtHandler_Proxy( button0, @button0_event ) wxEvtHandler_Connect( button0, wxEvent_EVT_COMMAND_BUTTON_CLICKED( ), -1, -1, 0 )

and, some more repeat stuff from last time.

wxWindow_SetAutoLayout( wx_frame, TRUE ) wxWindow_Show( wx_frame, 1 ) end sub sub App_OnExit( ) wxapp_onexit( wx_app ) end sub

there, that should do it for the frame. now time for the printing! :-O

3.   THE PRINTING!

ok, here's the function for the button event (don't start running in circles screaming, i'll explain afterwards :P)

sub button0_event( byval event as wxEvent ptr, byval iListener as long ) select case wxEvent_GetEventType( event ) case wxEvent_EVT_COMMAND_BUTTON_CLICKED ''stuff myprintout = wxPrintout( "some title or other ;P" ) wxPrintout_RegisterVirtual( myprintout, _ @onBeginDocument, _ @onEndDocument, _ @onBeginPrinting, _ @onEndPrinting, _ @onPreparePrinting, _ @hasPage, _ @onPrintPage, _ @getPageInfo ) dim as wxPrinter ptr myprinter myprinter = wxPrinter( 0 ) wxPrinter_Print( myprinter, wx_frame, myprintout, TRUE ) end select end sub

the proto is pretty straightforward, wx-c will automatically pass both a wxEvent pointer and an ilistener to any event-handler function, which can come in very handy when handling > 1 function. the select case stuff really isn't necessary in this example since we only have one event being handled, but vwx-cdev puts it there by default, and i'm not one to argue with myself ;). we want to declare myprintout as a wxPrintout pointer because that's what wx-c takes for printing ;P the title specified there will appear in a little "printing" window wx-c automatically pops up when your document is being sent to the printer. the registervirtual command is wx-c's sick and cruel way of making us do more work than we should have to ;) since most of the functions already exist, but with different numbers of parameters, so we have to manually override all of them in order to stop the program from crashing all over the place :*(. the next three lines of code initialize the printer with the default vars (hence the null), and tell it to print out our document. the wx_frame part tells it to make the print dialog a child of our main frame (aka wx_frame ;) ), and the TRUE tells it to make a dialog asking for the printer and number of copies, etc. specifying false only works if you send it the data in the constructor instead of null i think, basically that means don't change the true to false unless you want crashes ;P

the next bit of code is basically just placeholder callbacks, because wx-c is too dumb to assign automatic functions, which is kind of annoying :*(

function onBeginDocument( byval a as integer, byval b as integer ) as integer function = wxPrintout_OnBeginDocument( myprintout, a, b ) end function sub onEndDocument( ) wxPrintout_OnEndDocument( myprintout ) end sub sub onBeginPrinting( ) wxPrintout_OnBeginPrinting( myprintout ) end sub sub onEndPrinting( ) wxPrintout_OnEndPrinting( myprintout ) end sub sub onPreparePrinting( ) wxPrintout_OnPreparePrinting( myprintout ) end sub function hasPage( byval a as integer ) as integer function = wxPrintout_HasPage( myprintout, a ) end function sub getPageInfo( byval a as integer ptr, byval b as integer ptr, _ byval c as integer ptr, byval d as integer ptr ) wxPrintout_GetPageInfo( myprintout, a, b, c, d ) end sub

(yes, it is an annoyingly large amount of code, but in the future if you want to override wx-c's default values and uses of these functions, this way you'll get flexibility.)

now, finally, (drumroll please :P), the "only" sub, er, function that we actually care about...

function onPrintPage( byval a as integer ) as integer dim as wxDC ptr printoutdc printoutdc = wxPrintout_GetDC( myprintout ) wxDC_SetTextForeground( printoutdc, wxColour_ctorByParts( 0, 0, 255 ) ) wxDC_DrawText( printoutdc, "printing test", 5, 5 ) return -1 end function

coincidentally, there is no corresponding wx-c default callback for this function, so i've decided we'll just have to return true on success ;). yes, all that work and this is really the only part that does anything :P.

the first step to drawing stuff to the print page is getting the actual page. we accomplish this by getting the printout's dc, which is special and different from normal dcs because its default colors are optimized for, gasp, printing! :-O. To show off our super color capabilities, we change the text color to blue, how often did you see lprint generate blue text? :P and then we draw the text to the page. you can use any dc function on the print page. a complete list of supported dc functions is in the dc header file at inc/wx-c/dc.bi. most of the functions speak for themselves. yes, the drawbitmap function does allow you to print pictures. no, you cannot have my children. :P

4.   FINISHING UP

the rest of the code you should already know from the first tut.

wx_app = wxApp( ) wxApp_RegisterVirtual ( wx_app, @App_OnInit, @App_OnExit) wxApp_Run(0,0) end

and that's all there is to it.

CONCLUSION

so as you have seen, wx-c can handle far more printing flexibility than old man qbasic. with the example code i provided in this tut, we accomplished colored text printing on any generic printer, it worked flawlessly on my usb printer. this means printing may again see its rise in usefulness, since we are no longer limited to the parallel port. as a parting gift though, i'll provide a function that should help convert those old lprint programs from qb.

function onPrintPage( byval a as integer ) as integer dim as wxDC ptr printoutdc printoutdc = wxPrintout_GetDC( myprintout ) dim as string mystr for y = 0 to ( len( offscr ) + 1 ) / 80 - 1 wxDC_DrawText( printoutdc, mid$( offscr, y * 80, 80 ), 0, y * 100 ) next return -1 end function

is the basic function, replace the one in the example with that. you'll want a global string called "offscr" which contains the current contents of the screen, what you want to do is do a cls, the change all your lprints to prints, then run this before calling the print function:

offscr = "" dim as integer x, y for y = 0 to csrlin - 1 for x = 0 to 79 offscr += CHR$( iif( screen( y + 1, x + 1 ) = 0, 32, screen( y + 1, x + 1 ) ) ) next next cls

the last thing you'll want to do is take your main code and stick it inside the app_oninit() function from the example (get rid of the frame and that ugly button though) and be sure to issue an "end" command before app_oninit completes. it may be hackish, but i converted a ~1000 line qb prog heavily using lprint to fb this way with few problems. (meaning it can be done!) ask on the fb forums if you experience severe problems or if you can't seem to figure any of this out :P. until next time,

-dumbledore

CODE LISTING

'$include: "wx-c/wx.bi" #define wxCLOSE_BOX &h1000 #define FALSE 0 #ifndef TRUE # define TRUE NOT(FALSE) #endif option escape option explicit declare sub App_OnInit( ) declare sub App_OnExit( ) declare sub button0_event( byval event as wxEvent ptr, byval iListener as long ) declare function onBeginDocument( byval as integer, byval as integer ) as integer declare sub onEndDocument( ) declare sub onBeginPrinting( ) declare sub onEndPrinting( ) declare sub onPreparePrinting( ) declare function hasPage( byval as integer ) as integer declare function onPrintPage( byval as integer ) as integer declare sub getPageInfo( byval as integer ptr, byval as integer ptr, _ byval as integer ptr, byval as integer ptr ) dim shared wx_app as wxapp ptr,wx_frame as wxframe ptr, myprintout as any ptr sub App_OnInit( ) wx_frame = wxFrame( ) wxFrame_Create( wx_frame, 0, -1, "My WX-C Project", wxSize( 440, 312 ), _ wxSize( 378, 384 ), wxDEFAULT_FRAME_STYLE or wxCLOSE_BOX xor _ wxMAXIMIZE_BOX xor wxRESIZE_BORDER, _ "frame" ) wxWindow_SetBackgroundColour( wx_frame, wxSystemSettings_GetColour( 15 ) ) '' '' create widget button0 '' dim as wxButton ptr button0 button0 = wxButton( ) wxButton_Create( button0, wx_frame, -1, "button0", wxSize( 0, 0 ), _ wxSize( 370, 350 ), 0, 0, 0 ) wxEvtHandler_Proxy( button0, @button0_event ) wxEvtHandler_Connect( button0, wxEvent_EVT_COMMAND_BUTTON_CLICKED( ), -1, -1, 0 ) wxWindow_SetAutoLayout( wx_frame, TRUE ) wxWindow_Show( wx_frame, 1 ) end sub sub App_OnExit( ) wxapp_onexit( wx_app ) end sub sub button0_event( byval event as wxEvent ptr, byval iListener as long ) select case wxEvent_GetEventType( event ) case wxEvent_EVT_COMMAND_BUTTON_CLICKED ''stuff myprintout = wxPrintout( "some title or other ;P" ) wxPrintout_RegisterVirtual( myprintout, _ @onBeginDocument, _ @onEndDocument, _ @onBeginPrinting, _ @onEndPrinting, _ @onPreparePrinting, _ @hasPage, _ @onPrintPage, _ @getPageInfo ) dim as wxPrinter ptr myprinter myprinter = wxPrinter( 0 ) wxPrinter_Print( myprinter, wx_frame, myprintout, TRUE ) end select end sub function onBeginDocument( byval a as integer, byval b as integer ) as integer function = wxPrintout_OnBeginDocument( myprintout, a, b ) end function sub onEndDocument( ) wxPrintout_OnEndDocument( myprintout ) end sub sub onBeginPrinting( ) wxPrintout_OnBeginPrinting( myprintout ) end sub sub onEndPrinting( ) wxPrintout_OnEndPrinting( myprintout ) end sub sub onPreparePrinting( ) wxPrintout_OnPreparePrinting( myprintout ) end sub function hasPage( byval a as integer ) as integer function = wxPrintout_HasPage( myprintout, a ) end function function onPrintPage( byval a as integer ) as integer dim as wxDC ptr printoutdc printoutdc = wxPrintout_GetDC( myprintout ) wxDC_SetTextForeground( printoutdc, wxColour_ctorByParts( 0, 0, 255 ) ) wxDC_DrawText( printoutdc, "printing test", 5, 5 ) return -1 end function sub getPageInfo( byval a as integer ptr, byval b as integer ptr, _ byval c as integer ptr, byval d as integer ptr ) wxPrintout_GetPageInfo( myprintout, a, b, c, d ) end sub wx_app = wxApp( ) wxApp_RegisterVirtual ( wx_app, @App_OnInit, @App_OnExit) wxApp_Run(0,0) end