안녕하세요.
VirtualTreeView는 소스가 델파이로 되어 있으면,
델파이나 BCB에서 사용가능한 형태의 콤포넌트로 제공되고 있습니다.
소스가 델파이다 보니 BCB에서 사용할때는 정보가 좀 부족한 면이 있습니다.
그래서 이 강좌를 시작한 이유기도 하구요 ^^
저도 처음 이 콤포넌트의 막강한 기능을 접하고는 감동이었지요.
그런데, inline 에디터의 예제가 델파이로 되어 있어서 구현하려니 참 나감하더군요ㅡ.ㅡ
그러던중. VirtualTreeView 홈페이지 (
http://www.soft-gems.net/ ) 에 갔더니
BCB로 만들어진 inline 에이터 예제와 소스 샘플이 있더군요.
http://www.soft-gems.net/VirtualTreeview/
이 위치의
" IVTEditLink demo for BCB 5 "
이 예제를 받아 보시면 됩니다.
그런데, 이 예제를 받아 보면 실행은 되는데, 제대로 다 만들어 놓은 것은 아니더군요.
버그도 좀 있구요.
아무튼 이것을 바탕으로 수정및 업데이트 된 inline 에디터에 대해서 다루어 보겠습니다.
1. inline 에디터 유닛
EditorUnit.cpp 와 EditorUnit.h 란 인라인 에디터 소스는 위에서 설명한 소스를 가져다가 제가 업데이트한 것입니다.
업데이트의 주 내용은
* 범용적으로 사용가능하도록 소스의 의존성 제거
* 다수의 버그 수정
등 입니다.
이 소스도 최종본이라고 하기는 뭐하구요. 각 필요에 따라서 수정을 더 해 나아갸 합니다.
저도 제 필요에 따라서 조금씩 업데이트 하기 때문에, 아지 모든 기능이 동작하는 것은 아닙니다 ^^
EditorUnit 의 소스는 첨부파일을 보시구요.
EditorUnit.h 파일에 보시면,
typedef enum {
ptNone,
ptEdit,
ptCombo,
// ptNumber,
ptDate
} TPropertyTyp;
typedef struct {
TPropertyTyp PropertyTyp; // editory type
WideString Value; // data value
bool Changed; // 변경 여부
} TPropertyData, *lpPropertyData;
이런 형 정의가 있는데요.
TPropertyTyp 은 inline 에디터에서 사용할 에디팅 형식 입니다.
ptNone --> 에이터를 사용하지 않음.
ptEdit --> TEdit 형태의 에디터를 제공.
ptCombo --> 콤포박스 형태의 에디터 제공
ptDate --> 날짜 선택 (TDateTimePicker) 에디터 제공
TPropertyData 은 VTV에서 한 셀(Cell) 에 해당하는 데이타의 형입니다.
Node 나 Row 의 데이타가 아닙니다. 주의 하세요.
이 정도만 아시고,
EditorUnit.cpp 와 EditorUnit.h 를 inline 에디터를 사용할 프로젝트에 추가 하시면 됩니다.
2. 데이타 구조 선언
이번 예제는 3번째 강좌에서 보여 드렸던 phonebook 예제에서 생일 컬럼을 하나더 추가한 형태로 만들어 보겠습니다.
이름, 전화번호, 성별, 생일
을 가지고 있는 것으로 만들어 보겠습니다.
#include "EditorUnit.h"
데이타 구조를 선언하시 곳에 위와 같이 include를 추가해 주시구요.
typedef struct tagPhonebook {
TPropertyData Colunms[4]; // 0 - 이름, 1 - 전화번호, 2- 성별 , 3 - 생일
} structPhonebook;
데이타 선언은 위와 같이 합니다. Column이 4개 라서 4개짜리 배열로 만들었습니다.
3. VTV 의 기본 Events 구현
기본 Events는 이전에도 계속 말씀 드렸지만,
OnGetNodeDataSize
OnGetText
이구요.
이미지를 출력할 것이라면
OnGetImageIndex
까지 구현해 주시면 됩니다. 이번예제는 이미지는 없습니다 ^^
void __fastcall TForm1::VirtualStringTree1GetNodeDataSize(
TBaseVirtualTree *Sender, int &NodeDataSize)
{
NodeDataSize = sizeof(structPhonebook);
}
OnGetNodeDataSize 는 변경되는 것이 없지요
void __fastcall TForm1::VirtualStringTree1GetText(TBaseVirtualTree *Sender,
PVirtualNode Node, TColumnIndex Column, TVSTTextType TextType,
WideString &CellText)
{
if (!Node)
return;
structPhonebook *pPhonebook = (structPhonebook *)Sender->GetNodeData(Node);
CellText = pPhonebook->Colunms[Column].Value;
}
OnGetText는 배열을 사용하면서 소스가 더 간단해 졌습니다^^
4. VTV의 속성 변경
VTV가 처음 폼에 올려 놓으면 Column 0 만을 선택할 수 있습니다.
그러므로, Column 0을 제외한 다른 Column을 편집하기 위해서는 선택 모드를 변경해 주어야 합니다.
TreeOptions -> SelectionOptions -> toExtendedFocus : true
이 값을 true로 해 주어야 각 컬럼별로 선택할 수가 있습니다.
5. inline 에디터 관련 Events 구현
inline 에디터를 구현하기 위해서는 최소 2개의 Event를 구현해 주서야 하는데요.
OnCreateEditor : 각 셀에서 에디팅이 시작할 때 에디터를 생성해주는 시간을 제공합니다.
OnEditing : 각 셀의 에디팅을 허용할 것인지 말것인지 결정합니다.
OnCreateEditor 이벤트를 구현할때, 에디터의 형식이 ptCombo 일때와 아닐경우가 다른데요.
ptCombo는 콤보박스 형태의 에디팅이 되기 때문에, 콤보박스에 보여질 데이타를 전달해 주어야 합니다.
그래서,
__fastcall TPropertyEditLink(TVirtualStringTree* Tree, TVirtualNode* Node, int Column, TPropertyData* Data, TStringList *combolist);
생성자를 위의 것으로 사용하고, 콤보박스에 보여질 항목을 TStringList로 만들어서 전달해 주어야 합니다.
그외의 경우는 아래의 생성자를 이용하면 됩니다.
__fastcall TPropertyEditLink(TVirtualStringTree* Tree, TVirtualNode* Node, int Column, TPropertyData* Data);
아래에 OnCreateEditor 이벤트를 구현한 예제가 있는데요.
Column 2 에서만 ptCombo로 생성한 예제 입니다.
void __fastcall TForm1::VirtualStringTree1CreateEditor(
TBaseVirtualTree *Sender, PVirtualNode Node, TColumnIndex Column,
IVTEditLink *EditLink)
{
if (!Node) return;
TPropertyEditLink* PropertyLink;
structPhonebook *pPhonebook = (structPhonebook *)Sender->GetNodeData(Node);
if (pPhonebook)
{
if (Column == 2)
{ // ComboBox 형태의 편집을 지원할 경우
TStringList* MyList = new TStringList();
try
{
MyList->Add("남자");
MyList->Add("여자");
PropertyLink = new TPropertyEditLink((TVirtualStringTree*)Sender, Node, Column, &(pPhonebook->Colunms[Column]), MyList);
}
__finally
{
delete MyList;
}
}
else // ComboBox 형태가 아닐경우
PropertyLink = new TPropertyEditLink((TVirtualStringTree*)Sender, Node, Column, &(pPhonebook->Colunms[Column]));
PropertyLink->QueryInterface(__uuidof(IVTEditLink), (void**)EditLink);
}
}
OnCreateEditor 이벤트를 구현해 줍니다.
이 이벤트에 들어 오면, 노드의 데이타를 가져와서
각 컬럼에 해당하는 값 (pPhonebook->Colunms[Column])으로
TPropertyEditLink 클래스를 생성해 주구요. (이 클래스가 EditorUnit.cpp 에 있는 것입니다)
PropertyLink->QueryInterface(__uuidof(IVTEditLink), (void**)EditLink);
를 이용해서, EditLink 파라미터를 채워주면 됩니다.
void __fastcall TForm1::VirtualStringTree1Editing(TBaseVirtualTree *Sender,
PVirtualNode Node, TColumnIndex Column, bool &Allowed)
{
Allowed = false;
if (!Node) return; // only for safety the program !
structPhonebook * pPhonebook = (structPhonebook *)Sender->GetNodeData(Node);
if (pPhonebook)
Allowed = (pPhonebook->Colunms[Column].PropertyTyp != ptNone);
}
OnEditing 이벤트에서 에이터를 허용할 셀을 알려 주는데요.
pPhonebook->Colunms[Column].PropertyTyp 이 ptNone 가 아닌 경우만
Allowed 를 true로 넣어 주는 것입니다.
자 이제 모든 필요 이벤트는 다 만들었구요.
7. 데이타 넣기
데이타를 넣는 버튼을 하나 만들어서
그 버튼이 눌렸을때, 데이타를 넣어 주면 됩니다.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
PVirtualNode Node;
structPhonebook *pPhonebook;
Node = VirtualStringTree1->AddChild(NULL);
if (Node)
{
pPhonebook = (structPhonebook *)VirtualStringTree1->GetNodeData(Node);
pPhonebook->Colunms[0].Value = "볼레롱";
pPhonebook->Colunms[0].PropertyTyp = ptEdit;
pPhonebook->Colunms[0].Changed = false;
pPhonebook->Colunms[1].Value = "02-1234-5678";
pPhonebook->Colunms[1].PropertyTyp = ptEdit;
pPhonebook->Colunms[1].Changed = false;
pPhonebook->Colunms[2].Value = "남자";
pPhonebook->Colunms[2].PropertyTyp = ptCombo;
pPhonebook->Colunms[2].Changed = false;
pPhonebook->Colunms[3].Value = "1970-3-2";
pPhonebook->Colunms[3].PropertyTyp = ptDate;
pPhonebook->Colunms[3].Changed = false;
}
}
위 예에서 보시면, Columns 0 ~ 2 까지는 ptEdit 란 형태로 넣었구요.
Column 3 만 ptDate를 넣었습니다.
실행해 보신 후에 각 셀은 편집은 F2를 누르시거나 마우스로 클릭하고 잠시 기다리면 편집모드로 들어 갑니다.
실행해서 편집해 보세요.
오늘 여기까지 합니다 ^^
아무쪼록 이글이 도움이 되길 바랍니다.