何时在OnNewText事件后重绘VirtualTreeView?

时间:2012-10-12 23:03:47

标签: delphi c++builder virtualtreeview tvirtualstringtree

我使用此代码填充VirtualStringTree并允许重命名项目:

//---------------------------------------------------------------------------
// Structure for the tree
//---------------------------------------------------------------------------
struct TVSTdata
{
UnicodeString Name;
};
//---------------------------------------------------------------------------
// Initialization of the tree
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
VirtualStringTree1->NodeDataSize = sizeof(TVSTdata);
// Fill all nodes with initial data
InitializeTree();
}
//---------------------------------------------------------------------------
// Fill all nodes with data and assign FocusedNode
//---------------------------------------------------------------------------
void TForm1::InitializeTree()
{
TVirtualNode* pNode;
TVirtualNode* pActiveNode;
TVSTdata*     pData;

VirtualStringTree1->BeginUpdate();
VirtualStringTree1->Clear();

pNode = VirtualStringTree1->AddChild(NULL); pData = static_cast<TVSTdata*>(VirtualStringTree1->GetNodeData(pNode)); pData->Name = "This is name 1";
pNode = VirtualStringTree1->AddChild(NULL); pData = static_cast<TVSTdata*>(VirtualStringTree1->GetNodeData(pNode)); pData->Name = "This is name 2";
pNode = VirtualStringTree1->AddChild(NULL); pData = static_cast<TVSTdata*>(VirtualStringTree1->GetNodeData(pNode)); pData->Name = "This is name 3"; pActiveNode = pNode;
pNode = VirtualStringTree1->AddChild(NULL); pData = static_cast<TVSTdata*>(VirtualStringTree1->GetNodeData(pNode)); pData->Name = "This is name 4";
pNode = VirtualStringTree1->AddChild(NULL); pData = static_cast<TVSTdata*>(VirtualStringTree1->GetNodeData(pNode)); pData->Name = "This is name 5";

VirtualStringTree1->Selected[pActiveNode] = true;
VirtualStringTree1->FocusedNode = pActiveNode; // PROBLEM -> if assigned from within OnNewText will still remain NULL and won't be set to pActiveNode!
VirtualStringTree1->EndUpdate();
}
//---------------------------------------------------------------------------
// Just display the text
//---------------------------------------------------------------------------
void __fastcall TForm1::VirtualStringTree1GetText(TBaseVirtualTree *Sender, PVirtualNode Node, TColumnIndex Column, TVSTTextType TextType, UnicodeString &CellText)
{
TVSTdata* pData = static_cast<TVSTdata*>(Sender->GetNodeData(Node));
CellText = pData->Name;
}
//---------------------------------------------------------------------------
// Allow editing
//---------------------------------------------------------------------------
void __fastcall TForm1::VirtualStringTree1Editing(TBaseVirtualTree *Sender, PVirtualNode Node, TColumnIndex Column, bool &Allowed)
{
Allowed = true;
}
//---------------------------------------------------------------------------
// Now this is where ideally I would reload the tree with new data - after rename
//---------------------------------------------------------------------------
void __fastcall TForm1::VirtualStringTree1NewText(TBaseVirtualTree *Sender, PVirtualNode Node, TColumnIndex Column, UnicodeString NewText)
{
NewText = "not important for this example as tree is reloaded anyway";
InitializeTree();  // ERROR is here - after assigning FocusedNode it is still NULL
//Timer1->Enabled = true; // If delayed call FocusedNode is correctly assigned and not NULL
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
//InitializeTree();
//Timer1->Enabled = false;
}
//---------------------------------------------------------------------------

问题 - 最初调用InitializeTree()并分配VirtualStringTree1->FocusedNode时,它被正确分配(非NULL)。

但是,如果在InitializeTree()内调用此OnNewText函数以在重命名事件后实际从数据库重新加载树 - 在分配FocusedNode之后它仍为NULL。因此,显然无法在FocusedNode事件中重新加载树并分配OnNewText

我实现了延迟调用以重新加载新树并重新分配FocusedNode - 通过实现快速和脏的计时器(可能已经使用PostMessage进行延迟函数调用,但这只是一个愚蠢的例子) - 在计时器内分配后不再是NULL并按预期工作。

有人能指出实现树的重新加载的最佳方式是什么 - 就像使用一个特定的事件一样,可以安全地设置新的FocusedNode并且它不会被重新分配回NULL?延迟函数调用是实现此目的的唯一方法,还是有更好的事件要捕获(例如,如果一个发生在OnNewText之后,如果这个不允许设置聚焦节点)。当然这有效但我感兴趣的是有更好的方法来做到这一点。

1 个答案:

答案 0 :(得分:7)

当您处于FocusedNode树状态时,您无法更改tsEditing,并且在您离开OnNewText事件之前,您处于该状态。 OnNewText本身更适合编辑验证;它是事件,您可以在其中修改编辑的值。相反,您应该使用在实际编辑完成后触发的OnEdited事件。因此,移动您的数据库更新和树重新加载,如下面的C ++ Builder伪代码所示:

void __fastcall TForm1::VirtualStringTree1Edited(TBaseVirtualTree *Sender, 
  PVirtualNode Node, TColumnIndex Column)
{
  // update your database here; with VirtualStringTree1.Text[Node, Column] you
  // can access the current node text after edit; when you update your DB, call
  InitializeTree();
}