StringGrid Enterキーでセル移動(横・縦)


StringGridDemo

StringGridのOptionsプロパティの goEditing=Trueにしたとき
StringGridのColorプロパティをclWindow以外の色にすれば編集状態時にセル位置が見やすくなります

[Shift+Enter]で逆方向に移動するようにしたものです。

//StringGridのOnKeyDownイベント
procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key=VK_RETURN then begin
    with TStringGrid(Sender) do begin
      if SpBtnRight.Down then
//-------------------------------------    {[→]横移動}
        if Shift=[ssShift] then begin  {Shift+Enter 左移動}
          if Col > FixedCols then
            Col:=Col-1
          else
            if Row > FixedRows then begin
              Col:=ColCount-1;
              Row:=Row-1;
            end else begin
              Col:=ColCount-1;
              Row:=RowCount-1;
            end
          end
        else begin  {Enter 右移動}
          if Col < ColCount-1 then
            Col:=Col+1
          else
            if Row < RowCount-1 then begin
              Col:=FixedCols;
              Row:=Row+1;
            end else begin
              Col:=FixedCols;
              Row:=FixedRows;
            end;
          end
      else
//-------------------------------------    [↓]縦移動
        if Shift=[ssShift] then begin  {Shift+Enter 上移動}
          if Row > FixedRows then
            Row:=Row-1
          else
            if Col > FixedCols then begin
              Row:=RowCount-1;
              Col:=Col-1;
            end else begin
              Col:=ColCount-1;
              Row:=RowCount-1;
            end
          end
        else
          begin  {Enter 下移動}
            if Row < RowCount-1 then
              Row:=Row+1
            else
              if Col < ColCount-1 then begin
                Col:= Col +1;
                Row:=FixedRows;
              end else begin
                Col:=FixedCols;
                Row:=FixedRows;
              end;
          end;
    end;{with}
  end;
end;


StringGridで右寄せ表示・書式設定


//StringGridのOnDrawCellイベント
procedure TForm1.StringGrid1DrawCell(Sender: TObject;
  ACol, ARow: Longint;
  Rect: TRect; State: TGridDrawState);
begin
   StringGrid1.Canvas.FillRect(Rect);
   Rect.Top := Rect.Top + 2;
   DrawText(StringGrid1.Canvas.Handle, 
            PChar(StringGrid1.Cells[ACol,ARow]),
            Length(StringGrid1.Cells[ACol,ARow]),
            Rect, DT_RIGHT); // DT_RIGHT=右寄せ
end;

// 応用編
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  SGrid :TStringGrid;
  S :String;
  DTdraw :Integer;
begin
  SGrid:=TStringGrid(Sender);
  if (ARow>0)and(ACol=6) then 
    SGrid.Canvas.Brush.Color:=$00DAFECF;	{7列目の背景色を変更}
  SGrid.Canvas.FillRect(Rect);

  Rect.Left:= Rect.Left + 3;
  S:=SGrid.Cells[Acol,Arow];
  if (ARow=0) then DTdraw:=DT_CENTER else 	{1行目は、中央揃え}
  case ACol of
    0,4:DTdraw:=DT_CENTER;	{1,5列目は、中央揃え}
    1,3:DTdraw:=DT_RIGHT;	{2,4列目は、右揃え}
    5,6:begin		{6,7列目は、右揃えで桁区切り}
          DTdraw:=DT_RIGHT;
          S:=FormatFloat('#,###',StrToFloatDef(S,0));{表示のみ変更}
        end
    else DTdraw:=DT_LEFT;	{その他は、左揃え}
  end;
  DrawText(SGrid.Canvas.Handle,
            PChar(S),
            Length(S),
            Rect, DTdraw or DT_VCENTER or DT_SINGLELINE);{縦は中央揃え}
end;


StringGrid 行を削除する


procedure GridLineDel(var SGrid:TStringGrid; DeleteFix:Boolean=True);
var
  ACol,ARow: Integer;
begin
  with SGrid do begin
    //1行全てを削除して行を繰上げる
    if DeleteFix then begin
      for ARow:= Row to RowCount -1 do
        Rows[ARow].Assign(Rows[ARow+1]);
      Rows[RowCount -1].Clear;   //最終行
//    if RowCount-1 > FixedRows then RowCount:=RowCount-1;    //表の最終行を減らす場合
    end else
    //FixedCellを残して削除する
    begin
      for ARow:= Row to RowCount -1 do
        for ACol:= FixedCols to ColCount -1 do
          Cells[ACol,ARow]:=Cells[ACol,ARow +1];
      for ACol:= FixedCols to ColCount -1 do //最終行
        Cells[ACol,RowCount -1]:='';
    end;
  end;
end;

呼出しはPopUpMenuとかでするのがよいでしょう。 以下の例では、選択範囲の行を削除しています。

var ARow:Integer;
begin
  with StringGrid1 do begin
    for ARow:=1 to Selection.Bottom-Selection.Top+1 do
//      GridLineDel(StringGrid1);	//1行全てを削除して行を繰上げる場合
        GridLineDel(StringGrid1,False);//FixedCellを残して現在行を削除する

    Selection:= TGridRect(Rect( Col,Row,Col,Row));		//選択解除
  end;
end;


StringGrid 行を挿入する


procedure GridLineIns(var SGrid:TStringGrid; InsertFix:Boolean=True);
var
  ACol,ARow :Integer;
begin
  with SGrid do begin
    //1行挿入
    if InsertFix then begin
//    RowCount:=RowCount+1;   //行を増やす場合
      if Row < RowCount-1 then
        for ARow:=RowCount-1 downto Row+1 do
          Rows[ARow].Assign(Rows[ARow-1]);
      Rows[Row].Clear;
    end else
    //FixedCellは残す
    begin
      if Row < RowCount-1 then
        for ARow:=RowCount-1 downto Row+1 do
          for ACol:=FixedCols to ColCount-1 do
            Cells[ACol,ARow]:=(Cells[ACol,ARow-1]);
      for ACol:=FixedCols to ColCount-1 do
        Cells[ACol,Row]:='';
    end;
  end;
end;

  以下の例では、選択範囲の行数分を挿入しています。

var ARow:Integer;
begin
  with StringGrid1 do begin
    for ARow:=1 to Selection.Bottom-Selection.Top+1 do
//    GridLineIns(StringGrid1);			//1行挿入
      GridLineIns(StringGrid1,False);	//FixedCellを残して行を挿入する
    Selection:= TGridRect(Rect( Col,Row,Col,Row));
  end;
end;


StringGridで特定のセルを編集可・不可にする


  //StringGridのOnSelectCellイベント
procedure TForm1.StringGrid1SelectCell(Sender: TObject; 
	ACol, ARow: Integer;  var CanSelect: Boolean);
begin
  with TStringGrid(Sender) do begin
    if ACol = 2                               {1列目のAColは0}
      then Options := Options - [goEditing]   {3列目を編集不可}
      else Options := Options + [goEditing];  {編集可}
  end;
end;

(注)編集可にすると、複数セルの選択ができなくなります。


StringGridですべての列幅を自動調整する


procedure SGridAutoFit(SGrid: TStringGrid);
var
   ARow, ACol, tmpColWidth, maxColWidth: Integer;
begin
  for ACol := 0 to SGrid.ColCount-1 do begin
    maxColWidth := SGrid.DefaultColWidth;
    for ARow := 0 to SGrid.RowCount-1 do begin
      tmpColWidth := SGrid.Canvas.TextWidth(SGrid.Cells[ACol,ARow]);
      if tmpColWidth > maxColWidth then maxColWidth := tmpColWidth;
    end;
    SGrid.ColWidths[ACol] := maxColWidth + 10;
   end;
end;


StringGridでソートする (複数キーに対応)


	GridSort(対象StringGrid, キー列, [true=数値 False=文字列]);

	複数キーで、ソートする場合は、下位キーから順番に実行して下さい。
	例:	GridSort(StringGrid1, 2);		3列目文字キー
		GridSort(StringGrid1, 0, True);		1列目数値キー

	数値を文字列キーにする場合は、桁あわせ(0で埋める)が必要ですが、
	  StringGrid1.Cells[1,1]:=IntToStr(数値)		  X 
	  StringGrid1.Cells[1,1]:= FormatFloat('000',数値) O
	第3引数をTrueにすれば実数でソートします
procedure GridSort(SGrid:TStringGrid; ACol:Integer; KeyIsNum:Boolean=False);
  procedure MergeSort(Buffer: TStringList; ARow, Count: Integer);
    var I, J, Center : Integer;
        Temp: TStringList;
        Hikaku: Boolean;
  begin
    if Count = 1 then Exit;
    Center := Count div 2;
    MergeSort(Buffer, ARow, Center);
    MergeSort(Buffer, ARow + Center, Count - Center);
    I:=0; J:=0;
    Temp := TStringList.Create;
    try
      while (I < Center) and (J < Count - Center) do begin
        if KeyIsNum then
          Hikaku:=( StrToFloatDef(Buffer[ARow+I],0) > StrToFloatDef(Buffer[ARow+Center+J],0) )
        else
          Hikaku:=( CompareStr(Buffer[ARow+I],Buffer[ARow+Center+J]) >0 );
        if Hikaku then begin
          Temp.AddObject(Buffer[ARow + Center + J], Buffer.Objects[ARow + Center + J]);
          Inc(J);
        end else begin
          Temp.AddObject(Buffer[ARow + I], Buffer.Objects[ARow + I]);
          Inc(I);
        end;
      end;
      if I = Center then
        while J < Count - Center do begin
          Temp.AddObject(Buffer[ARow + Center + J], Buffer.Objects[ARow + Center + J]);
          Inc(J);
        end
      else
        while I < Center do begin
          Temp.AddObject(Buffer[ARow + I], Buffer.Objects[ARow + I]);
          Inc(I);
        end;
      for I:=0 to Count-1 do begin
        Buffer[ARow + I] := Temp[I];
        Buffer.Objects[ARow + I] := Temp.Objects[I];
      end;
    finally
      Temp.Free;
    end;
  end;

var
  ARow: Integer;
  Buffer: TStringList;
begin
  with SGrid do begin
    Buffer := TStringList.Create;
    try   //Buffer に key とそれに対応する Rows を格納する
      for ARow:=FixedRows to RowCount-1 do begin
        Buffer.AddObject(Cells[ACol, ARow], TStringList.Create);
        TStringList(Buffer.Objects[ARow - FixedRows]).Assign(Rows[ARow]);
      end;
      //Buffer を実際にソートする
      MergeSort(Buffer, 0, RowCount - FixedRows); //Buffer.Sort; と置き換え
      //ソートしたデータを Grid に書き戻す
      for ARow := FixedRows to RowCount - 1 do begin
        Rows[ARow].Assign(TStringList(Buffer.Objects[ARow - FixedRows]));
        TStringList(Buffer.Objects[ARow - FixedRows]).Free;
      end;
    finally
      Buffer.Free;
    end;
  end;
end;


StringGridのデータをExcelに書き出す

 usesに ComObj を追加して下さい。

procedure ExportToExcel(SGrid:TStringGrid);
var
  MsExcel      : Variant;
  MsApplication: Variant;
  WBook        : Variant;
  WSheet       : Variant;
  iCol,iRow    : integer;
  function columnToA1(clm:Integer) :string ;
  begin // カラム数 ==> A1参照形式へ変換
    if (clm-1) div 26 > 0 then
      Result:=Chr(64+ (clm-1) div 26)
    else
      Result:='';
    Result:=Result+ chr(65 + (clm-1) mod 26);
  end;


begin
//Excel起動
  MsExcel := CreateOleObject('Excel.Application');
  MsApplication := MsExcel.Application;
  MsApplication.Visible := True;
  WBook  := MsApplication.WorkBooks.Add ;
  WSheet :=WBook.ActiveSheet;
  //Excelにデータ出力
  WSheet.Rows[1].Font.Bold:= 'True';  //タイトル行を太字にする
  for iRow:=0 to SGrid.RowCount-1 do begin
    for iCol:=0 to SGrid.ColCount-1 do begin
      WSheet.Cells[iRow+1,iCol+1].Value:=SGrid.Cells[iCol,iRow];
    end;
  end;
  WSheet.Columns['A:'+columnToA1(SGrid.ColCount)].AutoFit; //列幅自動調整
end;


StringGridのデータをFILEに書き出す

 テキストの区切りにTABを使用

procedure GridSave(SGrid:TStringGrid; fName: String);
var stList :TStringList;
    ARow,ACol :Integer;
    S :String;
begin
  stList:=TStringList.Create;
  try
    for ARow:=0 to SGrid.RowCount-1 do begin
      S:= '';
      for ACol:=0 to SGrid.ColCount-1 do
        S:= S + SGrid.Cells[ACol,ARow]+ Chr(VK_TAB);
      stList.Add (S);
    end;
    stList.SaveToFile(fName);
//  stList.SaveToFile(fName,TEncoding.Unicode);   //Delphi2009
  finally
    stList.Free;
  end;
end;
//SaveDialogでの使用例
procedure TForm1.Button1Click(Sender: TObject);
begin
  SaveDialog1.DefaultExt:='TXT';
  SaveDialog1.Filter:= 'Text files (*.txt)|*.TXT';
  if SaveDialog1.Execute then
    GridSave(StringGrid1,SaveDialog1.FileName);
end;

 テキストの区切りに','を使用(CSV)

procedure GridSaveCSV(SGrid:TStringGrid; fName: String);
var stList :TStringList;
      ARow :Integer;
begin
  stList:=TStringList.Create;
  try
    for ARow:=0 to SGrid.RowCount-1 do
      stList.Add(SGrid.Rows[ARow].CommaText);
    stList.SaveToFile(fName);
//  stList.SaveToFile(fName,TEncoding.Unicode);   //Delphi2009
  finally
    stList.Free;
  end;
end;
//SaveDialogでの使用例
procedure TForm1.Button1Click(Sender: TObject);
begin
  SaveDialog1.DefaultExt:='CSV';
  SaveDialog1.Filter:= 'CSV files (*.csv)|*.CSV';
  if SaveDialog1.Execute then
    GridSaveCSV(StringGrid1,SaveDialog1.FileName);
end;


StringGridのデータをFILEから読込む

 TABで区切ったtextFileの読込み

procedure GridLoad(SGrid:TStringGrid; fName:string);
var stList: TStringList;
    ARow,ACol: Integer;
    tmpS: string;
    FldSeparator: Char;
begin
  stList:=TStringList.Create;
  try
    FldSeparator:= Char(VK_TAB);
    stList.LoadFromFile(fName);
    SGrid.RowCount:= stList.Count;
    SGrid.ColCount:= SGrid.FixedCols;
    for ARow:=0 to stList.Count-1 do begin
      ACol:= 0;
      tmpS:= stList[ARow];
      while Pos(FldSeparator,tmpS) > 0 do begin
        if ACol > SGrid.ColCount-1 then SGrid.ColCount:= ACol+1;
        SGrid.Cells[ACol,ARow]:= Copy(tmpS,1,Pos(FldSeparator,tmpS)-1);
        Delete(tmpS,1,Pos(FldSeparator,tmpS));
        Inc(ACol);
      end;
    end;
  finally
    stList.Free;
  end;
end;

 CSVFileからStringGridへ読込み

procedure GridLoadCSV(SGrid:TStringGrid; fName:string);
var stList: TStringList;
      ARow: Integer;
begin
  stList:=TStringList.Create;
  try
    stList.LoadFromFile(fName);
    SGrid.RowCount:= stList.Count;
    for ARow:=0 to stList.Count-1 do
      SGrid.Rows[ARow].CommaText:= stList[ARow];
  finally
    stList.Free;
  end;
end;


選択範囲をクリップボードにコピー

 usesに ClipBrd を追加して下さい。

//第2パラメータ、[Select=True]で選択範囲、Falseで全範囲
procedure CopyFromStringGrid(SGrid:TStringGrid;Select:Boolean=True);
var
   S :String;
   GRect :TGridRect;
   ACol,ARow :Integer;
begin
  if Select
    then GRect:=SGrid.Selection
    else GRect:=TGridRect(Rect(0,0,SGrid.ColCount-1,SGrid.RowCount-1));
  S:='';
  for ARow:=GRect.Top to GRect.Bottom do begin
    for ACol:=GRect.Left to GRect.Right  do begin
      if ACol= GRect.Right
        then S:=S+SGrid.Cells[ACol,ARow]
        else S:=S+SGrid.Cells[ACol,ARow]+#9;
    end;
    S:=S+#13#10;
  end;
  ClipBoard.AsText:= S;
end;


セル位置にクリップボードから貼付け(範囲指定は考慮していません)

 usesに ClipBrd を追加して下さい。

//第2パラメータ、[Select=True]で選択位置、Falseで左上(0,0)に貼付けます
procedure PasteToStringGrid(SGrid:TStringGrid; Select:Boolean=True);
var
  S,tmpS :String;
  ARow,ACol :Integer;
begin
  if Select then ARow:= SGrid.Row-1
            else ARow:= -1;
  S:=ClipBoard.AsText;
  while Pos(#13,S) > 0 do begin
    Inc(ARow);
    if Select then ACol:= SGrid.Col-1
              else ACol:= -1;
    tmpS:= Copy(S,1,Pos(#13,S));
    while Pos(#9,tmpS) > 0 do begin
      Inc(ACol);
      if (ACol <= SGrid.ColCount-1) and (ARow <= SGrid.RowCount-1) then
        SGrid.Cells[ACol,ARow]:= Copy(tmpS,1,Pos(#9,tmpS)-1);
      Delete(tmpS,1,Pos(#9,tmpS));
    end;
    if (ACol <= SGrid.ColCount-1) and (ARow <= SGrid.RowCount-1) then
      SGrid.Cells[ACol+1,ARow]:= Copy(tmpS,1,Pos(#13,tmpS)-1);
    Delete(S,1,Pos(#13,S));
    if Copy(S,1,1)=#10 then Delete(S,1,1);
  end;
end;


ページトップ