2012-10-12 50 views
3

我用這個代碼來填充VirtualStringTree並允許重命名項目:何時在OnNewText事件後重繪VirtualTreeView?

//--------------------------------------------------------------------------- 
// 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分配是正確分配(NOT NULL)。

但是,如果在OnNewText內調用此InitializeTree()函數以在重命名事件後實際重新裝載數據庫樹 - 在指定FocusedNode之後,它仍爲NULL。所以很顯然,樹不能從OnNewText事件中重新加載並分配FocusedNode

我實現了延遲調用來重新加載新樹並重新指定FocusedNode - 通過實現一個快速和髒的定時器(可以使用PostMessage進行延遲函數調用,但這僅僅是一個愚蠢的例子) - 在定時器之後分配它不再是NULL並按預期工作。

任何人都可以點我什麼是實現重新加載樹的最佳方式 - 就像一個特定的事件使用,其中安全設置新的FocusedNode它不會被重新分配回NULL?延遲函數調用是實現這一目標的唯一方法,或者是否存在更好的陷阱事件(例如,如果此錯誤發生在OnNewText之後(如果此錯誤不允許設置焦點節點)。當然這有效,但如果有更好的方法來做到這一點,我很感興趣。

+2

如果你在談論的數據庫,你真的需要重新加載當您編輯只是一個單一節點的整個樹?當你編輯節點並重新加載數據庫中的單個行(重新加載該節點)時,難道你不想更新某一行嗎? – TLama

+0

我需要重新排序樹,因爲編輯節點可能會改變字母順序。從排序後的數據庫中重新加載樹更容易,而不是單獨排序樹。由於加載函數也排序並創建多級樹,因此更容易這樣做。此外,在VT中進行的排序可能與數據庫的排序不同。另外,如果我重新加載只有一個節點,我仍然需要使某個節點專注於對嗎? – Coder12345

+1

從數據庫重新加載排序數據可能會更容易,而不是排序樹,但這是一個矯枉過正的問題。如果您需要對樹進行排序,只需在節點編輯後調用'SortTree'並處理'OnCompareNodes'事件即可。對於你的問題,首先你必須記住清除樹之前選擇了哪個節點。但是你不能通過存儲'PVirtualNode'來完成,因爲當你清除並重新填充樹時,你存儲的節點指針不再有效。您必須存儲選定節點的索引。然後,在填充樹後,通過該存儲的索引找到新節點並選擇找到的節點。 – TLama

回答

7

當您處於tsEditing樹狀態並且直到您離開OnNewText事件時,您才能更改FocusedNode,您處於該狀態。 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(); 
} 
+1

正是我需要的解釋。並且還通過PostMessage調用節省了我的工作量。謝謝! – Coder12345