Standard Grid Tutorial 2: User-Modifiable Grid

For BBj-specific tutorials, see Grid Tutorial 1- Standard Grid Using SENDMSG() functions and Grid Tutorial 2 - Standard Grid Using BBjGrid Methods.

This tutorial describes how to create a grid that can be edited by users.

  1. Open the SYSGUI device and dimension several variables:

    sysgui=unt
    open (sysgui)"X0"
    dim event$:tmpl(sysgui); event=len(event$)
    dim generic$:noticetpl(0,0)
    dim edit_param$:"initstr:c(1*=0),key:u(2),col:u(2),row:u(4)"
    dim grid_data$[2,2]

    The event$ variable reads the event loop. The generic$ variable contains the template returned by the NOTICETPL() function. (This function is new in Visual PRO/5 Rev. 2 and returns the Notify event template, which is more extensive than the standard event template.) The edit_param$ variable causes the grid to enter edit mode. The grid_data$[] array is used to store the information displayed in the grid. In this example, the data displayed in the grid can be changed, and it is necessary to store the current value of every cell at all times so cells can be redrawn as needed.

  2. Draw the window and a grid of three rows and three columns, then assign a string template to the grid$ variable, which contains the grid information block:

    print (sysgui)'window'(50,50,200,150,"Grid Editing",$00000002$,$$)
    grid=100
    print (sysgui)'grid'(grid,20,20,160,120,$9040$,3,3,3)
    dim grid$:tmpl(sysgui,ind=1)

  3. Set the row height and change the highlight method from changing the highlight color (the default) to outlining the cell:

    result$=sendmsg(sysgui,grid,68,150/4,$$); rem ' row height
    result$=sendmsg(sysgui,grid,57,0,$$); rem ' turn off color change highlighting

  4. Create nested loops to populate the grid_data$[] array with numbers from 0 to 8. Note the grid_data$[] array is loaded at the same time as the grid:

    counter=0
    for col=0 to 2
       result$=sendmsg(sysgui,grid,36,col,chr(51)); rem ' column width
       for row=0 to 2
              grid_data$[col,row]=str(counter)
          counter=counter+1
       next row
    next col

  5. Set up the event loop. The basic structure is the same as in the previous example, but this example will be checking for different events. The code to read the event loop and get a template for the Notify event information is identical:

    while 1   read record(sysgui,len=event)event$   if event.code$="N" :     then
    :        generic$=notice(sysgui,event.x);
    :        dim notice$:noticetpl(generic.objtype,event.flags);
    :        let notice$=generic$

  6. Check for Notify event 22, which indicates that one or more cells in the grid must be redrawn. This event will be sent to the program as soon as the grid displays, so the initial values will be displayed immediately.

    if event.code$="N" and event.flags=22
    :     then
    :        for col=notice.leftcol% to notice.rightcol%;
    :          grid.col=col%;
    :          for row=notice.toprow% to notice.botrow%;
    :             grid.row=row%;
    :             grid.buf$=grid_data$[col,row];
    :             grid.textcolor$=$000000$,grid.backcolor$=ffffff$,grid.alignment%=2;
    :             result$=sendmsg(sysgui,grid,54,0,grid$);
    :          next row;
    :        next col

    There are two user events that are a concern in a program that supports editing in a grid: the user indicating that editing should begin, and the indication that editing should end. In this program, a left-button mouse click on any cell will indicate editing should begin, and clicking on any other cell will indicate editing is complete, and the new value should be stored in the data array. To check for a mouse click, we test for Notify event 14, which is generated when the user clicks on a cell with the left mouse button. We will also check for notice.lparam=0 so that we react to the mouse button being released instead of the button being pushed. When the user indicates editing should begin, SENDMSG() Function 79 is issued to set a mask, and the grid control is put into edit mode with SENDMSG() Function 31. If no mask is specified for a cell, no data can be entered. SENDMSG() Function 31 requires a specially formatted string, which is called edit_param$ in this sample. This string is defined in step one. Here, the string is used to indicate the coordinates of the cell to be edited.

  7. Check for Notify event 14 and notice.lparam=0:

       if event.code$="N" and notice.code=14 and notice.lparam=0
    :     then
    :        result$=sendmsg(sysgui,grid,79,notice.col%,"000");
    :        edit_param.row%=notice.row%,edit_param.col%=notice.col%;
    :        result$=sendmsg(sysgui,grid,31,0,edit_param$)

  8. Check for Notify event 7, which indicates that editing has been completed:

    if event.code$="N" and notice.code=7
    :    then
    :       grid_data$[notice.col%,notice.row%]=sendmsg(sysgui,grid,34,0,$$)

    When Notify event 7 is generated, SENDMSG() Function 34 is used to read the value in the just-edited cell and store it in the data array.

  9. End the program with the code to enable the user to terminate the event loop by clicking the close button, followed by the end of the event loop itself and the end of the program:

       if event.code$="X"
    :     then
    :        break
    wend
    end

    The window created by the code so far looks like this:

    gridedit.png

The complete program is listed below:

0001 REM ' Grid Editing
0010 LET SYSGUI=UNT
0020 OPEN (SYSGUI)"X0"
0030 DIM EVENT$:TMPL(SYSGUI); LET EVENT=LEN(EVENT$)
0040 DIM GENERIC$:NOTICETPL(0,0)
0050 DIM EDIT_PARAM$:"initstr:c(1*=0),key:u(2),col:u(2),row:u(4)"
0060 DIM GRID_DATA$[2,2]
0070 PRINT (SYSGUI)'WINDOW'(50,50,200,150,"Grid Editing",$00000002$,$$)
0080 LET GRID=100
0090 PRINT (SYSGUI)'GRID'(100,20,20,160,120,$9040$,3,3,3)
0100 DIM GRID$:TMPL(SYSGUI,IND=1)
0110 LET RESULT$=SENDMSG(SYSGUI,GRID,68,150/4,$$); REM ' row height
0120 LET RESULT$=SENDMSG(SYSGUI,GRID,57,0,$$); REM ' turn off color change hig
0120:hlighting
0130 LET COUNTER=0
0140 FOR COL=0 TO 2
0150 LET RESULT$=SENDMSG(SYSGUI,GRID,36,COL,CHR(51)); REM ' column width
0160 FOR ROW=0 TO 2
0170 LET GRID_DATA$[COL,ROW]=STR(COUNTER)
0180 LET COUNTER=COUNTER+1
0190 NEXT ROW
0200 NEXT COL
0210 WHILE 1
0220 READ RECORD(SYSGUI,LEN=EVENT)EVENT$
0230 IF EVENT.CODE$="N" THEN LET GENERIC$=NOTICE(SYSGUI,EVENT.X); DIM NOTICE$:
0230:NOTICETPL(GENERIC.OBJTYPE,EVENT.FLAGS); LET NOTICE$=GENERIC$
0240 IF EVENT.CODE$="N" AND EVENT.FLAGS=22 THEN FOR COL=NOTICE.LEFTCOL% TO NOT
0240:ICE.RIGHTCOL%; LET GRID.COL%=COL; FOR ROW=NOTICE.TOPROW% TO NOTICE.BOTROW
0240:%; LET GRID.ROW%=ROW; LET GRID.BUF$=GRID_DATA$[COL,ROW]; LET GRID.TEXTCOL
0240:OR$=$000000$,GRID.BACKCOLOR$=$FFFFFF$,GRID.ALIGNMENT%=2; LET RESULT$=SEND
0240:MSG(SYSGUI,GRID,54,0,GRID$); NEXT ROW; NEXT COL
0250 IF EVENT.CODE$="N" AND NOTICE.CODE=14 AND NOTICE.LPARAM=0 THEN LET RESULT
0250:$=SENDMSG(SYSGUI,GRID,79,NOTICE.COL%,"000"),EDIT_PARAM.ROW%=NOTICE.ROW%,E
0250:DIT_PARAM.COL%=NOTICE.COL%,RESULT$=SENDMSG(SYSGUI,GRID,31,0,EDIT_PARAM$)
0260 IF EVENT.CODE$="N" AND NOTICE.CODE=7 THEN LET GRID_DATA$[NOTICE.COL%,NOTI
0260:CE.ROW%]=SENDMSG(SYSGUI,GRID,34,0,$$)
0270 IF EVENT.CODE$="X" THEN BREAK
0280 WEND
0290 END