私は自分のプログラムでグリッドとして使用しているサードパーティツリーパッケージ(LMD InnovativeのElXTree)を持っています。セルを選択するたびに、その行はフォーカスを取得し、必要に応じて強調表示されます。Delphiでメッセージが送信された場所を確認するにはどうすればよいですか?
グリッド内のセルをクリックして提供されたInplaceエディタを呼び出すと、その行がフォーカスを取得します。セルは編集モードで選択されているので、セルだけがハイライト表示されます(行全体ではなく)。
これは私が望むものではありません:1つのセルを編集してインプレイスエディタを呼び出すと、それをクリックして別のセルのインプレイスエディタを呼び出すと、まず古いセルの行にフォーカスが当てられ、強調表示されます。その後、すぐにそのフォーカスが取り除かれ、ハイライトされず、新しいセルの行にフォーカスが与えられ、強調表示されます。次に、その新しい行は、編集されたセルが編集されていることを除いて、すぐにハイライトされなくなります。これは迷惑な二重点滅を引き起こし、私はそれを取り除きたい。
私はパッケージのソースコードを持っており、これを使ってデバッグしています。私は、ダブルフォーカシングを呼び出すものを見つけることができれば、それを防ぐための簡単な修正方法を見つけ出すことができます。
ブレークポイントを配置すると、私はFormsユニットのTApplication.Runのメッセージ処理ループに入っています。このループが扱う多くのメッセージのうち2つは、フォーカスを設定するものです。私は、メッセージをディスパッチするClassesユニットのStdWndProcに、行ごとにプログラムをトレースすることができます。私はメッセージに関するすべての情報(ハンドル、パラメータなど)を持っています。
私が持っていない、知らないのは、メッセージの発信元です。手がかりを得るためにコールスタックにElXTreeユニットはありません。これらのルーチンの1つは、現在のコールスタックとは独立したメッセージを送信しているに違いありません。
メッセージがどこから送信されたか(つまりどのルーチンから送信されたか)を知ることができれば、私は停止して実行します。
メッセージの送信元を見つける方法はありますか。あるいは、私が持っているこの二重焦点問題を回避できる他の方法はありますか?私は、Delphi 2009
を使用しています参考、
詳しい情報:
ElXTreeはそれはで動作する独自のWindowsメッセージの数十を持っています。私の場合は、2つの関連するものは以下のとおりです。
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
procedure TElXTreeView.WMSetFocus(var Msg: TWMSetFocus); { private }
begin
inherited;
FHasFocus := True;
if (FOwner.HideSelection or (FOwner.HideSelectColor <> FOwner.FocusedSelectColor) or (FOwner.HideSelectTextColor <> FOwner.FocusedSelectTextColor)) and
(FOwner.Items.Count > 0) then
Invalidate;
with FOwner do
if Flat or FUseCustomScrollBars or IsThemed then
UpdateFrame;
end; { WMSetFocus }
procedure TElXTreeView.WMKillFocus(var Msg: TWMKillFocus); { private }
begin
FMouseSel := False;
FPressed := False;
FHasFocus := False;
inherited;
FHintItemEx := nil;
DoHideLineHint;
if HandleAllocated then
begin
with FOwner do
if Flat or FUseCustomScrollBars or IsThemed then
begin
UpdateFrame;
DrawFlatBorder(False, False);
if FUseCustomScrollBars then
begin
HScrollBar.HideHint;
VScrollBar.HideHint;
end;
end;
if (FOwner.HideSelection or (FOwner.HideSelectColor <> FOwner.FocusedSelectColor) or (FOwner.HideSelectTextColor <> FOwner.FocusedSelectTextColor)) and
(FOwner.Items.Count > 0) then
Invalidate;
end;
end; { WMKillFocus }
私はWMSetFocusルーチン、たとえば、中にブレークポイントを置くとき、私は次のコールスタックを取得:
唯一の他のElXTree呼び出しスタック内のルーチンは、第四行にいずれかになります。私は、このルーチンにブレークポイントを置く
procedure TElXTreeView.WndProc(var Message: TMessage);
var P1: TPoint;
Item: TElXTreeItem;
HCol: Integer;
IP: TSTXItemPart;
begin
if (FHintItem <> nil) and (FOwner.FHideHintOnMove) then
begin
if ((Message.Msg >= WM_MOUSEMOVE) and (Message.Msg <= WM_MOUSELAST)) or (Message.Msg = WM_NCMOUSEMOVE) then
begin
GetCursorPos(P1);
P1 := ScreenToClient(P1);
Item := GetItemAt(P1.X, P1.Y, IP, HCol);
if Item <> FHintItem then
DoHideLineHint;
inherited;
Exit;
end
else
if
((Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST)) or
((Message.Msg = CM_ACTIVATE) or (Message.Msg = CM_DEACTIVATE)) or
(Message.Msg = CM_APPKEYDOWN) or (Message.Msg = CM_APPSYSCOMMAND) or
(Message.Msg = WM_COMMAND) or
((Message.Msg > WM_MOUSEMOVE) and (Message.Msg <= WM_MOUSELAST))
or (Message.Msg = WM_NCMOUSEMOVE) then
DoHideLineHint;
end;
if (FHintItem <> nil) and ((Message.Msg = CM_ACTIVATE) or (Message.Msg = CM_DEACTIVATE))
or (Message.Msg = WM_NCMOUSEMOVE) then
DoHideLineHint;
inherited;
end;
、それが唯一の「継承」の行に通過するようで、システム関数を呼び出して、最終的にメッセージが処理されるStdWndProcに行きます(私の元の質問で説明したように)。
これを正確にトレースする際に問題となるのは、コードをデバッグしながらマウスクリックをして、プログラム内のビジュアルコントロール上にマウスポインタを置かなければならないということです。デバッグ中にマウスの移動や使用に間違いがあると、処理に影響を与える追加のマウスイベントが発生する可能性があります。
しかし、私は慎重にStdWndProcにトレースし、その行をフォーカスするディスパッチされたイベントを参照してください。私がすることができないことは、メッセージを発行するものを見つけることです。
ここで、メッセージの内容を知りません。まあ、私はそれがPostMessageまたはSendMessageコマンドからのものであると仮定します。
Result := SendMessage(hWnd, SBM_SetScrollInfo, Integer(Redraw), Integer(@ScrollInfo));
SendMessage(hWnd, SBM_GetScrollInfo, 0, Integer(@ScrollInfo));
SendMessage(FHScrollBar.Handle, Message.Msg, Message.wParam, Message.lParam);
SendMessage(FVScrollBar.Handle, Message.Msg, Message.wParam, Message.lParam);
case Key of
VK_LEFT: begin
PostMessage(FOwner.Handle, WM_HSCROLL, SB_LINELEFT, 0);
Exit;
end;
VK_RIGHT: begin
PostMessage(FOwner.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
Exit;
end;
end;
FScrollbarsInitialized := True;
if UseCustomScrollbars then
PostMessage(Handle, WM_UPDATESBFRAME, 0, 0);
end;
procedure TCustomElXTree.WMSysColorChange(var Msg: TWMSysColorChange);
begin
inherited;
PostMessage(FVScrollBar.Handle, Msg.Msg, TMessage(Msg).WParam, TMessage(Msg).LParam);
PostMessage(FHScrollBar.Handle, Msg.Msg, TMessage(Msg).WParam, TMessage(Msg).LParam);
PostMessage(FHeader.Handle, Msg.Msg, TMessage(Msg).WParam, TMessage(Msg).LParam);
end; { WMSysColorChange }
スクロールバーを持つ最初の7契約:私はすべてのこれらの呼び出しがElXTreeで行われた場所を探したとき、私はこれらの10を見つけます。次の3つはColorChangeです。
私は他のすべてのLMDコンポーネントルーチンもメッセージの発行のために調べましたが、有望に見えるものはありません。
私はまだ固まっていて、そのメッセージの送信者を見つける方法についてヒントやヒントを必要としています。
回避策:
まあ、かつて私は、Windowsがマウスイベントを開始したことに気づいたが、私はほとんどの点滅の停止して何かをすることができました。それは本当にハックです。誰かが何か良いことを知っているなら、それについて聞いてみたいと思います。 TElXTreeView.WndProcで
は、私は次のように継承された文を交換しました:
if (Message.Msg = WM_SETFOCUS) or (Message.Msg = WM_KILLFOCUS) then begin
FOwner.Items.BeginUpdate;
inherited;
FOwner.Items.EndUpdate;
end
else
inherited;
これは何と呼ばれるルーチン内起こってから焦点を当て、複数の停止です。
私は編集可能な項目をクリックしていますが、それでも編集モードに入る前に項目を強調表示しています。ハイライトはMouseDownで発生しますが、編集モードに入るのはMouseUpで発生するためです。私はこれを回避する方法を見つけることができるかもしれないが、最初の試みは失敗した。しかし、それは二重の点滅と同じくらい悪くないし、私はそれを持っていなければならない。
私の脳にプッシュするのを手伝ってくれたあなたのおかげで、受け入れられた答えは私に鍵の手がかりをくれたダビデに行きます。
...私はあまりにも早く話しました。他のコントロールを見つけました。グリッドのあるページは、コントロール間のページング時には更新されません。 EndUpdateの後にRefreshコマンドを追加しようとしました。私がそれをしたら、私は再び二重に点滅した。これは本当に面倒な問題です。
私はページングの回避策を得ることができるかもしれませんが、そのコントロールの開発者がより良い修正で私に反応することを願っています。
このようなことは、プログラミングの楽しさの1つではありません。 :-(
ソースがある場合は、メッセージ識別子(WM_Whatever)にgrepを実行し、実行/送信するルーチンにログを追加します。 OnFocus *イベントのイベントハンドラを追加し、そこにログを追加します。それはあなたがそれを絞り込むことから始めるはずです。 –
は、デバッグや実行時にそれを行う必要がありますか? –
@Marjan Perform/SendはTApplication.Runを経由しません。 –