TVirtualStringTree

Модератор: Модераторы

TVirtualStringTree

Сообщение Ustas » 05.07.2017 17:01:44

Доброго дня!

Искал альтернативу TViewList, народ в восторге от TVirtualStringTree. Решил попробовать. :cry:
Не знаю, может что то не догоняю, но чего то не срастается.
Не могу заполнить данными, Везде приводят примеры, типа:
Код: Выделить всё
  NewNode := VT.AddChild(nil);
  NewPhone := VT.GetNodeData(NewNode);
  if Assigned(NewPhone) then
    with NewPhone^ do
    begin
      Name := EdName.Text;
      Phone := EdPhone.Text;
    end;

У меня вообще в условие на заходит.
Кто в курсе - разъясните. Может какое слово заветное надо сказать?
Ustas
постоялец
 
Сообщения: 145
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром

Re: TVirtualStringTree

Сообщение vada » 05.07.2017 18:10:36

Оптимизируешь? В параметрах проекта.
Аватара пользователя
vada
энтузиаст
 
Сообщения: 635
Зарегистрирован: 14.02.2006 13:43:17

Re: TVirtualStringTree

Сообщение Лекс Айрин » 05.07.2017 18:14:18

Если я правильно помню, крышечка лишняя. И вообще, попробуй сначала без оператора with
Ustas писал(а):У меня вообще в условие на заходит.

Вообще, странный подход... Сначала добавляется пустая запись, потом она позиционируется в дереве(если я правильно понял), а потом заполняется... Имхо, перепутан порядок. Вполне возможно, что запись игнорируется уже на первой строчке, Попробуй сначала "собрать" ноду, а потом добавлять.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 3727
Зарегистрирован: 19.02.2013 16:54:51

Re: TVirtualStringTree

Сообщение Ustas » 05.07.2017 21:36:32

vada писал(а):Оптимизируешь? В параметрах проекта.

А подробнее...
Лекс Айрин писал(а):Сообщение Лекс Айрин » 05.07.2017 18:14:18

Ясности мне не прибавилось. Подобные примеры во всех описаниях, я даже могу привести пример из "официальной" документации.

Мне непонят что я делаю не так.
Ustas
постоялец
 
Сообщения: 145
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром

Re: TVirtualStringTree

Сообщение Лекс Айрин » 05.07.2017 22:21:11

Ustas, подозреваю, что ты смотришь описания для дельфовского компонента. А диалекты fpc и delphi немного различаются.

Как минимум, тебе надо будет посмотреть исходники самого компонента. Вообще, я глянул и ахнул.
Как минимум, компонент собран в режиме дельфи, не понятно где функции работы с элементами... в общем, создалось впечатление недоделки.

Ustas писал(а):Мне непонят что я делаю не так.


подозреваю, что добавление пустой ноды может не производиться. А может, все проще и тебе надо просто переписать код вот так:
Код: Выделить всё
NewNode := VT.AddChild(nil);
  NewPhone := VT.GetNodeData(NewNode);
  if Assigned(NewPhone) then
    with NewPhone do
    begin
      Name := EdName.Text;
      Phone := EdPhone.Text;
    end;

Надо еще знать как точно определены NewNode и NewPhone.
Можно и переключиться в режим дельфи. Попробуй все же убрать with -- он тоже может некорректно обрабатывать операцию разыменования. (имхо, он него иногда больше вреда чем пользы)
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 3727
Зарегистрирован: 19.02.2013 16:54:51

Re: TVirtualStringTree

Сообщение olegy123 » 05.07.2017 23:03:06

Ustas писал(а):У меня вообще в условие на заходит.
Кто в курсе - разъясните. Может какое слово заветное надо сказать?

VirtualTreeView - заточена на отображение списков/деревьев. Когда другие TListView, TStringGrid и др - представляют модель где данные уже представляют конкретный тип (String,Integer,CheckBox..)
то в VirtualTreeView вся работа идет с узлами и их связями.. а что показывать и как фильтровать - это задача программиста. Каждый узел(Node) имеет поле Data это тип Pointer.. туда VirtualTreeView выделяет память и помещает любые пользовательские данные.
Код: Выделить всё
TPhone = record
   Name:String;
   Number:String;
end;


сначала при работе, говорим какой размер нода(только пользовательские данные) VirtualStringTree1.NodeDataSize:=SizeOf(TPhone);
NewNode := VT.AddChild(nil); - добовляет узел. nil -значит это Root.
---- это все что нужно по самому минимуму, чтобы VirtualTreeView взлетел.
Теперь вы должны записать какие то данные в NewPhone^:
NewPhone := VT.GetNodeData(NewNode); - тут происходит выделение памяти из кучи размером NodeDataSize .. внутри происходит такое : NewNode.Data=GetMem(SizeOf(TPhone)); и возращает указатель на память в NewPhone:=NewNode.Data.
Допустим это будет номер телефона и имя.. NewPhone^.Number:='+7.......';NewPhone^.Name:='Petya';
но это не все.. Нужно чтобы TVirtualStringTree вывел нужный текст в нужную позицию, для этого есть событие OnGetText
Код: Выделить всё
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var pPhone:^TPhone;
begin
   pPhone:=Sender.GetNodeData(Node); // -- получаем указатель на структуру TPhone в памяти.
   case Column of
    0:CellText:=pPhone^.Name; // - колонка первая(индекс=0) вносим поле Имя.
    1:CellText:=pPhone^.Number; // - колонка вторая(индекс=1) вносим поле Номер.
   end;
end;


http://devdelphi.ru/?p=230

Такой подход позволяет высоко абстрагироваться VirtualTreeView от данных. Он только предлагает общие механизмы для работы со списками/деревьями/таблицами.

Добавлено спустя 13 минут 57 секунд:
С VirtualTreeView можно писать торрентрекеры, всякие многопоточные анализаторы, работу с БД и многое другое, в отличее от всякие TListView, TStringGrid - к данным он не имеет прямого отношение... просто когда надо вывести на экран он спрашивает, мол а как нужно выводить..
olegy123
постоялец
 
Сообщения: 463
Зарегистрирован: 25.02.2016 12:10:20

Re: TVirtualStringTree

Сообщение sign » 06.07.2017 07:22:13

Загрузка прайса.
Работающая процедура.
Код: Выделить всё
procedure TDM.LoadPrice(Sender: TBaseVirtualTree);
var D, P: PVirtualNode;
    Data: PPrice;
    i : Integer;
begin
  if not Assigned(Sender) then Exit;
  Sender.Clear;
  LoadTitle(Sender);
  if Param.Date = 0 then Param.Date := Now;
  InitParam(DM.q_Price, VarArrayOf(['pVisible', Ord(Param.Price_Is_Show), 'pDeleted', Ord(Param.Price_Is_Deleted), 'pDate', Param.Date]), tsOpen);
  i := 1;
  while not DM.q_Price.Eof do begin
    D := FindTitleProduct(Sender, DM.q_PriceGroup.AsInteger);
    P := Sender.AddChild(D);
    Data := Sender.GetNodeData(P);
    Data^ := TPrice.Create;
    Data^.Load;
    q_Price.Next;
    i += 1;
  end;
  q_Price.Close;
  FocusVirtualST(Sender, FindRecProduct(Sender, Param.RecPrice));
end;


Добавлено спустя 4 минуты 35 секунд:
Обязательно указать размер данных в OnGetNodeDataSize.
Обязательно заполнить OnGetText
У меня:
Код: Выделить всё
procedure TfFirms.vsPriceGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var Data:  PPrice;
begin
  if not Assigned(Node) then begin
    CellText := '-';
    Exit;
  end;
  Data := Sender.GetNodeData(Node);
  if Data^.Is_Title then
    if Column = clPriceName then CellText := Data^.Name
    else CellText := ''
  else
    case Column of
      clPriceName:   CellText := Data^.Name;
      clPriceOffice: CellText := IntToSTrDef(Data^.CountOffice, '')
      clPriceDC:     CellText := IntToSTrDef(Data^.CountSklad, '');
      clPriceAllDC:  CellText := IntToSTrDef(Data^.CountOffice + Data^.CountSklad + Data^.CountMove, '');
      clPriceAkk:    CellText := IntToStrDef(Data^.CountAkk, '');
      clPriceIC:     CellText := IntToSTrDef(Data^.CountIC, '');
      clPriceDelta:  CellText := IntToSTrDef(Data^.CountDelta, '');
      clPriceBall:   CellText := IntToSTrDef(Data^.Ball, '', FF2);
      clPriceCost:   CellText := CurrToStrF(Data^.CostConsult, ffCurrency, 0);
      clPriceMove:   CellText := IntToSTrDef(Data^.CountMove, '');
      clPriceZakaz:  CellText := IntToSTrDef(Data^.CountZakaz, '');
      clPricePos:    CellText := Format('%d/%d', [Data^.CountRow, Data^.CountShelf]);
    end;
end;

И т.д.
sign
энтузиаст
 
Сообщения: 857
Зарегистрирован: 30.08.2009 09:20:53

Re: TVirtualStringTree

Сообщение Ustas » 06.07.2017 14:04:32

[quote="sign"]

Не пойму, как мои данные попадают в TVirtualStringTree:

Код: Выделить всё
var D, P: PVirtualNode;
    Data: PPrice;
    i : Integer;

. . .

    D := FindTitleProduct(Sender, DM.q_PriceGroup.AsInteger);
    P := Sender.AddChild(D);
    Data := Sender.GetNodeData(P);
    Data^ := TPrice.Create;
    Data^.Load;

Наверное, TPrice - это целый класс.
До меня никак не дойдет, где и как, данные со структурой (условно)
Код: Выделить всё
TPhone = record
   Name:String;
   Number:String;
end;

загрузить в TVirtualStringTree.
Ustas
постоялец
 
Сообщения: 145
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром

Re: TVirtualStringTree

Сообщение sts » 06.07.2017 15:13:39

чую мы теряем юстаса...
там демки должны быть, пошукайте
вот набросал навскидку (не компилил)
Код: Выделить всё
TPhone = record
   Name:String;
   Number:String;
end;
PPhone = ^TPhone;

  TForm1 = class(TForm)
    qrPhones: TDataSet????;
    edPhones: TVirtualStringTree;
    procedure edPhonesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
    procedure edPhonesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
...........

настроить дерево (dfm\lfm)
edPhones.OnFreeNode = edPhonesFreeNode
edPhones.OnGetText = edPhonesGetText
в edPhones.Columns создать две колонки
включить Header
edPhones.Header.Options = [..........., hoVisible]

в FormCreate надо задать edPhones.NodeDataSize := SizeOf(TPhone);
загрузка дерева
Код: Выделить всё
procedure TForm1.LoadTreePhones;
var
  Node: PVirtualNode;
  Data: PPhone;
begin
  qrPhones.First;
  while not qrPhones.Eof do begin
    Node := edPhones.AddChild(ParentNode);
    Data := edPhones.GetNodeData(Node);

    Initialize(Data^); //потому что строки в рекорде
    Data.Name:= qrPhones.FieldByName(???).AsString;
    Data.Number:= qrPhones.FieldByName(???).AsString;
    qrPhones.Next;
  end; 
end;

procedure TForm1.edPhonesGetText(
  Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType; var CellText: WideString);
var
  Data : PPhone;
begin
  if Assigned(Node) then begin
    Data := edPhones.GetNodeData(Node);
    if Column = 0 then begin
      if TextType = ttNormal then CellText:= Data.Name;
    end else if Column = 1 then begin
      if TextType = ttNormal then CellText:= Data.Number;
    end;
  end;
end;

procedure TForm1.edPhonesFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data : PPhone;
begin
  if Assigned(Node) then begin
    Data := edPhones.GetNodeData(Node);
    Finalize(Data^); //потому что строки в рекорде
  end;
end;
sts
постоялец
 
Сообщения: 222
Зарегистрирован: 04.04.2008 12:15:44
Откуда: Тольятти

Re: TVirtualStringTree

Сообщение olegy123 » 06.07.2017 15:34:52

Ustas писал(а):Не пойму, как мои данные попадают в TVirtualStringTree:

TVirtualStringTree - работает с узлами (Node), может выводить списком, таблицей, и деревом..
у него есть свой рабочий класс PVirtualNode (он же Node)..
PVirtualNode могут друг за друга цепляться, таким образом получаются цепочки, деревья.. TVirtualStringTree читает эту нить.

у PVirtualNode есть волшебное поле Data - оно нужно для того чтобы указывать на пользовательские данные (String,Integer, record.. class, TPhone);

Node:=TVirtualStringTree.AddChild(ParentNode); -- Node цепляется к ParentNode..
Phone := Sender.GetNodeData(Node); -- читает у Node поле Data, если оно nil то выделяет в памяти(куче) объем равный NodeDataSize. теперь Data указывает на память где размещено новый [TPhone]
Phone^.Name ... теперь можно работать с данным участком памяти..

Добавлено спустя 7 минут 44 секунды:
Ustas писал(а):До меня никак не дойдет, где и как, данные со структурой (условно)

Код: Выделить всё
TPhone = record
   Name:String;
   Number:String;
end;

- это описание структуры типа Record у его есть поля [Name,Number]
- теперь компилятор знает о TPhone и знает его размер SizeOf(TPhone)

мы указываем что пользовательские данные в ноде [Node.Data]должны иметь размер SizeOf(TPhone)
VirtualStringTree.NodeDataSize:=SizeOf(TPhone);

Phone := Sender.GetNodeData(Node); тут идет определение Node.[Data] поля, оно NIL - тогда: выделяет память размером SizeOf(TPhone) и указывает где оно в [Phone].
теперь Phone рзмещено в памяти и можно с ним работать (читать/писать)
olegy123
постоялец
 
Сообщения: 463
Зарегистрирован: 25.02.2016 12:10:20

Re: TVirtualStringTree

Сообщение Ustas » 06.07.2017 17:06:30

sts писал(а): sts » 06.07.2017 15:13:39
чую мы теряем юстаса...

Мне в отпуск надо... И вообще, мне работать никак нельзя, я от нее устаю... :oops:

Все перепроверил, но похоже данные, все таки, в TVirtualStringTree не загружаются. Я в шоке...

З.Ы.

Загрузил, только появился нюанс. Определение размера данных (VST.NodeDataSize := SizeOf(TPingNode)) по структура, типа:
Код: Выделить всё
TPhone = record
   Name:String;
   Number:String;
end;

дает неправильны размер. Поэтому в TVirtualStringTree ничего не пишется. Если задать структуру данных так:
Код: Выделить всё
TPhone = record
   Name:String[10];
   Number:String[50];
end;

то все получается.

И еще, не могу задать в программе:
Код: Выделить всё
VST.Width := ???
VST.Height := ???
Ustas
постоялец
 
Сообщения: 145
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром

Re: TVirtualStringTree

Сообщение Ustas » 14.07.2017 12:07:16

Добил я это дело, всем: Благодарю!
Ustas
постоялец
 
Сообщения: 145
Зарегистрирован: 19.10.2009 14:58:10
Откуда: г.Муром


Вернуться в Компоненты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru