ユーザーがデータの入力を終了したら、文字列グリッドのセルの内容を返したいと思います。ユーザーは、キーボードの Enter キーを押すか、別のセルをシングルクリックまたはダブルクリックすると終了します。
Lazarus には FinishedCellEditing のメソッドがありますが、Delphi にはありません。Delphiでそれを検出するにはどうすればよいですか?
ユーザーがデータの入力を終了したら、文字列グリッドのセルの内容を返したいと思います。ユーザーは、キーボードの Enter キーを押すか、別のセルをシングルクリックまたはダブルクリックすると終了します。
Lazarus には FinishedCellEditing のメソッドがありますが、Delphi にはありません。Delphiでそれを検出するにはどうすればよいですか?
私はまったく同じ問題を抱えていますが、ユーザーにEnterキーを押すように強制するため、より簡単な解決策があります...
秘訣:編集中にユーザーが別のセルに変更できないようにするため、編集を終了するにはイントロ/エンターを押す必要があります。その後、他のセルに変更できるようにします。
悪い点は、OnKeyPress が OnSetEditText の前に発生することです。そのため、OnKeyUp で試しました...
そして、私が見つけたのは、セルを編集するときに、Enter/Intro を押した後、OnKeyUp が起動されないことです...これは VCL のバグです...キーが解放され、OnKeyUp が起動されていません。
だから、私はそれをバイパスする別のトリックを作ります... タイマーを使用して、私が行うことを少しだけ変えて、イベント OnSetEditText を前に発生させます。
私が成功のために何をしたかを説明させてください...
次のようなコードを OnSelectCell に配置して、別のセルの選択をロックしました。
CanSelect:=Not UserIsEditingOneCell;
そして、OnSetEditText に次のようなコードを配置します。
UserIsEditingOneCell:=True;
だから今、必要なのは、ユーザーがEnter/Introを押したときを検出することです...そして、私が言ったように恐ろしいことを見つけました... OnKeyUpはそのようなキーに対して起動されません...だから、私はタイマーと OnKeyPress の使用。OnKeyPress は起動されますが、OnKeyUp は起動されません。Enter キーの場合...
だから、OnKeyPressで私は次のようなものを置きます:
TheTimerThatIndicatesUserHasPressEnter.Interval:=1; // As soon as posible
TheTimerThatIndicatesUserHasPressEnter.Enabled:=True; // But after event OnSetEditText is fired, so not jsut now, let some time pass
そのようなタイマー イベント:
UserIsEditingOneCell:=False;
// Do whatever needed just after the user has finished editing a cell
それは機能しますが、タイマーを使用する必要があるため、それは恐ろしいことです...しかし、より良い方法はわかりません...そして、編集中のセルが実行されていない間、ユーザーを別のセルに移動させないようにする必要があるためです有効な値を持っています...私はそれを使用できます。
OnEndingEditing のようなイベントがないのはなぜですか?
PD: また、押されたキーごとに OnSetEditText が複数回起動され、Value パラメーターの値が異なることにも気付きました...少なくとも、OnGetEditMask イベントで EditMask 値 '00:00:00' を設定して作業している場合。
VCL の TStringGrid では、OnSetEditText イベントが必要です。ただし、ユーザーが任意のセルで何かを変更するたびに起動することに注意してください。したがって、ユーザーが編集を終了した後にのみ何かを実行したい場合は、イベントのパラメーターの行と列の値を監視する必要があります。もちろん、ユーザーがセルの編集を終了し、別のセルを編集していない場合 (たとえば、TStringGrid の外側をクリックした場合) に対処する必要があります。何かのようなもの:
TForm1 = class(TForm)
...
private
FEditingCol, FEditingRow: Longint;
...
end;
procedure Form1.DoYourAfterEditingStuff(ACol, ARow: Longint);
begin
...
end;
procedure Form1.StringGrid1OnEnter(...)
begin
EditingCol := -1;
EditingRow := -1;
end;
procedure Form1.StringGrid1OnSetEditText(Sender: TObject; ACol, ARow: Longint; const Value: string)
begin
if (ACol <> EditingCol) and (ARow <> EditingRow) then
begin
DoYourAfterEditingStuff(EditingCol, EditingRow);
EditingCol := ACol;
EditingRow := ARow;
end;
end;
procedure Form1.StringGrid1OnExit(...)
begin
if (EditingCol <> -1) and (EditingRow <> -1) then
begin
DoYourAfterEditingStuff(EditingCol, EditingRow);
// Not really necessary because of the OnEnter handler, but keeps the code
// nicely symmetric with the OnSetEditText handler (so you can easily
// refactor it out if the desire strikes you)
EditingCol := -1;
EditingRow := -1;
end;
end;
これは、インプレース エディターに送信された WM_KILLFOCUS メッセージに応答することで行います。これを実現するには、インプレース エディターをサブクラス化する必要があります。
Raymond Chen のブログから、フォーカスを変更する検証を実行する場合、これは適切ではないことを理解しています。
解決:
TMyGrid= class(TStringGrid)
private
EditorPrevState: Boolean; //init this to false!
EditorPrevRow : LongInt;
EditorPrevCol : LongInt;
procedure WndProc(VAR Message: TMessage); override;
procedure EndEdit (ACol, ARow: Longint); // the user closed the editor
etc
end;
constructor TMyGrid.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
EditorPrevRow := Row;
EditorPrevCol := Col;
EditorPrevState:= false;
end;
procedure TMyGrid.WndProc(var Message: TMessage);
begin
inherited;
if EditorPrevState then { The editor was open }
begin
if NOT EditorMode then { And not is closed }
begin
EditorPrevState:= EditorMode;
EndEdit(EditorPrevCol, EditorPrevRow); <------ editor is closed. process the text here
end;
EditorPrevRow := Row;
EditorPrevCol := Col;
End;
EditorPrevState := EditorMode;
end;
procedure TMyGrid.EndEdit(aCol, aRow: Integer); { AlwaysShowEditror must be true in Options }
begin
Cells[ACol, ARow]:= StringReplace(Cells[ACol, ARow], CRLF, ' ', [rfReplaceAll]); { Replace ENTERs with space - This Grid cannot draw a text on multiple rows so enter character will he rendered as 2 squares. }
if Assigned(FEndEdit)
then FEndEdit(Self, EditorPrevCol, EditorPrevRow); // optional
end;
基本的に、ユーザーが編集を終了する方法はたくさんありますが、これらすべてが常に適切なインターセプト ポイントになるわけではありません。
どのような状況でコンテンツを更新したいかを自問する必要があります。
たとえば、ユーザーがモーダル フォームをキャンセルしたとき、またはアプリケーションを終了したときに更新しますか?
--jeroen