Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How do I put a checkbox control in a cell of a Grid?

1,273 views
Skip to first unread message

Suwanto

unread,
Feb 3, 2000, 3:00:00 AM2/3/00
to
I need to put a control which could be a button or a checkbox into a
cell.
The cell could be a cell in a StringGrid, DrawGrid or DBGrid. The
problem
is that I don't know which grid to use. Which one of the above grids
will let
me insert a control into the cells?
Do you have any sample code? I look at some of the demo files, but they
only support combobox in a cell.

Please help, and thanks in advance,

Sean

suwanto.vcf

Damon Chandler

unread,
Feb 3, 2000, 3:00:00 AM2/3/00
to
Hi Sean,

> I need to put a control which could be a button or a checkbox into a
> cell. The cell could be a cell in a StringGrid, DrawGrid or DBGrid. The
> problem is that I don't know which grid to use. Which one of the above grids
> will let me insert a control into the cells?

Unfortunately, none of the above controls support such functionality. Also,
such a scheme would be rather resource intensive. For example, placing a
TCheckBox in every cell of any grid containing a non-trivial amount of cells
would require the creation of a numerous amount of windows. For checkboxes or
buttons, it is generally better to render the control manually. The WC_LISTIVEW
and WC_TREEVIEW Common Control class perform a similar technique for its
checkboxes. Any of the VCL's TCustomGrid decendant controls will work, as each
allows the rendering of individual cells via the OnDrawCell event
(OnDrawColumnCell for TDBGrid). The hard part of this implementation is
actually maintaining the visibility and selected state of each control (checked
for checkboxes, pushed for buttons). Also, you'll need to perform some
hit-testing to determine when to render each control in its selected state. The
following example demonstrates how to place a checkbox in each cell of a
TStringGrid. It uses the TStringGrid::Objects property to store the visible
(low-order word) and checked (high-order word) state of each checkbox.

First, define some utility functions to keep things sane (and readable)...

bool __fastcall GetCheckState(TStringGrid *Grid, int ACol, int ARow)
{
return HIWORD(reinterpret_cast<long>(Grid->Objects[ACol][ARow]));
}

void __fastcall SetCheckState(TStringGrid *Grid, int ACol, int ARow,
bool Checked)
{
long data = reinterpret_cast<long>(Grid->Objects[ACol][ARow]);
Grid->Objects[ACol][ARow] =
reinterpret_cast<TObject *>(MAKELONG(LOWORD(data), Checked));

RECT GridRect;
GetWindowRect(Grid->Handle, &GridRect);

RECT R = Grid->CellRect(ACol, ARow);
OffsetRect(&R, GridRect.left, GridRect.top);
InvalidateRect(Grid->Handle, &R, true);
}

bool __fastcall GetCheckBox(TStringGrid *Grid, int ACol, int ARow)
{
return LOWORD(reinterpret_cast<long>(Grid->Objects[ACol][ARow]));
}

void __fastcall SetCheckBox(TStringGrid *Grid, int ACol, int ARow,
bool Show, bool Checked)
{
Grid->Objects[ACol][ARow] =
reinterpret_cast<TObject *>(MAKELONG(Show, false));
SetCheckState(Grid, ACol, ARow, Checked);
}

bool __fastcall PtInCheckBox(TStringGrid *Grid, int X, int Y,
int &ACol, int &ARow)
{
Grid->MouseToCell(X, Y, ACol, ARow);
RECT R = static_cast<RECT>(Grid->CellRect(ACol, ARow));

OffsetRect(&R, 2, 2);
R.right = R.left + GetSystemMetrics(SM_CXMENUCHECK);
R.bottom = R.top + GetSystemMetrics(SM_CYMENUCHECK);

return PtInRect(&R, Point(X, Y));
}


Next, set the StringGrid's DefaultDrawing property to false, then put these
utility functions to work as demonstrated below. StringGrid1DrawCell is the
StringGrid's OnDrawCell event handler.

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
int col_start = StringGrid1->FixedCols;
int col_end = StringGrid1->ColCount;

int row_start = StringGrid1->FixedRows;
int row_end = StringGrid1->RowCount;

for (int col = col_start; col < col_end; ++col)
for (int row = row_start; row < row_end; ++row)
SetCheckBox(StringGrid1, col, row, true, false);
}

void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, int ACol,
int ARow, TRect &Rect, TGridDrawState State)
{
// if it's a fixed row (headers)
if (State.Contains(gdFixed))
{
StringGrid1->Canvas->Brush->Color = clBtnFace;
StringGrid1->Canvas->Font->Color = clWindowText;
StringGrid1->Canvas->FillRect(Rect);
Frame3D(StringGrid1->Canvas, Rect,
clBtnHighlight, clBtnShadow, 1);
}

// if the cell is selected
else if (State.Contains(gdSelected))
{
StringGrid1->Canvas->Brush->Color = clHighlight;
StringGrid1->Canvas->Font->Color = clHighlightText;
StringGrid1->Canvas->FillRect(Rect);
}

// if normal
else
{
StringGrid1->Canvas->Brush->Color = StringGrid1->Color;
StringGrid1->Canvas->Font->Color = StringGrid1->Font->Color;
StringGrid1->Canvas->FillRect(Rect);
}

// if this cell contains a checkbox
if (GetCheckBox(StringGrid1, ACol, ARow))
{
// set the flags for rendering checked/unchecked
unsigned int state = DFCS_BUTTONCHECK;
if (GetCheckState(StringGrid1, ACol, ARow))
state = state | DFCS_CHECKED;

// size the checkbox
RECT R = static_cast<RECT>(Rect);
OffsetRect(&R, 2, 2);
R.right = R.left + GetSystemMetrics(SM_CXMENUCHECK);
R.bottom = R.top + GetSystemMetrics(SM_CYMENUCHECK);

// draw the checkbox
DrawFrameControl(StringGrid1->Canvas->Handle, &R,
DFC_BUTTON, state);
}

// render the cell's text
else
{
AnsiString text = StringGrid1->Cells[ACol][ARow];
StringGrid1->Canvas->TextRect(Rect, Rect.Left, Rect.Top, text);
}
}


Finally, perform the hit-testing by implementing a handler for the
StringGrid's OnMouseDown event...

void __fastcall TForm1::StringGrid1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
int ACol, ARow;
if (PtInCheckBox(StringGrid1, X, Y, ACol, ARow))
{
SetCheckState(StringGrid1, ACol, ARow,
!GetCheckState(StringGrid1, ACol, ARow));
}
}


Not only does this scheme limit the number of window handles needed, it also
keep things in sync with the TCustomGrid painting implementation. The technique
is similar for Buttons (use DFCS_PUSHED for buttons).

Good luck!

--
Damon Chandler
http://bcbcaq.freeservers.com

Tom Woodrow

unread,
Feb 3, 2000, 3:00:00 AM2/3/00
to
Using TAdvStringGrid from TMS Software allows the user to insert
checkboxed, spin edit controls ets into individual grid cells. The
package (with some 25 or more components) sells for about $95 US.

www.tmssoftware.com

Tom Woodrow

0 new messages