使用 Borland C++ Builder
我有一个带有自行创建的 Breadcrumb 控件的应用程序,位于 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
发生。老实说,我现在什么都不确定了。
这是您所期望的吗?或者这仅仅是副作用,问题仍然存在?
另外......我怎么才能执行回调并从 View 中隐藏/删除弹出窗口,而不会“扰乱”TTreeView
?
暂时禁用 TTreeView
仍然是一个选项,但我宁愿解决这个问题,以免下次我将控件移动到其他位置时再次遇到麻烦。
最佳答案
我最终通过将消息发布到队列末尾来“修复”它,以便 TListView
OnClick
事件可以尽快完成,这样通过在 OnClick
事件期间避免 Hide()
或 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();
}
}
关于c++ - 在 TTreeView 上点击 TListView(在 TForm 上)触发 TTreeView OnChange 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43609664/