Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Компоненты Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.08.2010, 20:45   #1
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
Сообщение Куда исчезает строка из Node.Data (TreeView)?

Приветствую всех!
Просьба не смеяться, что задача банальная и дочитать до конца.
Допустим,имеется 1 таблица базы со следующими полями:
ID - идентификатор записи, тип строка (например, ID='A');
ParentID - ссылка на ID отца, тип строка.
Name - имя записи,строка.
Проблема в том,что алгоритм не работает,если ID и ParentID строки
(а вот если числа - всё в порядке,хотя по логике действий ему вроде бы
должно быть пофиг числа там или строки).
Вся проблема в строчке
TreeNode:=TreeCompanies.Items.AddCh ildObject(Node ,
qTreeCompanies.FieldByName('Name'). AsString ,
Pointer(qTreeCompanies.FieldByName( 'ID').AsString));
- здесь создаётся объект-потомок узла Node,в Node.Data по идее значение строкового ID должно запомниться,а не запоминается!
Числового запоминается,а строкового нет!
Вот код построения дерева из БД,немного переделал для себя,взято из статьи "DBTreeView своими руками".
Код:
procedure TForm1.ExpandLevel(Node: TTreeNode);
Var i   : Integer;
    TreeNode : TTreeNode;
    ID: string;
Begin
    // Для самого верхнего уровня выбрать только тех,
    // кто не имеет родителей.
    IF Node = nil Then ID:='O'
    Else ID:=String(Node.Data);
    qTreeCompanies.Close;
    showmessage(ID);
    qTreeCompanies.ParamByName('ParentID').AsString:=ID;
    qTreeCompanies.Open;
    // Для каждой строки из полученного набора данных
    // формируем ветвь в TreeView, как дочерние ветки к той,
    // которую мы только что "раскрыли"
    TreeCompanies.Items.BeginUpdate;
    For i:=1 To qTreeCompanies.RecordCount Do
    Begin
       // Запишем в поле Data ветки ее идентификационный номер(ID) в таблице
       TreeNode:=TreeCompanies.Items.AddChildObject(Node ,
                                  qTreeCompanies.FieldByName('Name').AsString ,
                                 Pointer(qTreeCompanies.FieldByName('ID').AsString));
       TreeNode.ImageIndex:=1;
       TreeNode.SelectedIndex:=2;
       // Добавим фиктивную (пустую) дочернюю ветвь только для того,
       // чтобы был отрисован [+] на ветке и ее можно было бы раскрыть
       TreeCompanies.Items.AddChildObject(TreeNode , '' , nil);
       qTreeCompanies.Next;
    End;
    TreeCompanies.Items.EndUpdate;
End;

procedure TForm1.FormCreate(Sender: TObject);
begin
 RebuildTreeCompanies;
end;

procedure TForm1.RebuildTreeCompanies;
begin
    TreeCompanies.Items.Clear;
    // Принудительное раскрытие самого верхнего уровня
    ExpandLevel(nil);
    TreeCompanies.Selected:=TreeCompanies.Items[0];
end;

procedure TForm1.TreeCompaniesExpanding(Sender: TObject; Node: TTreeNode;
  var AllowExpansion: Boolean);
begin
  IF Node = nil Then Exit;
  // Если первая дочерняя ветвь той, которую мы хотим раскрыть, пустая
  // значит это фиктивная ветвь, дерево еще не достраивалось по этой ветви.
  // Удаляем фиктивную ветвь и "разворачиваем" дерево вглубь той ветки,
  // на которой стоим
  IF Node.getFirstChild.Data = nil
  Then Begin
          Node.DeleteChildren;
          ExpandLevel(Node);
       End;
end;
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Старый 06.08.2010, 22:59   #2
Karabash
Форумчанин
 
Регистрация: 26.07.2009
Сообщений: 216
По умолчанию

Запоминать в TTreeNode.Data адрес начала динамического массива (а string - это и есть динамический массив с точки зрения памяти) бессмысленно. Тем более что следом идет оператор qTreeCompanies.Next;
Что за адрес будет в Data предыдущего ноуда после его выполнения?
Вопрос риторический.
Если уж обойтись без строковых идентификаторов никак нельзя, то надо запоминать в Data экземпляры класса, каждый из которых в своем поле (свойстве) будет содержать нужный строковый ID.
Karabash вне форума Ответить с цитированием
Старый 07.08.2010, 00:14   #3
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
Сообщение

Цитата:
Karabash
класс я создал, но ID определяется только для последних узлов.
Когда в TreeNode:=TreeCompanies.Items.AddCh ildObject(Node, qTreeCompanies.FieldByName('Name'). AsString ,Pointer(MyID.id)) пишу просто MyID Delphi
на строчках MyID := TnID.Create();
IF Node = nil Then MyID.ID:='O'
Else MyID.ID:=String(Node.Data);
qTreeCompanies.Close;

ругается Acess Violation in ...

Код:
type
  TnID = class
    ID: string;
  end;
...
procedure TForm1.ExpandLevel(Node: TTreeNode);
Var i : Integer;
    TreeNode : TTreeNode;
    MyID: TnID;
Begin
    // Для самого верхнего уровня выбрать только тех,
    // кто не имеет родителей.
    MyID := TnID.Create();
    IF Node = nil Then MyID.ID:='O'
    Else MyID.ID:=String(Node.Data);
    qTreeCompanies.Close;
         SHOWMESSAGE(MyID.ID);
    qTreeCompanies.ParamByName('ParentID').AsString:=MyID.ID;
    qTreeCompanies.Open;
    // Для каждой строки из полученного набора данных
    // формируем ветвь в TreeView, как дочерние ветки к той,
    // которую мы только что "раскрыли"
    TreeCompanies.Items.BeginUpdate;
    For i:=1 To qTreeCompanies.RecordCount Do
    Begin
        MyID.ID := qTreeCompanies.FieldByName('ID').AsString;
       // Запишем в поле Data ветки ее идентификационный номер(ID) в таблице
       TreeNode:=TreeCompanies.Items.AddChildObject(Node ,
                                  qTreeCompanies.FieldByName('Name').AsString ,
                                  Pointer(MyID.id));
       TreeNode.ImageIndex:=1;
       TreeNode.SelectedIndex:=2;
       // Добавим фиктивную (пустую) дочернюю ветвь только для того,
       // чтобы был отрисован [+] на ветке и ее можно было бы раскрыть
       TreeCompanies.Items.AddChildObject(TreeNode , '' , nil);
       qTreeCompanies.Next;
    End;
    TreeCompanies.Items.EndUpdate;
End;
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Старый 07.08.2010, 00:46   #4
Karabash
Форумчанин
 
Регистрация: 26.07.2009
Сообщений: 216
По умолчанию

Та же ошибка - попытка записать в Data указатель на строку.
Вместо Pointer(MyID.id)) пишем: ..., TObject(MyID)).
При "вытаскивании" строки из Data (как пример):
Код:
if Node.Data <> nil then
  S := TnID(Node.Data).Id;
Karabash вне форума Ответить с цитированием
Старый 07.08.2010, 07:00   #5
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
Сообщение

Стало чуть лучше - но id запоминается для самых последних потомков и
так для всех узлов одинаково. Исходник, скриншот исходной таблицы и дерева:
Код:
...
    MyID := TnID.Create();
    IF Node = nil Then s:='O'
    Else s:=tnid(Node.Data).ID;
    qTreeCompanies.Close;
         SHOWMESSAGE(s);
    qTreeCompanies.ParamByName('ParentID').AsString:=s;
    qTreeCompanies.Open;
    // Для каждой строки из полученного набора данных
    // формируем ветвь в TreeView, как дочерние ветки к той,
    // которую мы только что "раскрыли"
    TreeCompanies.Items.BeginUpdate;
    For i:=1 To qTreeCompanies.RecordCount Do
    Begin
        MyID.id := qTreeCompanies.FieldByName('ID').AsString;
       // Запишем в поле Data ветки ее идентификационный номер(ID) в таблице
       TreeNode:=TreeCompanies.Items.AddChildObject(Node ,
                                  qTreeCompanies.FieldByName('Name').AsString ,
                                  Pointer(TObject(MyID)));
       TreeNode.ImageIndex:=1;
       TreeNode.SelectedIndex:=2;
       // Добавим фиктивную (пустую) дочернюю ветвь только для того,
       // чтобы был отрисован [+] на ветке и ее можно было бы раскрыть
       TreeCompanies.Items.AddChildObject(TreeNode , '' , nil);
       qTreeCompanies.Next;
    End;
    TreeCompanies.Items.EndUpdate;
End;
Изображения
Тип файла: jpg MyError.JPG (32.6 Кб, 58 просмотров)
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Старый 07.08.2010, 08:58   #6
Karabash
Форумчанин
 
Регистрация: 26.07.2009
Сообщений: 216
По умолчанию

Вообще то, последний вопрос на другую тему, а по правилам его надо задавать в другой теме форума.
А чтобы предметно понять в чем дело, логика заполнения Treeview не шибко ясна.
Зачем, например, на 1-м и 2-м уровнях одни и те же наименования? И без "фиктивных" ноудов как-то всю жизнь обходились.
Karabash вне форума Ответить с цитированием
Старый 07.08.2010, 09:48   #7
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
Сообщение

Karabash так в том-то и дело,что при данных значениях не должно быть
Цитата:
на 1-м и 2-м уровнях одни и те же наименования
(таблица слева)
"Фиктивные" ноуды нужны - т.к. заранее я не знаю есть ли вообще потомки или нет,
ну чтоб "+" отображался. Узнаю,что у узла есть потомки - только при раскрытии на OnExpanding.
P.S.
Я и сам бы рад сделать ID и ParentID - числами - меньше мудрежа.
Ну так требование к моей программе такое,что ID и ParentID - строки.
Неймы могут быть одинаковыми,потому и ID - уникален.
А вообще,в рабочей версии у меня ID - строка длиной 22 символа,
которая генерится через GUID_CREATE(). И полей больше...
А в TreeView загружается любая Firebird-таблица,содержащая поля
ID, ParentID, Name ну и GRP - признак группы

Цитата:
Вообще то, последний вопрос на другую тему, а по правилам его надо задавать в другой теме форума.
Так тема-то и к БД и к общим вопросам вроде бы относится, и св-во Node.data опять же. Я думал,что что-то я св-ва TreeView плохо знаю.
Сколько ищу пример, где ID и ParentID - строки, Name - строка и никаких
Level(где хранится сколько у узла потомков) нету.
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Старый 07.08.2010, 09:55   #8
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
По умолчанию

Приношу извинения, что тема щас немного не соответствует разделу - так дело-то
в строчке TreeCompanies.Items.AddChildObject( Node ,
qTreeCompanies.FieldByName('Name'). AsString ,
Pointer(TObject(MyID)));
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Старый 07.08.2010, 10:23   #9
Karabash
Форумчанин
 
Регистрация: 26.07.2009
Сообщений: 216
По умолчанию

Цитата:
"Фиктивные" ноуды нужны - т.к. заранее я не знаю есть ли вообще потомки или нет,
Как это "заранее я не знаю"? А "таблица слева"? В таблице базы все расписано и очень хорошо известно какие ноуды к каким принадлежат.
По-мне так надо выполнить один запрос к таблице и по результату построить TreeView. Без "мудрежа".
Если СУБД Firebird, то конструкция qTreeCompanies.RecordCount из области фантастики.
Академический прием "сканирования" полученного от запроса результата выглядит в общем случае так:
Код:
qTreeCompanies.Open;
while not qTreeCompanies.Eof do begin
  //операторы, работающие с текущей записью
  qTreeCompanies.Next;
end;
qTreeCompanies.Close;
Karabash вне форума Ответить с цитированием
Старый 07.08.2010, 10:47   #10
Alexei91
Заблокирован
Форумчанин
 
Аватар для Alexei91
 
Регистрация: 30.12.2009
Сообщений: 544
Сообщение

Цитата:
Как это "заранее я не знаю"? А "таблица слева"?
Не в том смысл. Принцип действия всего этого кода такой:
1) Сначало формируются корневые элементы (со значением ParentID='O' или '0000000000000000000', если хотите).
2) При раскрытии 1-й из веток дерева вновь запускается процедура ExpandLevel,где ей передаётся выбранный Node.
3)Тут уже определяются потомки этого Node и фиктивная ветвь удаляется,
ветка раскрывается...
В общем посмотрите http://http://www.delphikingdom.com/...?catalogid=488 и попробуйте запустить этот пример,
когда у вас ID и ParentID строки,а не числа. Работает???

P.S.

Про while not qTreeCompanies.Eof do - я знаю, "пока не кончились записи в запросе делать то-то".
Так и RecordCount - тож есть, количество записей,кот. возвращает запрос Query.
Темы для WordPress. Русские WordPress шаблоны
Alexei91 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Куда отследить куда утекает память? TwiX Общие вопросы Delphi 6 02.03.2010 03:10
Исчезает Date and Time Picker! Klim Bassenger Microsoft Office Excel 17 24.11.2009 18:25
запустится и маментально исчезает в не куда gaka1995 Общие вопросы C/C++ 8 24.08.2009 15:37