Spreadsheet Control

new topic     » topic index » view thread      » older message » newer message

Someone was asking for information on how to create a spreadsheet-type of
control, so here's a small demo. Basically, it creates a hidden control
(drawn off the window) that traps key events. Two real scrollbars are
created; notice that they set the focus back to the hidden grid control
after scrolling. Note that it uses the onMouse and onPaint traps of the
parent window.

I redefined White in Win32Lib as:

   White = rgb( 192, 192, 192 )

since it's incorrectly defined. It should use system colors instead.

There are a lot of features that could be added: double buffering, key
handling, using real system colors, selecting rows/columns, resizing
columns, more navigation keys, center the labels... the list goes on and on.
If people are interested, I could develop it more (unless someone else wants
to take it on).

You can create the grid by calling:

   createGrid( parent, x, y, rows, cols, maxRows, maxCols )

Data is contained in the global sequence:

   gridData


Here's a small demo using the code:

-- BEGIN DEMO --

  include win32lib.ew
  include grid.ew

  constant Win = create( Window, "Grid Demo", 0,
                  Default, Default, 360, 180, 0 )

  -- create the grid
  createGrid( Win, 10, 10, 4, 4, 10, 10 )

  -- fill grid with data
  for y = 1 to 10 do
      for x = 1 to 10 do
          gridData[y][x] = sprintf( "%d, %d", {x,y} )
      end for
  end for

  WinMain( Win, Normal )

-- END DEMO --

Hope this helps!

-- David Cuny




-- BEGIN GRID.EW --
-- emulated spreadsheet-type grid control

include win32lib.ew

constant
    CellCX      = 64,           -- cell width
    CellCY      = 20            -- cell height

integer
    grid,           -- id of grid
    gridOwner,      -- parent of grid
    gridCols,       -- number of displayed columns
    gridRows,       -- number of displayed rows
    gridMaxCols,    -- max number of columns
    gridMaxRows,    -- max number of rows
    gridX,          -- x position of grid
    gridY,          -- y position of grid
    gridCX,         -- width of grid
    gridCY,         -- height of grid
    gridV,          -- grid vertical scroll bar
    gridH,          -- grid horizontal scroll bar
    cellX,          -- current cell x
    cellY           -- current cell y

global sequence
    gridData        -- grid cells

global procedure paintGrid()
    -- draw the grid control
    integer x, y, x1, y1, x2, y2, offsetX, offsetY, thisX, thisY, h, v
    sequence size

    -- size of font
    size = getFontSize( gridOwner )

    -- to center text in cell
    offsetY = floor( (CellCY - size[2])/2 )

    -- cell index
    h = getScrollPos( gridH ) - 1
    v = getScrollPos( gridV ) - 1

    -- cell index
    x = 0
    y = 0

    -- draw each cell
    for posY = 0 to gridCY-1 by CellCY do

        for posX = 0 to gridCX-1 by CellCX do

            x1 = gridX+posX
            y1 = gridY+posY
            x2 = x1 + CellCX - 1
            y2 = y1 + CellCY - 1

            -- draw the cell
            if x = 0 or y = 0 then

                -- background
                setPenColor( gridOwner, White )
                drawRectangle( gridOwner, True, x1, y1, x2+1, y2+1 )
                setPenColor( gridOwner, Gray )
                drawRectangle( gridOwner, False, x1, y1, x2, y2 )

                -- selected col/row?
                if h+x = cellX or v+y = cellY then

                    -- highlight
                    setPenColor( gridOwner, BrightWhite )
                    drawLine( gridOwner, x1, y1, x2, y1 )
                    drawLine( gridOwner, x1, y1, x1, y2 )

                    -- shadow
                    setPenColor( gridOwner, Black )
                    drawLine( gridOwner, x2, y1, x2, y2 )
                    drawLine( gridOwner, x1, y2, x2, y2 )

                    setPenColor( gridOwner, Gray )
                    drawLine( gridOwner, x2-1, y1+1, x2-1, y2-1 )
                    drawLine( gridOwner, x1+1, y2-1, x2-1, y2-1 )


                end if

            else
                -- cell
                setPenColor( gridOwner, BrightWhite )
                drawRectangle( gridOwner, True, x1, y1, x2, y2 )
                setPenColor( gridOwner, Gray )
                drawLine( gridOwner, x2, y1, x2, y2 )
                drawLine( gridOwner, x1, y2, x2, y2 )

                -- selected?
                if x+h = cellX and y+v = cellY then
                    setPenColor( gridOwner, Black )
                    for i = 0 to 1 do
                        drawRectangle( gridOwner, False, x1+i, y1+i, x2-i,
y2-i )
                    end for

                end if

            end if

            -- text in the cell
            if x = 0 and y = 0  then
                -- no text

            elsif x = 0 then
                setPosition( gridOwner, x1+4, y1+offsetY )
                wPrintf( gridOwner, "%d", {y+v} )

            elsif y = 0 then
                setPosition( gridOwner, x1+4, y1+offsetY )
                wPrintf( gridOwner, "%s", "A"+x+h-1 )

            else
                setPosition( gridOwner, x1+4, y1+offsetY )
                wPrintf( gridOwner, "%d,%d", {x+h,y+v} )
            end if


            -- increment cell index
            x += 1

        end for

        -- increment cell index
        x = 0
        y += 1

    end for

end procedure

procedure paint( integer x1, integer y1, integer x2, integer y2 )
    paintGrid()
end procedure

procedure mouse( integer event, integer x, integer y, integer shift )

    if event = LeftDown then
        -- in the grid?
        if x >= gridX and y >= gridY
        and x < gridX+gridCX and y < gridY+gridCY then

            -- which cell?
            x = floor( (x-gridX)/CellCX )
            y = floor( (y-gridY)/CellCY )

            if x != 0 and y != 0 then
                -- cell index
                cellX = getScrollPos( gridH ) + x - 1
                cellY = getScrollPos( gridV ) + y - 1

            end if

            -- update the grid
            paint( 0, 0, 0, 0 )

            -- focus on hidden control
            setFocus( grid )

        end if

    end if

end procedure

procedure keydown( integer keycode, integer shift )

    -- key handler for scrollbar

    integer h, v

    if keycode = VK_HOME then
        cellX = 1
        cellY = 1
        setScrollPos( gridH, 1 )
        setScrollPos( gridV, 1 )

    elsif keycode = VK_LEFT then

        if cellX > 1 then

            -- move cell
            cellX -= 1

            -- need to scroll?
            h = getScrollPos( gridH )
            if h > cellX then
                -- scroll
                setScrollPos( gridH, cellX )
            else
                -- just paint
                paintGrid()
            end if
        end if

    elsif keycode = VK_RIGHT then

        -- check range
        if cellX < gridMaxCols then

            -- move cell
            cellX += 1

            -- need to scroll?
            h = getScrollPos( gridH )
            if h + gridCols - 1 < cellX then
                -- scroll
                setScrollPos( gridH, h+1 )
            else
                -- just paint
                paintGrid()
            end if

        end if

    elsif keycode = VK_UP then
        if cellY > 1 then

            -- move
            cellY -= 1

            -- need to scroll?
            if getScrollPos( gridV ) > cellY then
                setScrollPos( gridV, cellY )
            else
                paintGrid()
            end if
        end if

    elsif keycode = VK_DOWN then

        -- check range
        if cellY < gridMaxRows then

            -- move cell
            cellY += 1

            -- need to scroll?
            v = getScrollPos( gridV )
            if v + gridRows - 1 < cellY then
                -- scroll
                setScrollPos( gridV, v+1 )
            else
                -- just paint
                paintGrid()
            end if

        end if


    end if

    -- don't give to the mle
    returnValue( True )

end procedure

procedure scrollbar( integer pos )
    -- update the grid
    paint( 0, 0, 0, 0 )

    -- focus on hidden control
    setFocus( grid )

end procedure

global procedure createGrid( integer owner, integer x, integer y,
                        integer rows, integer cols,
                        integer maxRows, integer maxCols )

    -- save values
    gridOwner   = owner
    gridX       = x
    gridY       = y
    gridCols    = rows
    gridRows    = cols
    gridMaxCols = maxRows
    gridMaxRows = maxCols
    gridCX      = (gridCols+1) * CellCX
    gridCY      = (gridRows+1) * CellCY

    -- allocate space for data
    gridData = repeat( repeat( "", gridMaxCols ), gridMaxRows )

    -- create controls
    grid  = create( MleText, "", gridOwner, -10, -10, 5, 5, 0 )
    gridV = create( VScroll, "", gridOwner, gridX+gridCX, gridY, 16, gridCY,
0 )
    gridH = create( HScroll, "", gridOwner, gridX, gridY+gridCY, gridCX, 16,
0 )

    -- scroll range
    setScrollRange( gridV, 1, (gridMaxRows - gridRows) + 1 )
    setScrollRange( gridH, 1, (gridMaxCols - gridCols) + 1 )

    -- selected cell
    cellX = 1
    cellY = 1

    -- set up callbacks
    onPaint[gridOwner]  = routine_id("paint")
    onMouse[gridOwner]  = routine_id("mouse")
    onKeyDown[grid]     = routine_id("keydown")
    onScroll[gridH]     = routine_id("scrollbar")
    onScroll[gridV]     = routine_id("scrollbar")

    -- draw the control
    paintGrid()

end procedure


-- END GRID.EW --

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu