1. Spreadsheet Control

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 message » categorize

2. Re: Spreadsheet Control

Urgh. There were a few bugs in the code, such as not actually using gridData
to display the code.

I also added system colors and double-buffering, so the display should be
smoother.

-- David Cuny

-- grid.exw
-- emulated spreadsheet-type grid control

include win32lib.ew

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

integer
    grid,           -- id of grid
    gridPix,        -- image 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

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

    -- size of font
    size = getFontSize( gridOwner )

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

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

    -- current cell
    x = 0
    y = 0

    -- background
    setPenColor( gridPix, getSysColor( COLOR_BTNFACE ) )
    drawRectangle( gridPix, True, 1, 1, gridCX, gridCY )


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

        for x1 = 0 to gridCX-1 by CellCX do

            x2 = x1 + CellCX - 1
            y2 = y1 + CellCY - 1

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

                -- background
                setPenColor( gridPix, getSysColor( COLOR_BTNFACE ) )
                drawRectangle( gridPix, True, x1, y1, x2+1, y2+1 )
                setPenColor( gridPix, getSysColor( COLOR_GRAYTEXT ) )
                drawRectangle( gridPix, False, x1, y1, x2, y2 )

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

                    -- highlight
                    setPenColor( gridPix, getSysColor( COLOR_BTNHIGHLIGHT )
)
                    drawLine( gridPix, x1, y1, x2, y1 )
                    drawLine( gridPix, x1, y1, x1, y2 )

                    -- shadow
                    setPenColor( gridPix, getSysColor( COLOR_3DDKSHADOW ) )
                    drawLine( gridPix, x2, y1, x2, y2 )
                    drawLine( gridPix, x1, y2, x2, y2 )

                    setPenColor( gridPix, getSysColor( COLOR_BTNSHADOW ) )
                    drawLine( gridPix, x2-1, y1+1, x2-1, y2-1 )
                    drawLine( gridPix, x1+1, y2-1, x2-1, y2-1 )


                end if

            else
                -- cell
                setPenColor( gridPix, getSysColor( COLOR_WINDOW ) )
                drawRectangle( gridPix, True, x1, y1, x2, y2 )
                setPenColor( gridPix, COLOR_GRAYTEXT )
                drawLine( gridPix, x2, y1, x2, y2 )
                drawLine( gridPix, x1, y2, x2, y2 )

                -- selected?
                if x+h = cellX and y+v = cellY then
                    setPenColor( gridPix, getSysColor( COLOR_BTNTEXT ) )
                    for i = 0 to 1 do
                        drawRectangle( gridPix, 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( gridPix, x1+4, y1+offsetY )
                wPrintf( gridPix, "%d", {y+v} )

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

            else
                setPosition( gridPix, x1+4, y1+offsetY )
                wPuts( gridPix, gridData[x+h][y+v] )
            end if


            -- increment cell index
            x += 1

        end for

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

    end for

    -- copy the pixmap
    copyBlt( gridOwner, gridX, gridY, gridPix )

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

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 )
    gridPix = create( Pixmap, "", 0, 0, 0, gridCX, gridCY, 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


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

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

function pick( sequence s )
    return s[ rand( length(s) ) ]
end function

-- fill it with data
for y = 1 to 10 do
    for x = 1 to 10 do
        for i = 1 to 4 + rand(10) do
            gridData[y][x] &= pick("qwertyuiopasdfghjklzxcvbnm")
        end for
    end for
end for

WinMain( Win, Normal )

new topic     » goto parent     » topic index » view message » categorize

3. Re: Spreadsheet Control

The line:

        wPuts( gridPix, gridData[x+h][y+v] )

should be:

        wPuts( gridPix, gridData[y+v][x+h] )

-- David Cuny

new topic     » goto parent     » topic index » view message » categorize

4. Re: Spreadsheet Control

David,

I was asking for it. thanks very much for the code. Hope we will be able to
see it in your future version of WIN32LIB (am I asking too much!).

Regards,
Prasanta.

new topic     » goto parent     » topic index » view message » categorize

5. Re: Spreadsheet Control

>From: "Cuny, David at DSS" <David.Cuny at DSS.CA.GOV>
>
>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).
>
I'm interested!  I don't have the know-how to take it over, but I've wished
several times that there was such a thing.

Thanks,

Ben
______________________________________________________
Get Your Private, Free Email at http://www.hotmail.com

new topic     » goto parent     » topic index » view message » categorize

6. Re: Spreadsheet Control

Ben Logan replied:

>> If people are interested, I could develop it more
>>(unless someone else wants to take it on).

> I'm interested!  I don't have the know-how to take
> it over, but I've wished several times that there
> was such a thing.

Take a look at the code, and let me know if you are still interested, and
what sorts of questions you have about it.

-- David Cuny

new topic     » goto parent     » topic index » view message » categorize

7. Re: Spreadsheet Control

David,

I forgot to mention in my earlier post that I am very much interested
regarding the additional features you mentioned. In fact I have started
modifying the code you have given to add cutomized headers (instead of
A..Z) and also auto adjustment of the cells. I am not sure if I am doing it
the right way, but I will release the code as soon as I have made the
changes. If you have any ideas, can you please convey them to me (you can
send me personal mails also).
Thanks again for the code.

Regards,
Prasanta.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu