2011-06-23 24 views
3

我有一个第三方树包(LMD Innovative的ElXTree),我在程序中用作网格。每当我选择一个单元格时,该行就会获得焦点并突出显示,就像我想要的那样。如何查找在Delphi中发送消息的位置?

当我通过单击网格中的单元格调用提供的Inplace编辑器时,该行获得焦点。因为单元格是在编辑模式下选择的,所以只有单元格被突出显示(不是整行),也正如我所希望的那样。

我不想要的是这样的:当我就地编辑一个单元格时,通过单击它来调用另一个单元格的就地编辑器,首先将具有旧单元格的行赋予焦点并突出显示。然后立即将其焦点带走并且不被强调,并且具有新单元格的行被给予焦点和突出显示。然后,除了在位编辑的单元格之外,该新行立即变得不突出。这导致一个恼人的双闪烁,我想摆脱它。

我有包的源代码,我一直在通过它进行调试。我确定如果我能找到调用双重对焦的东西,我将能够弄清楚如何进行简单的修改以防止它。

当我放置断点时,我发现我在Forms单元中的TApplication.Run的消息处理循环中。这个循环处理的许多消息中的两个是设置焦点的消息。我可以将程序一行一行地追溯到StdWndProc的Classes单元,其中消息是Dispatched。我拥有关于消息的所有信息(Handle,Parameters等)。

我没有,也不知道消息是从哪里发起的。在调用堆栈中没有ElXTree单元来提示我。其中一个例程必须独立于当前调用堆栈发送消息。

如果我可以找出发送信息的位置(即发送的是哪个例程),那么我将关闭并运行。

有什么方法可以找到邮件的发送地点吗?或者,还有其他方法可以解决我遇到的这个双重焦点问题吗?

仅供参考,我使用德尔福2009年


更多信息:

ElXTree有它与它自己的Windows消息的几十个。在我的情况下,两个相关的是:

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在调用栈例程是一个4号线:

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命令。当我寻找所有这些电话在ElXTree制造,我只觉得这些10:

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处理滚动条。接下来的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上。我可能能够找到解决办法,但最初的尝试不成功。但它没有双闪一样坏,如果必须的话,我可以忍受它。

感谢那些帮助我推动大脑的人。接受的答案是David给了我关键线索。


......也许我说得太快了。我发现了一些其他控件,例如带有网格的页面在控件之间分页时不会更新。我试过在EndUpdate之后添加一个Refresh命令。一旦我做到了,我又重新闪了一次。这是一个真正的混乱问题。

我可能能够得到解决方法,但我希望该控件的开发人员能够对我做出更好的修复。

这样的事情不是编程的乐趣之一。 :-(

+0

如果您有源代码,请在消息标识符(WM_Whatever)上执行grep,将日志记录添加到执行/发送它的例程中;为OnFocus *事件添加事件处理程序并在其中添加日志记录。这应该让你开始缩小范围。 –

+0

需要做调试或运行时? –

+0

@Marjan执行/发送不通过TApplication.Run –

回答

3

这些消息被发送到消息队列而不是同步发送,这很明显,因为你正在追溯到TApplication.Run这是泵送主线程消息队列的例程。这就是为什么你没有看到堆栈上的呼叫站点。它们通过调用PostMessage生成,无论是在第三方组件中,还是可能由Windows调用。

我不知道这些组件,所以我怀疑我可以帮助解决您的问题。我想你应该联系应该知道该怎么做的组件供应商。

+0

谢谢大卫。我明白为什么他们不在堆栈中,但我正在寻找方法来追踪这些信息的来源。如果我能找到答案,解决方案应该很简单。我现在联系了这家供应商,正在等待回应,但看起来这是ELDOS开发的很老的代码,LMD公司从ElPack那里购买了ElPack。我后面有几个版本,但他们的更改日志并不表示对此有任何修正。 – lkessler

+0

您是否可以通过搜索PostMessage调用来找到这些调用? –

+0

@David:我试过了,但所有的PostMessage和SendMessage调用都没有看到我正在寻找的WM_SETFOCUS或WM_KILLFOCUS消息。查看我添加到我的问题的更多信息部分。有没有其他方式可以发送此消息? – lkessler