2011-06-23 20 views
3

私は自分のプログラムでグリッドとして使用しているサードパーティツリーパッケージ(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ルーチン、たとえば、中にブレークポイントを置くとき、私は次のコールスタックを取得:

Call Stack

唯一の他の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つではありません。 :-(

+0

ソースがある場合は、メッセージ識別子(WM_Whatever)にgrepを実行し、実行/送信するルーチンにログを追加します。 OnFocus *イベントのイベントハンドラを追加し、そこにログを追加します。それはあなたがそれを絞り込むことから始めるはずです。 –

+0

は、デバッグや実行時にそれを行う必要がありますか? –

+0

@Marjan Perform/SendはTApplication.Runを経由しません。 –

答えて

3

これらのメッセージは、同期して送信されるのではなく、メッセージキューに送信されます。これは、メインスレッドのメッセージキューをポンピングするルーチンであるTApplication.Runにトレースされているためです。そのため、コールサイトはスタックに表示されません。 PostMessageの呼び出しによって生成されます.PartMessageは、サードパーティ製のコンポーネントか、Windowsの可能性が高い可能性があります。

私はこれらのコンポーネントを知らないので、私はあなたの問題を解決するのに役立ちます。私はあなたが何をすべきかを知っておくべきコンポーネントベンダーに連絡するべきだと思います。

+0

Davidに感謝します。私は彼らがスタックにいない理由を理解していますが、私はこれがどこから呼び出されたかを追跡する方法を探しています。私がそれを見つけることができれば、解決策は簡単でなければならない。私は今ベンダーに連絡して応答を待っていますが、これはELDOSによって開発された非常に古いコードであると思われます。LMD社はElPackを購入しました。私は後ろにいくつかのバージョンがありますが、変更履歴はこれに対する修正を示すものではありません。 – lkessler

+0

私は示唆したように、PostMessageへの呼び出しを検索することでこれらの呼び出しを見つけることができませんでしたか? –

+0

@David:私は試しましたが、PostMessageとSendMessageの呼び出しのうち、私が探しているWM_SETFOCUSまたはWM_KILLFOCUSのメッセージはありません。詳細については、私の質問に追加したセクションを参照してください。このメッセージを送信する方法は他にありますか? – lkessler

関連する問題