I have extended my PRINTERS class to include a DIALOG to select a printer. I decided to include an option in the dialog to refresh the list of available printers. However if I try to use that option I get an error. The error appears to be that one (at least) of the controls on my dialog doesn't have a logical value in its update property. At least that's my guess from looking at error.log.
I have reproduced the fault with the following cut down code:
Code: Select all | Expand
#include "hbclass.ch"#include "FiveLinux.ch"STATIC oWndFUNCTION Main( xHomeDir, xDataDir)PUBLIC oPRINTERSoPRINTERS := PRINTERS():New()DEFINE WINDOW oWnd TITLE ( "Test Dialog Update" ) MENU BldInMenu()ACTIVATE WINDOW oWnd MAXIMIZEDRETURN nilFUNCTION BldInMenu()LOCAL lomMenuMENU lomMenu MENUITEM "_File" MENU MENUITEM "_Get Printers" ACTION TestPrinters() MENUITEM "e_Xit" ACTION oWnd:End() ENDMENUENDMENURETURN lomMenuFUNCTION TestPrinters()LOCAL sPrinterLOCAL sPortIF oPRINTERS:Select( "Test Document", @sPrinter, @sPort ) MsgInfo( "Print on " + sPrinter + " on port " + sPort ) ELSE MsgInfo( "Printing cancelled" )ENDIFRETURN nilCLASS PRINTERSDATA aNames /** array of printer names */DATA aPorts /** array of printer ports */DATA iCount /** number of printers installed */DATA sDefault /** name of default printer */DATA iDefault /** number of default printer - index into aNames and aPorts */DATA lDefault /** is there a default printer */DATA lExists /** is any printer defined */DATA lOSQueried /** has the OS been queried about available printers */DATA brw_PRINTER_LIST /** Printer List BROWSE object on Printer Selection DIALOG */DATA btn_PRINT /** Print button on Printer Selection DIALOG */METHOD New( lGetList ) CONSTRUCTORMETHOD GetList()METHOD Select( psJobName, psPrinter, psPort )ENDCLASSMETHOD New( plGetList ) CLASS PRINTERS/** _syntax: PRINTERS():New( [<lGetList>] ) _arguments: <lGetList> a logical value If .T. the operating system is queried and printer lists and defaults are set as part of the object's initialisation. Defaults to .T. _returns: the created PRINTERS object _description: see METHOD GetList() for a description of how the operating system is queried */IF PCOUNT() < 1 lGetList := .T. ELSE lGetList := plGetListENDIF::lOSQueried := .F.IF lGetList ::GetList()ENDIFRETURN selfMETHOD GetList() CLASS PRINTERS/** _syntax: <PRINTERS_object>:GetList() _arguments: none _returns: nil _description: Obtains information on installed printers from the operating system by RUNning lpstat -s > lpstat.txt. Opens the redirected output of the above command and parses that file building a list of printernames (in ::aNames) and ports (in ::aPorts). Retrieves the name of the default printer (in ::sDefault) and determines its position (in ::iDefault) If there is no default printer ::lDefault is set to .F. Determines if there are any printers installed (in ::lExists) and how many are installed (in ::iCount) */LOCAL iFileHandle /** file handle for reading output of lpstat command */LOCAL sPrinterLine /** line buffer for reading output of lpstat command */LOCAL sTest /** buffer for testing format of lines of lpstat command output */LOCAL iEndOffset /** work variable for splitting out printer name and port data */LOCAL lDefaultFound /** work variable for flagging that default printer name has been found */LOCAL ii /** work variable loop counter */::aNames := ARRAY( 0 )::aPorts := ARRAY( 0 )::iCount := 0::sDefault := ""::iDefault := 0::lDefault := .F.::lExists := .F.RUN lpstat -s > lpstat.txtiFileHandle := FOpen( "lpstat.txt" )DO WHILE HB_FReadLine( iFileHandle, @sPrinterLine, CHR(10) ) = 0 sTest := SUBSTR( sPrinterLine, 1, 11 ) IF sTest = "device for " sTest := SUBSTR( sPrinterLine, 12 ) iEndOffset := AT( ": ", sTest ) IF iEndOffset > 0 AAdd( ::aNames, ALLTRIM( SUBSTR( sTest, 1, iEndOffset - 1 ) ) ) AAdd( ::aPorts, SUBSTR( sTest, iEndOffset + 2 ) ) ::iCount += 1 ::lExists := .T. ENDIF ELSE sTest := SUBSTR( sPrinterLine, 1, 27 ) IF sTest = "system default destination:" ::sDefault := ALLTRIM( SUBSTR( sPrinterLine, 28 ) ) ::lDefault := .T. ENDIF ENDIFENDDOFClose( iFileHandle )IF ::lDefault FOR ii = 1 TO ::iCount IF ::aNames[ii] = ::sDefault ::iDefault := ii EXIT ENDIF NEXTENDIF::lOSQueried := .T.RETURN nilMETHOD Select( psJobName, psPrinter, psPort )/** _syntax: <PRINTERS_object>:Select( <JobName>, @<Printer, @<Port> ) _parameters: <JobName> a string Name of the job(s) to be printed. Gets displayed in the title of the dialog <Printer> a string (passed by reference) This gets updated with the name of the selected printer <Port> a string (passed by reference) This gets updated with the port of the selected printer _returns: a logical value. .T. indicates that the user has selected a printer and wishes to proceed .F. indicates that the user wishes to cancel _description: a dialog enabling the user to select a printer for (a) print job(s) or to cancel the print request A printer can be selected by either: double left clicking on it, or highlighting it and clicking on the print button The function gives an informational message if no printers are installed. The function checks that a printer list has been created, if not it invokes ::GetList() The user can get the printer list refreshed by clicking on the Refresh button */LOCAL dlg_SELECT_PRINTER /** Select Printer Dialog */LOCAL sTitle /** Dialog Title */ LOCAL lRetCode /** Function Return Code */IF !::lOSQueried ::GetList()ENDIFsTitle := "Select Printer for Printing " + psJobName DEFINE DIALOG dlg_SELECT_PRINTER TITLE sTitle SIZE 800, 500IF ::iCount < 1 @ 30, 10 SAY "No printers currently installed" ELSE @ 3, 1 BROWSE ::brw_PRINTER_LIST ; FIELDS ::aNames[::brw_PRINTER_LIST:nAt], ::aPorts[::brw_PRINTER_LIST:nAt] ; HEADERS "Printer", "Port" SIZE 550, 400 OF dlg_SELECT_PRINTER UPDATE ::brw_PRINTER_LIST:bLDblClick := { | nRow, nCol | ::btn_PRINT:Click() } BrwSetColWidths( ::brw_PRINTER_LIST , { 200, 350 } ) ::brw_PRINTER_LIST:SetArray( ::aNames )ENDIF@ 30, 600 BUTTON ::btn_PRINT PROMPT "Print" WHEN ::lExists ; ACTION ( psPrinter := ::aNames[::brw_PRINTER_LIST:nAt], psPort := ::aPorts[::brw_PRINTER_LIST:nAt], lRetCode := .T., dlg_SELECT_PRINTER:End() ) ; PIXEL OF dlg_SELECT_PRINTER@ 90, 600 BUTTON "Refresh" ACTION ( ::GetList(), dlg_SELECT_PRINTER:Update() ) PIXEL OF dlg_SELECT_PRINTER@ 240, 600 BUTTON "Cancel" ACTION ( lRetCode := .F., dlg_SELECT_PRINTER:End() ) PIXEL OF dlg_SELECT_PRINTERACTIVATE DIALOG dlg_SELECT_PRINTER CENTEREDRETURN lRetCodeFUNCTION BrwSetColWidths( oBrw, aWidths )iLastWidth := LEN( aWidths )FOR iCount = 1 TO iLastWidth oBrw:aColumns[iCount]:nWidth := aWidths[iCount]NEXTRETURN nil
Herewith the error.log:
Code: Select all | Expand
Application=========== Path and name: ./PRINTERS (32 bits) Time from start: 0 hours 0 mins 16 secs Error occurred at: 06/15/08, 21:06:19 Error description: Error BASE/1066 Argument error: conditional Args: [ 1] = U nilStack Calls=========== Called from (b)TWINDOW(79) Called from AEVAL(0) Called from (b)TWINDOW:TWINDOW(79) Called from TDIALOG:UPDATE(0) Called from (b)PRINTERS:SELECT(186) Called from TBUTTON:CLICK(149) Called from TBUTTON:HANDLEEVENT(158) Called from _FLH(241) Called from WINRUN(0) Called from TDIALOG:ACTIVATE(71) Called from PRINTERS:SELECT(188) Called from TESTPRINTERS(34) Called from (b)BLDINMENU(22) Called from TMENU:COMMAND(60) Called from TWINDOW:HANDLEEVENT(182) Called from _FLH(241) Called from WINRUN(0) Called from TWINDOW:ACTIVATE(134) Called from MAIN(11)Variables in use================ Procedure Type Value ========================== (b)TWINDOW Param 1: O Class: TSCROLLBAR Param 2: N 2 Local 1: U nil Local 2: U nil Local 3: N 0 AEVAL Param 1: A Len: 6 Param 2: B {|| ... } (b)TWINDOW:TWINDOW Param 1: O Class: TDIALOG TDIALOG:UPDATE (b)PRINTERS:SELECT Param 1: O Class: TBUTTON TBUTTON:CLICK Local 1: O Class: TBUTTON TBUTTON:HANDLEEVENT Param 1: N 1 Param 2: N 0 Param 3: N 0 Local 1: O Class: TBUTTON _FLH Param 1: N 1 Param 2: N 0 Param 3: N 0 Param 4: N 21 Local 1: O Class: TBUTTON WINRUN Local 1: U nil Local 2: U nil Local 3: U nil Local 4: U nil TDIALOG:ACTIVATE Param 1: L .T. Param 2: U nil Param 3: U nil Param 4: U nil Param 5: L .T. Param 6: U nil Local 1: O Class: TDIALOG Local 2: N 7 PRINTERS:SELECT Param 1: C "Test Document" Param 2: U nil Param 3: U nil Local 1: O Class: PRINTERS Local 2: O Class: TDIALOG Local 3: C "Select Printer for Printing Test Document" Local 4: U nil TESTPRINTERS Local 1: U nil Local 2: U nil (b)BLDINMENU Param 1: O Class: TMENUITEM TMENU:COMMAND Param 1: N 135782784 Local 1: O Class: TMENU Local 2: O Class: TMENUITEM TWINDOW:HANDLEEVENT Param 1: N 3 Param 2: N 135782784 Param 3: N 0 Local 1: O Class: TWINDOW Local 2: U nil _FLH Param 1: N 3 Param 2: N 135782784 Param 3: N 0 Param 4: N 1 Local 1: O Class: TWINDOW WINRUN Local 1: U nil Local 2: U nil Local 3: U nil Local 4: U nil Local 5: U nil Local 6: U nil Local 7: U nil TWINDOW:ACTIVATE Param 1: U nil Param 2: U nil Param 3: U nil Param 4: L .T. Param 5: U nil Local 1: O Class: TWINDOW MAIN Local 1: U nil Local 2: U nilLinked RDDs=========== DBF DBFFPT DBFNTX DBFBLOBDataBases in use================Classes in use:=============== 1 HASHENTRY 2 HBCLASS 3 HBOBJECT 4 PRINTERS 5 TWINDOW 6 TMENU 7 TMENUITEM 8 TDIALOG 9 TCONTROL 10 TWBROWSE 11 TWBCOLUMN 12 TSCROLLBAR 13 TBUTTON 14 ERRORMemory Analysis=============== 24 Static variables Dynamic memory consume: Actual Value: 0 bytes Highest Value: 0 bytes
Your help would be appreciated as the UPDATE option would be very handy for the code I have to write in the near future, even though it could be removed from this particular class with little loss of utility.
Thanks
Doug
(xProgrammer)