StringGrids and Bitmaps

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]




Search WWW


As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.


Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 


We receive a few cents from each purchase.  Thanks


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa 365 Puzzlers  Calendar 2017

Mensa 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)


Feedback:  Send an e-mail with your comments about this program (or anything else).

Search only





This program was motivated by an email exchange with a hobbyist programmer involving two programs that were giving him trouble. I'm not sure of George's age, but in one of his replies he said "You have made a Great Granddad very happy", so he must be of the up there with me as part of the "old fogey" generation.  We need all the help we can get!

The first problem has two parts. For one, he wanted the cells of a StringGrid to change as the mouse cursor passed over them. Initially the objective was to highlight the cell by coloring the background. This is implemented as "StringGrid Demo 1". The secondary objective was to change the text in the cell when the mouse cursor was present and restore the original text when the mouse leaves. This is "StringGrid Demo 2".

The second problem, was actually George's first request, how to successfully transfer an image, or portion of an image canvas, to a bitmap for further processing. The problem was that he did not realize that the Width and Height properties of a bitmap must be specified before attempting to transfer to it. I decided to illustrate this, and have a little fun, by transferring cell-sized pieces of a Bitmap image to the StringGrid as the mouse moves over cells. This is "StringGrid Demo 3" with two options: the "Simple" one just "paints" the bitmap to the
StringGrid cell by cell as the cursor moves over it. The "Tricky" option places images on empty cells as the mouse passes over them, but erases any cell touched by the cursor if the image piece is already displayed.  Zigzagging across columns and down the rows makes this almost too easy, so the program randomly paints a few cells initially just to make it a little more interesting.

All the demos use different versions of the same two Event Exits: "OnMouseMove" gets called when the mouse cursor is on the StringGrid and moves. The exit receives the screen coordinates of the cursor but StringGrid objects include a "MouseToCell" method that converts (X, Y) screen coordinates to Column and Row values. The specific action taken varies with the demo, but the key is that any change made to a cell will trigger a call to the "OnDrawCell" event exit where the appropriate action can be taken to change what the user sees.

StringGrid Demo 1: Highlight cell under mouse cursor

Redraws the entire StringGrid on every mouse move.

OnMouseMove exit simply converts screen coordinate to cell coordinates and saves them in global variables that OnDrawCell can check. Since no cell data is changed, MouseMove calls the grid's "Invalidate" method to force all cells to be redrawn. The DrawCell exit is called once for each cell to be redrawn. This exit checks the saved cell coordinates against those of the cell to be redrawn and when they match, the exit colors the background as desired. All other cells get the default (white) background color.

All three StringGrids in this program have their "DefaultDrawing" property set to False when they were defined.. This lets the DrawCell exits completely control Cell appearance. All other properties are at their initial default values.

A better solution would be to have the Mouse move routine save x,y at end of each entry (as previous location) and compare new x,y with previous x,y and "Update" rather than "Invalidate" the StringGrid to redraw only the changed cells. String Demo 2 implements this idea.

StringGrid Demo 2: Change text and redraw only the cells that change as mouse moves

This version also modifies the text (to '!!!!') in the cell currently under the mouse and restores it to the initial value when the mouse leaves the cell.

On entry, MouseMove saves the current cell location in variables NewCol and NewRow. It then checks to see if:

  1. the cursor is on a cell since area covered by the cells maybe less than the
    grid dimensions.
  2. The current cursor location is different from the previous location (saved in SaveCol and SaveRow). Since MouseMove is called for every detected movement, multiple calls may be made as the cursor moves inside the cell.   We want only to process the first entry in this cell.

If 1) and 2) are true, then:

  1. If SaveCol has a valid value (i.e. this is not the first entry), we will restore a previously saved SaveCell value into the cell.   SaveCol is initially set to -1 in a PageControlChange exit indicating to the other methods that there is no previous value to restore.
  2. Move Newcol & NewRow values to SaveCol & SaveRow and save the current cell value in SaveCell so that it can be restored when the Mouse leaves this cell.

Since we are now changing Cell values rather just the background color, we can call the grid's "Update" method which will redraw only changed cells rather than calling "Invalidate" which forces all cells to be withdrawn.

StringGrid Demo 3: Create a bitmap and "paint" image pieces on the grid.

Bitmap manipulation was another problem George had because he did not realize that bitmap Width and Height properties must be set before copying images to them. This grid demo version starts with  a default image or one you load into a TImageBitmap B1 has been resized so that it's size matches the size of the StringGrid. The bitmap of the image is then drawn to the B1 Canvas using the StretchDraw method. 

When the mouse moves over the grid this time, the portion of the B1 relative to that cell is copied to the grid. The "Tricky" paint version primes the grid with a few cell images and then MouseMove toggles images on and off each time the mouse enters the cell. A little experimentation will train you to plug the "holes" left from your first attempts and complete the image.

The "Change image" button allow the user to choose a replacement image for the default image. Note that images will be stretched to fit the square StringGrid dimensions regardless of their original dimensions. Also, note that the program uses the Delphi JPEG component to load ".jpg" files as well as ".bmp" bitmap files.

Browse/Download Source 

bulletDownload source 
bulletDownload executable

Further Explorations

The "Tricky" painting could be converted into a puzzle or game by making the prefilled image section reproducible and then keeping track of the number of cell-to-cell move used to complete the picture. (Fewest moves wins.)  


Created: August 31, 2013

Modified: May 15, 2018

  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2018, Gary Darby    All rights reserved.