StringGridのInplaceEditorでIME状態取得について

解決


mook  2015-11-11 06:53:36  No: 47735

InplaceEditorで日本語を入力する時に今文字の変換中かどうかを知りたいのですが
下記の様なソースでやりますと ImeWindowProc_1 はスタックオーバーフローになってしまいます。

スタックオーバーフローにならないようにしたいのですが良い方法が思いつきません。

InplaceEditor を SGrid1GetEditText の外に出すことなども考えましたが無理のようで
何かいい方法がありましたらご教授お願いいたします。
(因みに環境は Windows8.1+Delphi6です)

type
  TForm1 = class(TForm)
〜略〜
    StringGrid1: TStringGrid;
〜略〜
  private
    { Private 宣言 }
    ImeConvStat:boolean;
    ImeWndMethod_1:TWndMethod;
    procedure ImeWindowProc_1(var Msg:TMessage);
  public
    { Public 宣言 }
  end;

〜略〜

//-----------------------------------------
// IME日本語変換状態取得 / TInplaceEdit用
procedure TForm1.ImeWindowProc_1(var Msg: TMessage);
begin
  case Msg.Msg of
    WM_IME_ENDCOMPOSITION:begin
      ImeConvStat := False;             // 変換終了
    end;
    WM_IME_COMPOSITION:begin
      ImeConvStat := True;              // 変換中
    end;
  end;
  ImeWndMethod_1(Msg);
end;

//-----------------------------------------
// セル編集
procedure TForm1.SGrid1GetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: String);
var
  InpEdit:TInplaceEdit;
begin
  InpEdit := TMyGrid(StringGrid1).InplaceEditor;

  if (InpEdit <> nil) then begin
     ImeWndMethod_1 := InpEdit.WindowProc;
     InpEdit.WindowProc := ImeWindowProc_1;
  end;

end;


Harry  2015-11-11 18:28:43  No: 47736

現状だと、OnGetEditTextが発生するたびにそのイベントハンドラ全体が実行されます。
すると、2回目に問題が発生します。
  1回目: Self.ImeWndMethod_1 ← InpEdit.WindowProc      // これは意図どおり
  2回目: Self.ImeWndMethod_1 ← TForm1.ImeWindowProc_1  // これはマズイ

この結果、TForm1.ImeWindowProc_1 の最後、
  ImeWndMethod_1(Msg);
で無限に自分自身を呼び出してしまいます。

なので、何らかの方法でサブクラス化を1回限りにする必要があります。
以下はその一例です。

  private
    FCapturedEdit: TInplaceEdit; // 追加

type
  TMyGrid = class(TStringGrid);

procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: String);
var
  InpEdit: TInplaceEdit;
begin
  InpEdit:=TMyGrid(StringGrid1).InplaceEditor;

  if (InpEdit<>FCapturedEdit) and (Assigned(InpEdit)) then begin
    Self.ImeWndMethod_1:=InpEdit.WindowProc;
    InpEdit.WindowProc:=Self.ImeWindowProc_1;
    FCapturedEdit:=InpEdit;
  end;
end;


mook  2015-11-11 22:25:55  No: 47737

Harry さん、早速のご回答ありがとうございます。

早速試してみたのですが
スタックオーバーフローは無くなりましたが

StringGridでセルをクリックして触ろうとしますと
あちこちセルは触れるのですが固まったような感じで編集モードになりません。
(キーでもマウスダブルクリックでも編集できません、何かおかしな動きです)
そしてプログラムを終了するときに

「ウィンドウハンドルが無効です。」

と言うメッセージでシステムエラーが起きます。

せっかく良い方法を教えて頂いたと思ってたのですが
確認しましても確かに一回だけしか処理されてないのに
その後の動きがおかしいです。


Harry  2015-11-11 23:13:00  No: 47738

うーん、どこかに何か配慮の足らない点があるのかもしれません。

まずは試しとしてアプリケーションを新規作成し、フォームにStringGridだけ置いて
やってみてください。
それで大丈夫なら、次は徐々に要素を追加していく作業を行います。
問題点はその過程で明らかになると思います。


mook  2015-11-12 01:06:13  No: 47739

Harry さん、ご連絡ありがとうございます。

すみません..私のやり方の問題でした。

そこでご指摘の通り新規にフォームを作りStringGridを貼ってやってみました。
結果、何の問題も無く動きました。
因みにこの状態で if (InpEdit<>FCapturedEdit) 〜 then begin / end; の部分をコメントにしますと
前と同じようにスタックオーバーフローになります。

これから実際のソースと比べながらどこが問題を起こしているのか調べてみます。

ありがとうございました、助かりました。


Harry  2015-11-12 02:00:04  No: 47740

前進できたようで何よりです。

もうすでにやってるとは思いますが、今度は逆に現在のコードからこのサブクラス化の部分
全体を取り除く(たぶんイベントを外すだけでいいと思いますが)とどうなるか、ですね。
それで問題が発生しないなら、何かとバッティングしてるということかも。

その「何か」は mook さんの仕込んだ特別なコードか、あるいは変哲のない普通のコードの
中に相性が悪いものがあるのかもしれません。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加