行単位でDrag&Dropにより、データを入れ替えることを前提としたサンプルです。
行番号部分をクリックすると列選択となり、列の選択には、CtrlキーやShiftキーと左クリックによる選択やマウスのスライドによる範囲選択ができます。実際に使えるものにするには、まだまだ作りこまないといけませんが、まあ、そのあたりはサンプルということで(^^;
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure StringGrid1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure StringGrid1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure StringGrid1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure StringGrid1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
Flag = 1;
var
CurrRow, FocusRow: Integer;
Sliding: Boolean;
procedure TForm1.FormCreate(Sender: TObject);
var
I,J: Integer;
begin
StringGrid1.DefaultDrawing := False;
StringGrid1.Align := alClient;
StringGrid1.RowCount := 50;
// とりあえずサンプルデータ
for I := 1 to StringGrid1.RowCount -1 do
for J := 1 to StringGrid1.ColCount -1 do
StringGrid1.Cells[J,I] := 'ITEM'+IntToStr(I*J) ;
end;
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
DRect: TRect;
Mode: Integer;
begin
DRect := Rect;
InflateRect(DRect, -2, -2);
{ 描画位置の設定・・・適当に }
if ACol = 1 then //右寄せ
Mode := DT_RIGHT
else if ACol = 2 then //左寄せ
Mode := DT_LEFT
else
Mode := DT_CENTER; //中央
{ 固定行が選択されている場合の表示 }
if Integer(StringGrid1.Objects[ACol,ARow]) = Flag then
begin
StringGrid1.Canvas.Brush.Color := clGray;
StringGrid1.Canvas.FillRect(Rect);
DrawEdge(StringGrid1.Canvas.Handle, Rect, BDR_SUNKENINNER, BF_BOTTOMRIGHT);
DrawEdge(StringGrid1.Canvas.Handle, Rect, BDR_SUNKENINNER, BF_TOPLEFT);
DrawText(StringGrid1.Canvas.Handle, PChar(IntToStr(ARow)),
Length(IntToStr(ARow)), DRect, Mode);
Exit;
end;
{ 固定行の標準描画 }
if (ACol = 0) and (ARow > 0) then
begin
StringGrid1.Canvas.Brush.Color := clBtnFace;
StringGrid1.Canvas.FillRect(Rect);
DrawEdge(StringGrid1.Canvas.Handle, Rect,BDR_RAISEDINNER, BF_BOTTOMRIGHT);
DrawEdge(StringGrid1.Canvas.Handle, Rect,BDR_RAISEDINNER, BF_TOPLEFT);
DrawText(StringGrid1.Canvas.Handle, PChar(IntToStr(ARow)),
Length(IntToStr(ARow)), DRect, DT_CENTER);
Exit;
end;
{ 固定列の標準描画 }
if (ARow = 0) then
begin
StringGrid1.Canvas.Brush.Color := clBtnFace;
StringGrid1.Canvas.FillRect(Rect);
DrawEdge(StringGrid1.Canvas.Handle, Rect,BDR_RAISEDINNER, BF_BOTTOMRIGHT);
DrawEdge(StringGrid1.Canvas.Handle, Rect,BDR_RAISEDINNER, BF_TOPLEFT);
if (ACol > 0) then
DrawText(StringGrid1.Canvas.Handle, PChar(IntToStr(ACol)),
Length(IntToStr(ACol)), DRect, DT_CENTER);
Exit;
end;
{ 行選択、セル選択の背景色の設定 }
if (goRowSelect in StringGrid1.Options) and
(Integer(StringGrid1.Objects[0,ARow]) = Flag) then
StringGrid1.Canvas.Brush.Color := clAqua
else
StringGrid1.Canvas.Brush.Color := clWindow;
StringGrid1.Canvas.FillRect(Rect);
DrawText(StringGrid1.Canvas.Handle, PChar(StringGrid1.Cells[ACol,ARow]),
Length(StringGrid1.Cells[ACol,ARow]), DRect, Mode);
if (not (goRowSelect in StringGrid1.Options)) and (gdFocused in State) then
StringGrid1.Canvas.DrawFocusRect(Rect);
end;
procedure TForm1.StringGrid1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure FlagClear;
var
I: Integer;
begin
for I := 0 to StringGrid1.Cols[0].Count - 1 do
StringGrid1.Cols[0].Objects[I] := nil;
end;
var
I, ACol, ARow: Integer;
begin
if (Button = mbRight) then Exit;
{ マウスの座標から現在のセル位置を取得します。 }
StringGrid1.MouseToCell(X, Y, ACol, ARow);
if (ACol <= 0) and (ARow <= 0) then Exit;
{ 0列目をクリックされた場合の処理 }
if (ACol = 0) then
begin
{0列で1行目以上の場合にはDragを許可します。}
if StringGrid1.Objects[0,ARow] = TObject(Flag) then
begin
StringGrid1.Row := ARow;
StringGrid1.BeginDrag(True);
Exit;
end;
{ 行選択の処理 }
CurrRow := Arow;
Sliding := True;
StringGrid1.Options := StringGrid1.Options + [goRowSelect];
// CtrlキーかShiftキーが押されていない場合には、Flagを消去します。
if (not (ssCtrl in Shift)) and (not (ssShift in Shift)) then
FlagClear;
if (ssCtrl in Shift) then
StringGrid1.Objects[0, ARow] := TObject(Flag)
else if (ssShift in Shift) then
begin
FlagClear;
// 選択範囲にFlagを設定します。
if (FocusRow < ARow) then
begin
for I := FocusRow to ARow do
StringGrid1.Objects[0, I] := TObject(Flag);
end
else
begin
for I := FocusRow downto ARow do
StringGrid1.Objects[0, I] := TObject(Flag);
end
end
else
StringGrid1.Objects[0,ARow] := TObject(Flag);
{ カーソルを現在の列に移動させます。 }
StringGrid1.Row := ARow;
FocusRow := ARow;
StringGrid1.Invalidate;
end
else
begin
{ 0列目以外の処理 }
FlagClear;
if ARow <> 0 then
StringGrid1.Objects[0, ARow] := TObject(Flag);
StringGrid1.Options := StringGrid1.Options - [goRowSelect];
FocusRow := ARow;
end;
end;
procedure TForm1.StringGrid1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
ACol, ARow: Integer;
begin
{マウスの座標から現在のセル位置を取得します。}
StringGrid1.MouseToCell(X, Y, ACol, ARow);
if (ACol <= 0) and (ARow <= 0) then Exit;
if Sliding and (ARow <> CurrRow)then
begin
if Integer(StringGrid1.Objects[0,ARow]) = Flag then
StringGrid1.Objects[0,ARow] := nil
else
StringGrid1.Objects[0,ARow] := TObject(Flag);
StringGrid1.Invalidate;
CurrRow := Arow;
end;
end;
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Sliding := False;
end;
procedure TForm1.StringGrid1DragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
var
ACol, ARow: Integer;
begin
if (Source is TStringGrid) then
(Sender as TStringGrid).MouseToCell(X, Y, ACol, ARow);
Accept := ((Sender is TStringGrid) and (Source is TStringGrid)) and
((Sender as TStringGrid) = (Source as TStringGrid)) and
(ARow > 0);
end;
procedure TForm1.StringGrid1DragDrop(Sender, Source: TObject; X,
Y: Integer);
var
I, DestRow, ACol: Integer;
SL: TStringList;
Temp: TList;
begin
Temp := TList.Create;
try
{挿入位置をマウス座標から取得します。}
StringGrid1.MouseToCell(X, Y, ACol, DestRow);
{DestRowまで選択行以外のものを保存します。}
for I := 0 to DestRow -1 do
begin
if StringGrid1.Objects[0,I] <> TObject(Flag) then
begin
SL := TStringList.Create;
SL.Assign(StringGrid1.Rows[I]);
Temp.Add(SL);
end;
end;
{選択行を保存します。}
for I := 0 to StringGrid1.RowCount -1 do
begin
if StringGrid1.Objects[0,I] = TObject(Flag) then
begin
SL := TStringList.Create;
SL.Assign(StringGrid1.Rows[I]);
Temp.Add(SL);
end;
end;
{DestRow以上で選択行以外を保存します。}
for I := DestRow to StringGrid1.RowCount -1 do
begin
if StringGrid1.Objects[0,I] <> TObject(Flag) then
begin
SL := TStringList.Create;
SL.Assign(StringGrid1.Rows[I]);
Temp.Add(SL);
end;
end;
{StringGrid1に設定します。}
for I := 0 to Temp.Count -1 do
StringGrid1.Rows[I].Assign(TStringList(Temp[I]));
finally
for I := 0 to Temp.Count -1 do
TStringList(Temp[I]).Free;
Temp.Free;
end;
end;
end.