Delphi Tips
>> Index
● 01/02 StringGrid の内容更新を高速に行う
● 09/16 StringGrid でセル編集終了のイベントを得たい
● 09/16 TStringGrid の列の ReSize イベントの取得
● 02/11 TSplitter をドラッグ中にヒント文字列が表示された時の不具合
● 02/08 StringGrid で マウスのある Cell 内容に応じた Hint を出したい
● 02/08 StringGridで選択セルのハイライト表示を無くしたい
● 02/08 TStringGridのソート
● 02/08 StringGrid/DBGrid でのセル編集の動作を細かく指定する
最終更新: 9092 日前
0190 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/05/19 osamu rev 1.2 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2000/01/02 osamu 編集
StringGrid の内容更新を高速に行う
| 少々データ量が大きいので時間を稼ぐため、画面表示の Update を
| 停止したいのですが TStringGrid に BeginUpdate/EndUpdate は
| 無いようです。
【解法1】
描画更新の一次停止
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 0, 0);
描画更新の再開
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 1, 0);
StringGrid1.Refresh;
この方法は、すべての TWinControl に対して有効です。
【解法2】
描画更新の一次停止
StringGrid1.Rows[0].BeginUpdate;
描画更新の再開
StringGrid1.Rows[0].EndUpdate;
Rows[0] は Rows[1] でも何でも構いませんが、停止と開始で同じ添字を使わなければなりません。Cols[x] も使えます。一つの Rows[x] または Cols[x] に対して BeginUpdate すると StringGrid のすべての表示更新が停止になります。
BeginUpdate は TStrings の仮想メンバ関数なので、TMemo.Lines とか TListBox.Items などで BeginUpdate を使って TMemo/TListBox などの変更を高速に行うこともできます。
【メモ】
描画更新の再開を必ず行うために、BeginUpdate/EndUpdate は try/finally で保護した方が良いです。
StringGrid1.Rows[0].BeginUpdate;
try
// 更新処理
finally
StringGrid1.Rows[0].EndUpdate;
end;
また、BeginUpdate を繰り返し呼んだ場合には EndUpdate を同じ回数呼ばなければ描画は再開されません。さらに、BeginUpdate よりも多く EndUpdate を呼んでしまうとおかしなことになってしまうので注意が必要です。
参照: [Delphi-ML:38146] [builder:19539] <コンポーネント >
0263 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/16 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/16 osamu 編集
StringGrid でセル編集終了のイベントを得たい
StringGrid で表計算のような動作をさせようとすると、セル編集終了のイベントで、関係し合うセルの再計算を行いたくなります。OnSetEditText というイベントが利用できそうなのですが、このイベントはユーザのキー入力の一文字ごとに発生するため使えません。
で、少なくとも Delphi3 では、以下のようにすると、セル編集終了時を検出することができます。
これは、セル編集終了時に、OnSetEditText が2度続けて同じ Value 値で呼び出されるという現象を利用しています。Delphi の今後のバージョンで動作が保証されるわけではありませんので、注意が必要です。また、Options に goAlwaysShowEditor が含まれている場合には、Enter キーで値を確定することができないという不具合(?)が生じます。
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: String);
const
MagicValue = 'd0308|ybh<_lfds$t083q()'#1#5; // 入力値としてありえない値
PreviousEditorValue: string = MagicValue; // C でいう static 変数の代り
begin
if Value<>PreviousEditorValue then begin // まだ編集中
PreviousEditorValue:= Value;
Exit;
end;
// 編集終了時には、同じ値が二度続けて送られてくる
case ACol of
0: ;
1: ; // ここで入力後の処理
2: ;
end;
// 次回のために絶対にありえない文字列を代入
PreviousEditorValue:= MagicValue;
end;
参照: [Delphi-ML:42663] <コンポーネント >
0262 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/16 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/16 osamu 編集
TStringGrid の列の ReSize イベントの取得
ColWidthsChanged を overrideすることで、実現できます。
■interface
TStringGrid_Ex = class(TStringGrid)
private
FOnColWidthsChange:TNotifyEvent;
ptotected
procedure ColWidthsChanged; override;
published
property OnColWidthsChange:TNotifyEvent
read FOnColWidthsChange
write FOnColWidthsChange;
end;
■implementation
procedure TStringGrid_Ex.ColWidthsChange;
begin
inherited;
if Assigned(FOnColWIdthsChange) then
FOnColWidthsChange(Self);
end;
■利用方法
procedure TForm1.Grid1OnColWidthsChange(Sender:TObject);
var
idx :Longint;
begin
//条件
// Grid1.ColCount = Grid2.ColCountであること
if Sender = Grid1 then begin
for idx:=0 to Grid1.ColCount-1 do begin
Grid2.ColWidths[idx] := Grid1.ColWidths[idx];
end;
end else begin
for idx:=0 to Grid2.ColCount-1 do begin
Grid1.ColWidths[idx] := Grid2.ColWidths[idx];
end;
end;
end;
end;
同様に、RowHeighsChangedもoverrideできます。
参照: [Delphi-ML:31921] <コンポーネント >
0134 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/11 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/11 osamu 編集
TSplitter をドラッグ中にヒント文字列が表示された時の不具合
TSplitter をドラッグ中に他のコントロール上にてヒントボックスを出現させると、TSpliter の境界線がその場に残ってしまいます。
TSplitter のドラッグ中は Application.ShowHint を False にしてしまうという回避方が [Delphi-ML:24019] にて紹介されています。
参照: [Delphi-ML:24019] <バグ> <その他コンポーネント関連> <コンポーネント >
0082 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
StringGrid で マウスのある Cell 内容に応じた Hint を出したい
{Application.OnShowHint イベントハンドラの設定}
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnShowHint := DoShowHint;
end;
{ヒントの表示ルーチン}
{TForm1 の Private で宣言してあります。}
procedure TForm1.DoShowHint( var HintStr: string; var CanShow: Boolean;
var HintInfo: THintInfo);
var
ACol,ARow: Integer;
ARect: TRect;
begin
{ストリンググリッドならば}
if HintInfo.HintControl = StringGrid1 then begin
with HintInfo do begin
{ヒントの色の指定}
HintColor := clAqua;
{セルの位置を取得}
StringGrid1.MouseToCell( CursorPos.x, CursorPos.Y, ACol, ARow );
{セルの範囲の取得}
ARect := StringGrid1.CellRect( ACol, ARow );
{ヒントの表示位置}
HintPos := StringGrid1.ClientToScreen( Point(ARect.Left,ARect.Bottom));
{ヒントの内容}
HintStr := 'このセルは('+IntToStr(ACol)+','+IntToStr(ARow)+')';
{ヒントの有効範囲の設定}
CursorRect := ARect;
end;
end;
end;
参照: [Delphi-ML:19686] <その他コンポーネント関連> <コンポーネント >
0029 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
StringGridで選択セルのハイライト表示を無くしたい
>> TStringGridについてなんですが、それにFocusが当たってない場合に一つのセルの色
>> が青で塗りつぶされています。これを塗りつぶされていなくしたいのですが、やり方
>> をご存知の方、ご教授願います。
以下のような方法でできます。
// TForm1のメンバ
StringGrid1Selection:TGridRect;
// implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1Selection:=TGridRect(Rect(-1,-1,-1,-1));
end;
procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
StringGrid1Selection:=StringGrid1.Selection;
StringGrid1.Selection:=TGridRect(Rect(-1,-1,-1,-1));
end;
procedure TForm1.StringGrid1Enter(Sender: TObject);
begin
StringGrid1.Selection:=StringGrid1Selection;
end;
ただし、
TGridRect(Rect(-1,-1,-1,-1))は、ちょっと無理をしているので、
Delphi1.0や、将来のバージョンでは動かないことも考えられます。
> function GridRect(l,t,r,b:LongInt):TGridRect;
> begin
> with Result do begin
> Left:=l;
> Top:=t;
> Right:=r;
> Bottom:=b;
> end;
> end;
を作っておいて
StringGrid1.Selection:=GridRect(-1,-1,-1,-1);
とするのが正攻法です。
参照: [Delphi-ML:17189] <コンポーネント >
0023 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
TStringGridのソート
> StringGrid上に表示したデータを、ある列(Col)をKEYとしてソートし、
> 再表示させたいのですが、どのようにしたらよいのでしょうか?
エレガントさを求めず、力わざで良ければ、
procedure TForm1.FormCreate(Sender: TObject);
var i,j:Integer;
begin
for i:=0 to StringGrid1.ColCount-1 do
for j:=0 to StringGrid1.RowCount-1 do
StringGrid1.Cells[i,j]:=IntToStr(Random(100));
end;
procedure TForm1.StringGrid1DblClick(Sender: TObject);
var c,min,i,j:Integer;
s:string;
begin
c:=StringGrid1.Col;
for i:=0 to StringGrid1.RowCount-2 do begin
min:=i;
for j:=i+1 to StringGrid1.RowCount-1 do
if StrToInt(StringGrid1.Cells[c, j ]) <
StrToInt(StringGrid1.Cells[c,min]) then
min:=j;
if min<>i then
for j:=0 to StringGrid1.ColCount-1 do begin
s:=StringGrid1.Cells[j,i];
StringGrid1.Cells[j,i]:=StringGrid1.Cells[j,min];
StringGrid1.Cells[j,min]:=s;
end;
end;
end;
としてできますが、セル数が1万を超えると速度的にチョットきつくなってきます。大きなグリッドに対してこのようなことをやりたければTListViewを使うことをお勧めします。
参照: [Delphi-ML:12259] <コンポーネント >
0009 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
StringGrid/DBGrid でのセル編集の動作を細かく指定する
下のような関数を使って、TCustomGridで定義されているインプレースエディタを取得すれば、
GetGridEditor(StringGrid1).SelStart:=0;
などとできます。
function GetGridEditor(Grid: TCustomGrid): TCustomEdit;
var i: Integer;
begin
Result:=nil;
for i:=0 to Grid.ControlCount-1 do
if Grid.Controls[i] is TCustomEdit then begin
Result:=TCustomEdit(Grid.Controls[i]);
Exit;
end;
end;
参照: [Delphi-ML:18726] <データベース> <コンポーネント > <DataControls>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home