【发布时间】: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 问题。
标签: c++ c++builder vcl