5
votes

I would like to strike text of all cells from a line in a stringgrid by right click on that line. My code is about ok, but the clicked cell from the line is not striked (the other well)!?! Also, I have to click first on a line and then right click to proceed, I would like just to right click but don't know how :-/ My code:

procedure TForm1.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var
  i, j: integer;
begin
  if Button = mbRight then
  begin
    j:=StringGrid1.Selection.Top;
    If MessageDlg('Disable row '+IntToStr(j),
      mtConfirmation, [mbYes, mbNo], 0, mbYes) =mrYes then
    begin
      With Stringgrid1 As TStringGrid Do
        With Canvas Do
        begin
          for i := 0 to 2 do
          begin
            Rect := CellRect  (i, StringGrid1.Selection.Top);
            Font.Style := Font.Style + [fsStrikeOut];
            FillRect(Rect);
            DrawText(Canvas.Handle, PChar(Cells[i,j]), -1, Rect ,DT_CENTER );
          end;
        end;
    end;
  end;
end;

Wonderfull!!! But if I want to store the striked status I also add a column containing a 'x'; it works fine BUT when I create form I load the stringrid value and some 'x' in column 3, I try to use that code in form.create to strike these row but doesn't work :-(

for J := 1 to stringGrid1.RowCount-1   do
begin
if  stringGrid1.Cells[3,J]='x' then
for I:=1 to 2 do
    begin
    StringGrid1.Canvas.Font.Style := Font.Style + [fsStrikeOut];
    StringGrid1.Canvas.Brush.Color := clBtnFace; // title
    StringGrid1.Canvas.FillRect(Rect);
    Rect.Top := Rect.Top + 4;
    drawText(Canvas.Handle, PChar(StringGrid1.Cells[I, J]), -1, Rect, DT_CENTER);
    StringGrid1.Invalidate;
    end
  else
    begin
    StringGrid1.Canvas.Font.Style := Font.Style - [fsStrikeOut];
    StringGrid1.Canvas.Brush.Color := clBtnFace; // title
    StringGrid1.Canvas.FillRect(Rect);
    Rect.Top := Rect.Top + 4;
    drawText(Canvas.Handle, PChar(StringGrid1.Cells[I, J]), -1, Rect, DT_CENTER);
    StringGrid1.Invalidate;
    end;
end;

Any idea???

1
Your drawing code looks ok, but overall idea will not work. Striked-thru text you just drawn will be erased and cell will be redrawn with default style. You have to write OnDrawCell handler and draw all your cells. - Free Consulting
Adding to FC's comment, your OnMouseDown handler should simply update the state of your data, and call Refresh to trigger a redraw. Your OnDrawCell handler should look at this state to decide whether or not to use strike-through for any cell it is drawing. - Disillusioned
You're not interested in the selection, you are interested in where the mouse is clicked. Replace your StringGrid1.Selection.Top with StringGrid1.MouseCoord(X, Y).Y. There're two of them (of course you can use 'j' for the latter). - Sertac Akyuz

1 Answers

3
votes

Since the property Rows is of type TStrings you might store the needed information about being marked as deleted in the Object of the first item (e.g. quick and dirty as integer). The painting is done in OnDrawCell using the stored information.

const
  CRLF = #13#10;


procedure TForm3.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  i: Integer;
begin
  With TStringGrid(Sender) do
  begin
    With Canvas Do
    begin
      if Integer(Rows[ARow].Objects[0]) = 1 then
        Font.Style := Font.Style + [fsStrikeOut]
      else
        Font.Style := Font.Style - [fsStrikeOut];
      if ARow = 0 then
        Brush.Color := clBtnFace // title
      else
        Brush.Color := clWhite;
      FillRect(Rect);
      Rect.Top := Rect.Top + 4;
      DrawText(Canvas.Handle, PChar(Cells[ACol, ARow]), -1, Rect, DT_CENTER);
    end;
  end;
end;

procedure TForm3.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
const
  C_Message: Array [0 .. 1] of String = ('Disable', 'Enable');
var
  C, R: Integer;
begin
  StringGrid1.MouseToCell(X, Y, C, R);
  if (Button = mbRight) and (C > -1) and (R > 0 { -1 } ) then
  begin // Allow  Disable or Enable depending on the stored state
    if (MessageDlg(C_Message[Integer(StringGrid1.Rows[R].Objects[0])] + ' row ' + IntToStr(R), mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes) then
    begin
      If Integer(StringGrid1.Rows[R].Objects[0]) = 0 then
        StringGrid1.Rows[R].Objects[0] := TObject(1)
      else
        StringGrid1.Rows[R].Objects[0] := TObject(0);
      StringGrid1.Invalidate; // force repainting
    end;
  end;
end;

procedure TForm3.FormCreate(Sender: TObject);
var
  R, C: Integer;
begin // Demo content
  With StringGrid1 do
  begin
    FixedCols := 0;
    DefaultDrawing := false;
    Rowcount := 6;
    Colcount := 4;
    DefaultColWidth := 100;
    Rows[0].Text := 'COL 1' + CRLF + 'COL 2' + CRLF + 'COL 3' + CRLF + 'COL 4';
    for R := 1 to Rowcount - 1 do
      for C := 0 to Colcount - 1 do
        Cells[C, R] := Format('Content %d - %d', [C + 1, R]);
  end;
end;