单击 TreeView 上的 ListView(在 TForm 上)会触发 TreeView OnChange 事件
Posted
技术标签:
【中文标题】单击 TreeView 上的 ListView(在 TForm 上)会触发 TreeView OnChange 事件【英文标题】:Click on TListView (on TForm) over TTreeView triggers TTreeView OnChange event 【发布时间】:2017-04-25 11:40:05 【问题描述】:使用 Borland C++ Builder
我有一个应用程序,它带有一个自行创建的面包屑控件,位于TTreeView
控件的正上方,TListView
控件(alClient
在TForms
内)作为下拉菜单。
控件的位置是新的。意思是,实现较旧,并且以前运行良好,但我只是将面包屑控件移到 TTreeView
控件上方。
我现在注意到,从面包屑控件中单击 TListView
项目,也会触发 TTreeView
OnChange
事件!
并且选中的节点是最上面的节点。
这会导致我的设计发生冲突,因为TListView
项目单击和TTreeView
Onchange
会导致显示/完成不同的事情。
哪个事件最终“获胜”也不是 100%,因此结果也是可变的。
我可以考虑在面包屑代码执行时尝试禁用TTreeView
,以便忽略点击,但我想知道这是正常现象还是我遗漏了什么?
两个控件在相互显示时触发是否正常?
ListView 项目点击是通过分配以下函数的 OnClick 事件处理的:
void __fastcall TBreadcrumbListViewEx::InternalListViewClick(TObject *Sender)
if (FListView->Selected && FOnBreadcrumbListItemClick)
TPoint pt;
pt = FListView->ScreenToClient(Mouse->CursorPos);
THitTests HitTests = FListView->GetHitTestInfoAt(pt.x, pt.y);
if ( (HitTests.Contains(htOnIcon)) || (HitTests.Contains(htOnItem)) ||
(HitTests.Contains(htOnLabel)) || (HitTests.Contains(htOnStateIcon)) )
// This is a very precarious situation, because the FOnBreadcrumbListItemClick callback will most likely trigger building a new Breadcrumbs layout (Different Items)
// Which causes OnData events from this control to want to access Breadcrumbs that have been deleted already
// Therefore, get the selected Item (which will trigger OnData) and use its Index and Data members
TListItem *Item = FListView->Selected ;
// Next prevent any OnData event to get through and wreak havoc
// This needs to be done *before* Hide() is called
_releasing = true ;
// Hide is necesary because if the FOnBreadcrumbListItemClick event takes a long time, for instance it shows a dialog,
// this control will still be visible, yet it cannot show proper content anymore, since the OnData event is disabled
// Hence Hide() to no show it anymore when, for instance, a dialog is showing
Hide() ;
FOnBreadcrumbListItemClick(this, Item->Index, BreadcrumbItem, Item->Data);
Release(); // Close();
我一直在运行测试。
首先,我禁用了事件/回调FOnBreadcrumbListItemClick()
,但问题仍然存在,即使单击该项目时没有真正发生任何事情。
我一直在尝试禁用Hide()
、Release()
,将Release()
替换为Close()
等。但如果其中一个仍然存在,问题仍然存在。
只有当我同时禁用 Hide()
和 Release()
/Close()
时,我似乎不会遇到麻烦。直到那时我才在我的测试中不再看到TTreeView
OnChange
出现。老实说,我现在什么都不确定了。
这是你所期望的吗?或者这仅仅是一个副作用,问题仍然是别的?
另外......我将如何执行回调并从视图中隐藏/删除弹出窗口,而不会“不安”TTreeView
?
暂时禁用TTreeView
仍然是一种选择,但我宁愿修复这个问题,以免下次我将控件移动到其他位置时再次遇到麻烦。
【问题讨论】:
这意味着您的面包屑代码不会吞噬弹出表单上的鼠标单击,而是允许它传递到下面的 TreeView。这不是默认情况下 UI 的操作方式,这意味着您的面包屑可能会做一些不应该做的额外事情。但是您没有提供minimal reproducible example 来重现该问题,因此我投票决定将此作为题外话结束。 (ListItem)单击触发了一个重新填充面包屑控件的事件。深入挖掘我看到面包屑Enabled
设置为false
一段时间,在此过程中,以避免在冗长的过程中更多的点击。因此,这会在 Onclick 事件期间发生。这可能是面包屑控件不吞下鼠标点击的原因吗?我会再做一些测试。
@RemyLebeau - 今天经过更多测试后,我觉得可以在我认为存在问题的地方发布代码。感谢您的意见。
没有。我将不得不撤回或编辑我自己的答案。虽然下面的代码效果更好,但问题仍然存在。我现在改变了我的调试方法,并专注于TTreeView
而不是面包屑控件,我注意到问题从调用TreeView->ClearSelection()
的那一刻开始。该调用将 TreeView 设置为一种状态(不知何故),它突然也捕获了上面显示的控件的点击。对于未调用 ClearSelection() 的情况,所有工作都按预期工作并继续按预期工作。发现这一点也解释了我一直看到的可变性
现阶段我必须假设这是一个 VCL 问题。
【参考方案1】:
我最终通过将消息发布到队列末尾来“修复”它,以便 TListView
OnClick
事件可以尽快完成,并且鼠标事件完全被吸收,通过避免 @ OnClick
活动期间的 987654323@ 或 Release()
。
void __fastcall TBreadcrumbListViewEx::InternalListViewClick(TObject *Sender)
if (FListView->Selected && FOnBreadcrumbListItemClick)
TPoint pt = FListView->ScreenToClient(Mouse->CursorPos);
THitTests HitTests = FListView->GetHitTestInfoAt(pt.x, pt.y);
if ( (HitTests.Contains(htOnIcon)) || (HitTests.Contains(htOnItem)) ||
(HitTests.Contains(htOnLabel)) || (HitTests.Contains(htOnStateIcon)) )
PostMessage(Handle /*Destination*/, WM_APP, 0, (LPARAM)FListView->Selected);
//------------
void __fastcall TBreadcrumbListViewEx::WmApp(TMessage &Msg)
TListItem *ClickedItem = (TListItem*)Msg.LParam ;
if (ClickedItem)
// Next prevent any more OnData events to get through and wreak havoc
// This needs to be done *before* Hide() is called
_releasing = true ;
// Hide is necesary because if the FOnBreadcrumbListItemClick event takes a long time, for instance it shows a dialog,
// this control will still be visible, yet it cannot show proper content anymore, since the OnData event is disabled
// Hence Hide() to no show it anymore when, for instance, a dialog is showing
Hide() ;
// Disable the entire breadcrumb control to avoid clicks while a dialog is up or during a lengthy process to get the data for next
// breadcrumb layout
BBar->Enabled = false ;
FOnBreadcrumbListItemClick(this, ClickedItem->Index, BreadcrumbItem, ClickedItem->Data);
BBar->Enabled = true ;
Release();
【讨论】:
以上是关于单击 TreeView 上的 ListView(在 TForm 上)会触发 TreeView OnChange 事件的主要内容,如果未能解决你的问题,请参考以下文章
单击 ListView 上的删除按钮后删除 ListView 上的项目
在用户单击 listView 项目上的按钮的 Firebase 数据库上写入