//////////////////////////////////////////////////////////// //CSV保存する関数 //00/09/08 ユニット化 // LoadもSaveもExcel互換(DelphiのCommaText仕様)にした //2005/04/22 // ユニット名をCsvIOForStrGrid→StringGridunitにした // TsvへのIO関数も用意した //////////////////////////////////////////////////////////// unit StringGridUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, ComObj, Variants, Math, StringUnitLight, WordDecompose, XPtest; type TGridSize = record RowCount: Cardinal; ColCount: Cardinal; end; type TSeparateValueFileInfo = record StrictMatrix: Boolean; GridSize: TGridSize; end; //StringGridの内容をCSV形式に保存します procedure CSVSaveForStringGrid(TargetGrid: TStringGrid; SaveGridRect: TRect; FileName: String); //CSVファイルが何行何列で構成されているかを調べる function GetRectFromCSVFile(FileName: String): TSeparateValueFileInfo; //CSVファイルをStringGridにロードします function CSVLoadForStringGrid(TargetGrid: TStringGrid; StartingPoint: TPoint; FileName: String): Boolean; //StringGridの内容をTSV形式に保存します procedure TSVSaveForStringGrid(TargetGrid: TStringGrid; SaveGridRect: TRect; FileName: String); //TSVファイルが何行何列で構成されているかを調べる function GetRectFromTSVFile(FileName: String): TSeparateValueFileInfo; //TSVファイルをStringGridにロードします function TSVLoadForStringGrid(TargetGrid: TStringGrid; StartingPoint: TPoint; FileName: String): Boolean; procedure StringGridClear(StrGrid: TStringGrid); procedure StringGridRowNumber(StrGrid: TStringGrid; OutputCol:Word=0; StartRow:Word=0; StartNumber:Integer=0; IncCount:Integer=1); procedure StringGridAutoFitCol(StrGrid: TStringGrid; FitColumn: Word; MinColumnWidth, MaxColumnWidth, TextWidthPlus: Word); procedure StringGridAutoFitCols(StrGrid: TStringGrid; FitStartColumn, FitEndColumn, MinColumnWidth, MaxColumnWidth, TextWidthPlus: Word); procedure GridTextOutputExcel(StrGrid: TStringGrid; GridRect: TRect; OutputExcelPoint: TPoint); implementation {Rectがちゃんと内部に入っているかどうか確認する関数} function RectInRect(InRect, OutsideRect: TRect): Boolean; begin Result := false; if (OutsideRect.Left <= InRect.Left) and (InRect.Right <= OutsideRect.Right) then if (OutsideRect.Top <= InRect.Top) and (InRect.Bottom <= OutsideRect.Bottom) then begin Result := true; end; end; {PointがOutsideRect内部に入っているかどうかを確認する関数} function PointInRect(InPoint: TPoint; OutsideRect: TRect): Boolean; var PointRect: TRect; begin PointRect.TopLeft := InPoint; PointRect.BottomRight := InPoint; Result := RectInRect(PointRect, OutsideRect); end; //------------------------------- (*StringGridの内容をCSV形式に保存します 引数説明: TargetGrid: SaveGridRect:目的のGridのCSVにする指定範囲 FileName: 備考: SaveGridRect := Rect(0,0,ColCount-1,RowCount-1) こうするとGridのすべてのセルがCSV化される := Rect(FixexCols, FixedRows, ...) とすると非固定セル部分がCSV化されます -------------------------------*) procedure CSVSaveForStringGrid(TargetGrid: TStringGrid; SaveGridRect: TRect; FileName: String); var StringList1, RowStringList: TStringList; i, j: Integer; begin {↓StringGridの大きさに指定Rectが収まっているのかをチェック} if not RectInRect(SaveGridRect, Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin raise Exception.Create('指定のRect範囲がおかしいです'); exit; end; StringList1 := TStringList.Create; RowStringList := TStringList.Create; try for j := SaveGridRect.Top to SaveGridRect.Bottom do begin RowStringList.Clear; for i := SaveGridRect.Left to SaveGridRect.Right do begin RowStringList.Add(TargetGrid.Rows[j].Strings[i]); end; StringList1.Add(RowStringList.CommaText); {↑一行を追加/CommmaTextを使うためExcel互換になっている} end; StringList1.SaveToFile(FileName); finally RowStringList.Free; StringList1.Free; end; end; //------------------------------- (*CSVファイルが何行何列で構成されているかを調べる 引数説明: FileName: 戻り値: TcsvFileInfo: StrictMatrix: CSVとして完全な行数を持っているかどうか ColCount: CSVとして正しく無い場合、ファイルの最大列数をしめす RowCount: そのまんま 備考: 内部で自作汎用関数StrCount2を使用しています。 履歴: 2000/00/00 -------------------------------*) function GetRectFromCSVFile(FileName: String): TSeparateValueFileInfo; var StringList1: TStringList; i, MatrixColCount: Integer; begin Result.StrictMatrix := false; Result.GridSize.ColCount := 0; Result.GridSize.RowCount := 0; if not FileExists(FileName) then exit; StringList1 := TStringList.Create; try StringList1.LoadFromFile(FileName); Result.GridSize.RowCount := StringList1.Count; {↑行数を設定} if Result.GridSize.RowCount = 0 then exit; for i := 0 to StringList1.Count - 1 do begin (*----------------------------------- if Result.ColCount < WordCount(',', StringList1[i], dmExcelCSV) then Result.ColCount := WordCount(',', StringList1[i], dmExcelCSV); //-----------------------------------*) if Result.GridSize.ColCount < WordCount(',', StringList1[i], dmDelimiterExactly) then Result.GridSize.ColCount := WordCount(',', StringList1[i], dmDelimiterExactly); {↑列数を設定} end; (*----------------------------------- Result.StrictMatrix := true; MatrixColCount := WordCount(',', StringList1[0], dmExcelCSV); for i := 1 to StringList1.Count - 1 do begin if MatrixColCount <> WordCount(',', StringList1[0], dmExcelCSV) then Result.StrictMatrix := false; {↑CSVとして完全かどうかを確認} end; //-----------------------------------*) Result.StrictMatrix := true; MatrixColCount := WordCount(',', StringList1[0], dmDelimiterExactly); for i := 1 to StringList1.Count - 1 do begin if MatrixColCount <> WordCount(',', StringList1[i], dmDelimiterExactly) then begin Result.StrictMatrix := false; {↑CSVとして完全かどうかを確認} break; end; end; finally StringList1.Free; end; end; //------------------------------- (*CSVファイルをStringGridにロードします 引数説明: TargetGrid: FileName: StartingPoint: CSVを読み込む所を決めます StartingPoint:=Point(0,0)なら StringGridの一番左上から読み込み :=Point(Grid.FixedCols,Grid.FixedRows)なら 非固定セル部分から読み込まれます 戻り値: true:成功 false:失敗 備考: GridにCSVを読み込むだけの大きさが無ければ はみ出した所のデータは取得出来ません。 -------------------------------*) function CSVLoadForStringGrid(TargetGrid: TStringGrid; StartingPoint: TPoint; FileName: String): Boolean; var StringList1: TStringList; i, j, CellColCount: Integer; begin Result := false; if not FileExists(FileName) then exit; if not PointInRect(StartingPoint, Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin raise Exception.Create('指定位置がおかしいです'); exit; end; StringList1 := TStringList.Create; try StringList1.LoadFromFile(FileName); for i := 0 to StringList1.Count - 1 do begin {↓読み出したファイルの列数を出す} CellColCount := WordCount(',', StringList1[i], dmDelimiterExactly); for j := 0 to CellColCount do begin {↓もしループ中の指定位置がちゃんとグリッドに収まっているなら} if PointInRect(Point(j+StartingPoint.x, i+StartingPoint.y), Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin TargetGrid.Cells[j+StartingPoint.x, i+StartingPoint.y] := WordGet(',', StringList1[i], j, dmDelimiterExactly); end; end; end; finally StringList1.Free; end; end; {------------------------------- // StringGridの内容をTSV形式に保存します。 機能: 引数説明: SaveGridRect:目的のGridのTSVにする指定範囲 備考: SaveGridRect := Rect(0,0,ColCount-1,RowCount-1) こうするとGridのすべてのセルがTSV化される SaveGridRect := Rect(FixexCols, FixedRows, ...) とすると非固定セル部分がCSV化される 履歴: 2005/04/22 //------------------------------} procedure TSVSaveForStringGrid(TargetGrid: TStringGrid; SaveGridRect: TRect; FileName: String); var StringList1: TStringList; RowStr: String; i, j: Integer; begin {↓StringGridの大きさに指定Rectが収まっているのかをチェック} if not RectInRect(SaveGridRect, Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin raise Exception.Create('指定のRect範囲がおかしいです'); exit; end; StringList1 := TStringList.Create; try for j := SaveGridRect.Top to SaveGridRect.Bottom do begin RowStr := ''; for i := SaveGridRect.Left to SaveGridRect.Right do begin RowStr := RowStr + TargetGrid.Rows[j].Strings[i] + TAB; end; SetLength(RowStr, Length(RowStr)-1); StringList1.Add(RowStr); end; StringList1.SaveToFile(FileName); finally StringList1.Free; end; end; //------------------------------ {------------------------------- // TSVファイルが何行何列で構成されているかを調べる 機能: 引数説明: StrictMatrix: TSVとして完全な行数を持っているかどうか ColCount: TSVとして正しく無い場合、ファイルの最大列数をしめす RowCount: そのまんま 備考: 履歴: 2005/04/22 //------------------------------} function GetRectFromTSVFile(FileName: String): TSeparateValueFileInfo; var StringList1: TStringList; i, MatrixColCount: Integer; begin Result.StrictMatrix := false; Result.GridSize.ColCount := 0; Result.GridSize.RowCount := 0; if not FileExists(FileName) then exit; StringList1 := TStringList.Create; try StringList1.LoadFromFile(FileName); Result.GridSize.RowCount := StringList1.Count; {↑行数を設定} if Result.GridSize.RowCount = 0 then exit; for i := 0 to StringList1.Count - 1 do begin if Result.GridSize.ColCount < WordCount(tab, StringList1[i], dmDelimiterExactly) then Result.GridSize.ColCount := WordCount(tab, StringList1[i], dmDelimiterExactly); {↑列数を設定} end; Result.StrictMatrix := true; MatrixColCount := WordCount(tab, StringList1[0], dmDelimiterExactly); for i := 1 to StringList1.Count - 1 do begin if MatrixColCount <> WordCount(tab, StringList1[i], dmDelimiterExactly) then begin Result.StrictMatrix := false; break; end; end; finally StringList1.Free; end; end; //------------------------------ {------------------------------- // TSVファイルをStringGridにロードします 引数説明: StartingPoint: TSVを読み込む所を決めます StartingPoint:=Point(0,0)なら StringGridの一番左上から読み込み StartingPoint:=Point(Grid.FixedCols,Grid.FixedRows)なら 非固定セル部分から読み込まれます 戻り値: true:成功 false:失敗 備考: GridにTSVを読み込むだけの大きさが無ければ はみ出した所のデータは取得出来ません。 履歴: 2005/04/22 //------------------------------} function TSVLoadForStringGrid(TargetGrid: TStringGrid; StartingPoint: TPoint; FileName: String): Boolean; var StringList1: TStringList; i, j, CellColCount: Integer; begin Result := false; if not FileExists(FileName) then exit; if not PointInRect(StartingPoint, Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin raise Exception.Create('指定位置がおかしいです'); exit; end; StringList1 := TStringList.Create; try StringList1.LoadFromFile(FileName); for i := 0 to StringList1.Count - 1 do begin {↓読み出したファイルの列数を出す} CellColCount := WordCount(tab, StringList1[i], dmDelimiterExactly); for j := 0 to CellColCount do begin {↓もしループ中の指定位置がちゃんとグリッドに収まっているなら} if PointInRect(Point(j+StartingPoint.x, i+StartingPoint.y), Rect(0, 0, TargetGrid.ColCount - 1, TargetGrid.RowCount - 1)) then begin TargetGrid.Cells[j+StartingPoint.x, i+StartingPoint.y] := WordGet(TAB, StringList1[i], j, dmDelimiterExactly); end; end; end; finally StringList1.Free; end; end; //------------------------------ {------------------------------- // StringGridの内容をクリアします 備考: 履歴: 2005/04/23 //------------------------------} procedure StringGridClear(StrGrid: TStringGrid); var i: Integer; begin for i := 0 to StrGrid.RowCount-1 do begin StrGrid.Rows[i].Clear; end; end; //------------------------------ {------------------------------- // StringGridの指定列に行番号を入れます 備考: 履歴: 2005/04/23 //------------------------------} procedure StringGridRowNumber(StrGrid: TStringGrid; OutputCol:Word=0; StartRow:Word=0; StartNumber:Integer=0; IncCount:Integer=1); var i: Integer; begin {↓出力列がColCountより大きいなら×} if StrGrid.ColCount-1 < OutputCol then Exit; {↓開始行がRowCountより大きいなら×} if StrGrid.RowCount-1 < StartRow then Exit; for i := StartRow to StrGrid.RowCount-1 do begin StrGrid.Cells[OutputCol, i] := IntToStr(StartNumber + ((i-StartRow)*IncCount)) end; end; //------------------------------ {------------------------------- // StringGridの指定列のサイズを文字内容にあわせてFitする // StringGridAutoFitCol // StringGridAutoFitCols 引数説明: FitRow:指定列 MinRowWidth: 列最小幅 MaxRowWidth: 列最大幅 FitStartRow, FitEndRow: 指定列 備考: 履歴: 2005/04/23 //------------------------------} procedure StringGridAutoFitCol(StrGrid: TStringGrid; FitColumn: Word; MinColumnWidth, MaxColumnWidth, TextWidthPlus: Word); var i, ItemTextWidth: Integer; begin ItemTextWidth := 0; for i := 0 to StrGrid.RowCount-1 do begin ItemTextWidth := Max(ItemTextWidth, StrGrid.Canvas.TextWidth(StrGrid.Cols[FitColumn].Strings[i])+ TextWidthPlus); end; ItemTextWidth := Max(MinColumnWidth, ItemTextWidth); ItemTextWidth := Min(MaxColumnWidth, ItemTextWidth); StrGrid.ColWidths[FitColumn] := ItemTextWidth; end; procedure StringGridAutoFitCols(StrGrid: TStringGrid; FitStartColumn, FitEndColumn, MinColumnWidth, MaxColumnWidth, TextWidthPlus: Word); var i: Integer; begin if FitEndColumn < FitStartColumn then Exit; if StrGrid.ColCount-1 < FitEndColumn then Exit; for i := FitStartColumn to FitEndColumn do begin StringGridAutoFitCol(StrGrid, i, MinColumnWidth, MaxColumnWidth, TextWidthPlus); end; end; //------------------------------ {------------------------------- // Gridの内容をExcelに出力する 備考: 履歴: 2005/04/23 //------------------------------} procedure GridTextOutputExcel(StrGrid: TStringGrid; GridRect: TRect; OutputExcelPoint: TPoint); var Excel : Variant; WorkBook : Variant; WorkSheet : Variant; CreateNewBookFlag: Boolean; i, j: Integer; begin if not RectInRect(GridRect, Rect( Point(0,0), Point(StrGrid.ColCount-1, StrGrid.RowCount-1) ) ) then Exit; try try {表示中のExcelのオブジェクトを取得} Excel:=GetActiveOleObject('Excel.Application'); except on EOleSysError do begin //ShowMessage('エクセルが起動していません'); Excel := CreateOleObject('Excel.Application'); end; end; {ブックを作成} WorkBook := Excel.Workbooks.Add; {シートオブジェクトを定義} WorkSheet := WorkBook.WorkSheets[ 1 ]; CreateNewBookFlag := True; WorkSheet.Activate; Excel.Visible:=True; for i := GridRect.Top to GridRect.Bottom do begin for j := GridRect.Left to GridRect.Right do begin if StrGrid.Cells[j,i] <> '' then begin WorkSheet.Cells[OutputExcelPoint.Y + (i-GridRect.Top) +1, OutputExcelPoint.X + (j-GridRect.Left) +1] := StrGrid.Cells[j, i]; end; end; end; if CreateNewBookFlag then //幅自動調整 WorkSheet.Columns.AutoFit; except //{ ----------------------------------- Excel.DisplayAlerts := False;//メッセージダイアログを表示しない WorkBook.close; WorkBook:=unAssigned; WorkSheet:=unAssigned; Excel.Quit; Excel:=unAssigned; //----------------------------------- } end; end; //------------------------------ end.