문제

이전에 게시 된 질문의 업데이트 버전입니다. 이전 제목은 Delphi의 Virtual TreeView에서 색인 별 노드 선택.]

하루의 더 나은 부분 이후, 나는 간단한 두 테이블 데이터 인식 패션으로 가상 트리 뷰 구성 요소 (강력하지만 복잡한)가 작동한다고 생각합니다.

이제 최상위 노드의 1,512 번째 (예 :)를 단순히 선택하려고합니다. 나는 첫 번째 최상위 노드를 얻은 다음 getnextsibling 1,511을 루프로 호출하는 것 외에는 다른 방법을 볼 수 없습니다.

이것은 불필요하게 관련된 것 같습니다. 더 간단한 방법이 있습니까?

업데이트

내 트리의 노드를 초기화하려면 데이터베이스 액세스가 필요하기 때문에 시작시 모든 노드를 초기화하는 것은 실현할 수 없습니다. 사용자가 이미 선택한 레코드가없는 양식으로 시작하면 괜찮습니다. 사용자가 트리 주위를 스크롤함에 따라 현재 창을 트리에 표시하기에 충분한 노드가 채워져 있으며 성능은 정상입니다.

사용자가 이미 선택한 데이터베이스 레코드로 대화 모드에서 양식을 시작하면 사용자가 양식을보기 전에 해당 노드로 트리를 전진시켜야합니다. 레코드가 나무 끝에있는 경우 첫 번째 노드에서 트리를 걸을 때 10 초가 걸릴 수 있기 때문에 이것은 문제입니다. getnextibling ()을 얻을 수있을 때마다 대부분의 노드가 사용자에게 표시되지 않더라도 노드가 초기화됩니다. 나는 해당 노드의 초기화를 사용자에게 볼 수있는 지점으로 연기하는 것을 선호합니다.

레코드를 선택하지 않고 트리를 열고 수직 스크롤 막대를 사용하여 단일 작업에서 트리 중간으로 이동하면 올바른 노드가 표시되기 때문에 더 나은 방법이 있어야한다는 것을 알고 있습니다. 내가 건너 뛰는 노드를 초기화 할 필요없이.

이것은 레코드를 선택한 상태에서 트리를 열 때 달성하고 싶은 효과입니다. 나는 가고 싶은 노드의 인덱스를 알고 있지만 인덱스별로 갈 수 없다면 트리에서 바이너리 검색을 수행 할 수 있습니다. 나무의 중간).

또는 아마도 그리드를 가로 지르면서 중간 노드를 초기화 할 수없는 트리 뷰에 만들 수있는 상태 설정이있을 수 있습니다. 시작/종료 업데이트를 시도했지만 트릭을 수행하지 않는 것 같습니다.

도움이 되었습니까?

해결책

초기화하지 않고 노드의 형제를 얻으려면 NextSibling 포인터 (선언 참조 TVirtualNode).

다른 팁

트리 제어는 컴퓨터 과학 수업에서 배울 수있는 고전적인 나무처럼 구성됩니다. 나무의 뿌리에서 1512 번째 어린이로가는 유일한 방법은 링크를 하나씩 걷는 것입니다. 직접 수행하든 트리 제어 방법을 사용하든 여전히 그렇게해야합니다. 컨트롤 자체에 제공된 내용이 보이지 않으므로이 기능을 사용할 수 있습니다.

function GetNthNextSibling(Node: PVirtualNode; N: Cardinal;
  Tree: TBaseVirtualTree = nil): PVirtualNode;
begin
  if not Assigned(Tree) then
    Tree := TreeFromNode(Node);
  Result := Node;
  while Assigned(Result) and (N > 0) do begin
    Dec(N);
    Result := Tree.GetNextSibling(Result);
  end;
end;

자신이 자주하는 것을 발견하면 자신을 색인으로 만들고 싶을 수도 있습니다. 배열을 만드는 것만 큼 간단 할 수 있습니다. PVirtualNode 포인터와 모든 최상위 값을 저장하므로 1512 번째 값을 읽을 수 있습니다. 트리 컨트롤은 이러한 데이터 구조 자체가 필요하지 않으므로 유지 관리하지 않습니다.

당신은 또한 재고 할 수도 있습니다 그런 데이터 구조가 필요합니다. 당신은 ~ 진짜 그런 색인으로 노드에 액세스해야합니까? 또는 대신 A를 유지할 수 있습니다 PVirtualNode 포인터, 트리의 나머지 노드와 관련된 위치는 더 이상 중요하지 않습니다 (예 : 원하는 노드에 대한 참조를 잃지 않고 정렬 할 수 있음)?

업데이트에 작성하십시오.

레코드를 선택하지 않고 트리를 열고 수직 스크롤 막대를 사용하여 단일 작업에서 트리 중간으로 이동하면 올바른 노드가 표시되기 때문에 더 나은 방법이 있어야한다는 것을 알고 있습니다. 내가 건너 뛰는 노드를 초기화 할 필요없이.

수직 스크롤은 클라이언트 위치에 표시되는 논리적 y 좌표가 변경되기 때문에 여기에는 차이가 있습니다. 컨트롤은 스크롤 바 위치 및 스크롤 범위에서 오프셋을 계산 한 다음 컨트롤 상단에서 보이는 노드를 계산합니다. 노드는보기로 스크롤 된 영역을 페인트해야 할 때만 다시 초기화됩니다.

노드의 y 좌표가있는 경우 호출하여 노드 포인터를 얻을 수 있습니다.

function TBaseVirtualTree.GetNodeAt(X, Y: Integer; Relative: Boolean;
  var NodeTop: Integer): PVirtualNode;

노드의 Y 좌표는 이전의 모든 가시 노드의 높이의 합입니다. 노드가 붕괴되지 않았다고 가정하면 (따라서 평평한 레코드 목록이거나 하위 노드가있는 모든 노드가 확장 되었음) 모두 기본 높이가 쉽습니다. 이 코드는 좋은 출발점이어야합니다.

procedure TForm1.SelectTreeNode(AIndex: integer; ACenterNodeInTree: boolean);
var
  Y, Dummy: integer;
  Node: PVirtualNode;
begin
  Y := Round((AIndex + 0.5) * VirtualStringTree1.DefaultNodeHeight);
  Node := VirtualStringTree1.GetNodeAt(0, Y, False, Dummy);
  if Node <> nil then begin
    Assert(Node.Index = AIndex);
    VirtualStringTree1.ScrollIntoView(Node, ACenterNodeInTree);
    VirtualStringTree1.Selected[Node] := True;
    VirtualStringTree1.FocusedNode := Node;
  end;
end;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top