You still had the old StringGrid in the lfm file, but had commented its declaration in the pas file. Open the lfm file in an external editor and delete the StringGrid (first line to be deleted: " object sgMarks: TStringGrid", last line to be deleted "end" immediately before "object btnNewRecord: TButton" - make a backup copy before deleting anything)
Next: Since the old StringGrid is no longer there and you create the new MCStringGrid by code in the FormCreate event you must assign all properties that you had assigned to the StringGrid to the MCStringGrid. Here is the full code for sgMarks in the FormCreate event:
sgMarks := TMCStringGrid.Create(Self);
sgMarks.Parent := self;
sgMarks.height := 188;
sgMarks.width := 381;
sgMarks.left := 8;
sgMarks.top := 56;
sgMarks.ColCount := 5;
sgMarks.Cells[0, 0] := 'Line#';
sgMarks.Cells[1, 0] := 'Surname';
sgMarks.Cells[2, 0] := 'Forename';
sgMarks.Cells[3, 0] := 'Theory';
sgMarks.Cells[4, 0] := 'Practical';
sgMarks.ColWidths[0] := 36;
sgMarks.ColWidths[1] := 68;
sgMarks.ColWidths[2] := 73;
sgMarks.colWidths[3] := 64;
sgMarks.ColWidths[4] := 64;
sgMarks.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
goRangeSelect, goEditing, goColSpanning, goSmoothScroll];
sgMarks.OnEditingDone := @sgMarksEditingDone;
sgMarks.OnExit := @sgMarksEditingDone;
sgMarks.OnHeaderClick := @sgMarksHeaderClick;
sgMarks.OnPickListSelect := @onPickListSelect;
sgMarks.OnPrepareCanvas := @OnPrepareCanvas;
sgMarks.OnDrawCell := @sgMarksOnDrawCell;
sgMarks.OnSelectEditor := @sgMarksOnSelectEditor;
sgMarks.OnMergeCells := @MergeCellsHandler;
The OnPrepareCanvas that you added is nonsense (sorry for the word...). You must put here all commands that you want to be used for modification of the canvas for painting which will be called immediately afterwards. Here is what I would extract from the uncommented part of your OnDrawCell handler (declare the myXXXX colors outside the OnDrawCell method globally somewhere - you might need them again):
procedure TfrmGrid.sgMarksPrepareCanvas(sender: TObject; aCol, aRow: Integer;
aState: TGridDrawState);
begin
//sgMarks.Canvas.Brush.Color := clYellow;
//sgMarks.Canvas.Brush.Color := myXXX;
sgMarks.Canvas.Brush.Color := myBabyBlue;
if ARow = 0 then sgMarks.Canvas.Font.Style := [fsBold] else
sgMarks.Canvas.Font.Style := [];
if (ARow <> 0) and (ACol <> 0) then sgMarks.Canvas.Brush.Color := clLtGray;
end;
Since I see in the commented part of your OnDrawCell method that you may also want to paint bitmaps inside the cell the OnPrepareCanvas method is probably not what you need. For painting the bitmaps you could go back to the OnDrawCell method (however not tested with the MCStringGrid), or use the OnDrawCellText method of the MCStringGrid.
Now my part in the desaster: In your OnMergeCells event you check the contents of another cell to determine if the cells in col 2 to 5 will have to be merged. The problem is that calling Cells[col, row] checks whether the cell at (col,row) belongs to a merged block - and this can be determined only by firing an OnMergeCells event again - which calls Cells[] again - which fires OnMergeCells again -- etc, etc --> the program will crash in a stack overflow.
The new unit mcgrid in the attachment fixes this issue (hopefully...)
Let me better explain the OnMergeCells event. Suppose the grid is being redrawn. This occurs cell by cell along each row and then from top to bottom. Whenever a cell is painted it must be determined if the cell belongs to a merged block because in this case a larger cell rectangle will be required. For this purpose the grid calls the procedure which is hooked into the grid as OnMergeCell handler. The handler gets the column and row index of the cell which is about to be painted and returns to the grid the true left anr right column and top and bottom row index of the merged block. Then the grid will adapt the cell rectangle to the size of the merged block and paint the cell text. The cell text is determined from the top/left cell of the merged block which requires another call of OnMergeCells by the internal GetCells method.
After a cell is painted the grid procedes to the next cell and asks again if this is a merged cell. The OnMergeCells handler must repeat the left/right column and top/bottom row indexes of the cell block here even if the block already has been painted. One reason is that the merged block could be visible only partially, and you don't want to see the cell text jumping while the merged block scrolls out of view. This could be optimized, but would require more changes in the inherited code.
Your code: If I understand correctly you want to merge the cells in column 2 to 5 if the cell in column 1 contains the text "COMMENT" or " * ". Therefore you must check for the merged block boundaries in all block columns not only in col 2:
procedure TfrmGrid.MergeCellsHandler(Sender: TObject; ACol, ARow: Integer;
var ALeft, ATop, ARight, ABottom: Integer);
begin
if (sgMarks.Cells[1, ARow] = 'COMMENT') or (sgMarks.Cells[1, ARow] = ' * ') then
begin
if (ACol >= 2) and (ACol <= 5) then
begin
ALeft := 2;
ARight := 5;
ATop := ARow; // I suppose don't want "3" here...
ABottom :=ARow;
end;
end;
end;
In the attachment, find a modified version of your project. It does compile and run without any error now, but I did not check any of the other methods because I don't know how to load data etc.