Recent

Author Topic: grid question... making newly added cell text extend through the cells to right  (Read 10414 times)

swoop80

  • New Member
  • *
  • Posts: 40
Okay.  I have given your instructions a try (attempting to use my existing demo project, and just add your cool stuff to it).  I'm getting errors again - some like what I was getting much earlier today. 

Here is the exception I get now: Project string_grid_demo raised exception 'EClassNotFound' with message: Class "TStringGrid" not found   At address 43FB3C

swoop80

  • New Member
  • *
  • Posts: 40
attempting to upload a txt file which contains my Unit1 code.

wp

  • Hero Member
  • *****
  • Posts: 13352
It definitely would be easier for me to help you if you would upload a complete compilable project because then the debugger would help. For this purpose, pack the .lfm, .pas, .lpi, and .lpr files into a single .zip file and upload it here (no compiler-generated files, please).

Quickly scanning your file I saw one bug: you implement an OnDrawCell handler, and in this code you change the options of the grid. If doing this triggers another repaint you may get into trouble because this would call OnDrawCell again... You seem to set only colors there. Also, I don't know how my modified grid behaves if there is an OnDrawCell handler, I did not test this case. It is much better to use the OnPrepare event for this purpose which definitely cooperates with merged cells.

Another problem is in the OnMergeCells handler: you commented the "if". If the grid supports the merging option (goColSpanning in Options) then whenever a cell rectangle is needed, i.e. even for non-merged cells, the OnMergeCells event is called - this is because the grid per se does not know which cells are merged. Without the "if" every cell therefore would be mapped to the block col=2..5 and row=3.

No errors, but bad coding: FillGrid and GridToArray work only with the grid in frmGrid (frmGrid.sgMarks). Therefore, they should be methods of TfrmGrid. Or, if you want them to work with other grids, then you should pass the grid variable as a parameter.

swoop80

  • New Member
  • *
  • Posts: 40
Would like to focus on this point for now:


Another problem is in the OnMergeCells handler: you commented the "if". If the grid supports the merging option (goColSpanning in Options) then whenever a cell rectangle is needed, i.e. even for non-merged cells, the OnMergeCells event is called - this is because the grid per se does not know which cells are merged. Without the "if" every cell therefore would be mapped to the block col=2..5 and row=3.


I commented out the if for now because i thought the if might be better in the the part of the logic which invokes the onmerge logic... but not sure if that is really what is occurring....  so question: is that code (where the @ onmerge is placed) 'calling' the onmerge event logic... or is it just setting up an event to be fired?  If the latter: what actually makes the event fire?

swoop80

  • New Member
  • *
  • Posts: 40
I have changed the handler to have this code now, but still get same error:

procedure TfrmGrid.MergeCellsHandler(Sender: TObject; ACol, ARow: Integer;
  var ALeft, ATop, ARight, ABottom: Integer);
begin
  // Define a merged block which is a single row heigh
  //if (ACol in [1..2]) and (ARow = 1) then begin
  if (sgMarks.Cells[1, ARow] = 'COMMENT') or (sgMarks.Cells[1, ARow] = '   *   ') then
      begin
        if ACol = 2 then
          begin
            ALeft := 2;
            ARight := 5;
            ATop := 3;
            ABottom :=3;
          end;
      end;
end;

swoop80

  • New Member
  • *
  • Posts: 40
I have changed to use an onprepare and added the IF in the handler... still getting same error.  Here is a zip file which has all the files in it:

wp

  • Hero Member
  • *****
  • Posts: 13352
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:
Code: Pascal  [Select][+][-]
  1.   sgMarks := TMCStringGrid.Create(Self);
  2.   sgMarks.Parent := self;
  3.   sgMarks.height := 188;
  4.   sgMarks.width := 381;
  5.   sgMarks.left := 8;
  6.   sgMarks.top := 56;
  7.   sgMarks.ColCount := 5;
  8.   sgMarks.Cells[0, 0] := 'Line#';
  9.   sgMarks.Cells[1, 0] := 'Surname';
  10.   sgMarks.Cells[2, 0] := 'Forename';
  11.   sgMarks.Cells[3, 0] := 'Theory';
  12.   sgMarks.Cells[4, 0] := 'Practical';
  13.   sgMarks.ColWidths[0] := 36;
  14.   sgMarks.ColWidths[1] := 68;
  15.   sgMarks.ColWidths[2] := 73;
  16.   sgMarks.colWidths[3] := 64;
  17.   sgMarks.ColWidths[4] := 64;
  18.   sgMarks.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  19.     goRangeSelect, goEditing, goColSpanning, goSmoothScroll];
  20.   sgMarks.OnEditingDone := @sgMarksEditingDone;
  21.   sgMarks.OnExit := @sgMarksEditingDone;
  22.   sgMarks.OnHeaderClick := @sgMarksHeaderClick;
  23.   sgMarks.OnPickListSelect := @onPickListSelect;
  24.   sgMarks.OnPrepareCanvas := @OnPrepareCanvas;
  25.   sgMarks.OnDrawCell := @sgMarksOnDrawCell;
  26.   sgMarks.OnSelectEditor := @sgMarksOnSelectEditor;
  27.   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):

Code: Pascal  [Select][+][-]
  1. procedure TfrmGrid.sgMarksPrepareCanvas(sender: TObject; aCol, aRow: Integer;
  2.   aState: TGridDrawState);
  3. begin
  4.   //sgMarks.Canvas.Brush.Color := clYellow;
  5.   //sgMarks.Canvas.Brush.Color := myXXX;
  6.   sgMarks.Canvas.Brush.Color := myBabyBlue;
  7.  
  8.   if ARow = 0 then sgMarks.Canvas.Font.Style := [fsBold] else
  9.     sgMarks.Canvas.Font.Style := [];
  10.  
  11.   if (ARow <> 0) and (ACol <> 0) then sgMarks.Canvas.Brush.Color := clLtGray;
  12. 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:
Code: Pascal  [Select][+][-]
  1. procedure TfrmGrid.MergeCellsHandler(Sender: TObject; ACol, ARow: Integer;
  2.   var ALeft, ATop, ARight, ABottom: Integer);
  3. begin
  4.   if (sgMarks.Cells[1, ARow] = 'COMMENT') or (sgMarks.Cells[1, ARow] = '   *   ') then
  5.   begin
  6.     if (ACol >= 2) and (ACol <= 5) then
  7.     begin
  8.       ALeft := 2;
  9.       ARight := 5;
  10.       ATop := ARow;   // I suppose don't want "3" here...
  11.       ABottom :=ARow;
  12.     end;
  13.   end;
  14. 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.

swoop80

  • New Member
  • *
  • Posts: 40
Thanks again.  As I was reading each paragraph, I was making updates.  Then I found that you included the fixes - appreciate that.  I downloaded and looked it over some more.  Some of it makes sense, other parts, not so much.  I compile it and tried it out, and it doesn't work right.  For instance, the drop-downs that are supposed to be in col 1 and 2 aren't operative for some reason.  But, I will work on it and see if I can figure something out.  There is more than enough to say grace over here - so, I will start praying.  Appreciate it.

 

TinyPortal © 2005-2018