Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Подскажите как сделать вывод базы данных в виде дерева [D7]


Страницы:   1 2

ceval ©   (2006-06-06 15:07:00) 

Здравствуйте
Подскажите как сделать вывод базы данных в виде дерева
например есть файл mdb и из него будут браться данныя
что то вроде этого (Главная - Отдел- Подразделения)
[]
|
[]___
|  |  |
[] [][]


rar   (2006-06-09 18:51:00) [1]


> Вот это плохо. Раньше или позже грабли будут точно. Если
> в таблицах не более нескольких тысяч записей можно не хранить
> кол-во, а просто динамически запрашивать.
> <Цитата>

Если динамически делать запрос, тогда вообще зачем это поле :-))

Оно и предназначено для рисования "плюсика" в TreeView


atruhin   (2006-06-08 21:23:00) [2]


> Правда пришлось это делать без триггеров.

Вот это плохо. Раньше или позже грабли будут точно. Если в таблицах не более нескольких тысяч записей можно не хранить кол-во, а просто динамически запрашивать.


rar   (2006-06-08 21:14:00) [3]

Что то я не совсем понял триггеры.
Поле HAS_CHILDREN что имеет только значения 0 и 1 что ли

Я делаю по другому, прибавляю или удаляю единицу и в этом поле храниться количество дочерних элементов

Правда пришлось это делать без триггеров.

С ними ругается что таблица находиться в изменении у меня СУБД ORACLE


Ega23   (2006-06-08 17:35:00) [4]


> При всем при том ты так и не сподобился объяснить, как ты
> умудряешься вывести "в виде дерева" именно базу данных,
> а не некий НД)
>


Ну конечно НД, а не "базу данных". Хотя если сильно постараться, то можно написать запрос, который выведет ПОЛНОЕ содержимое БД в один НД.


> Про "Не ври" может возьмешь слова обратно ?


Если тебя это успокоит, то пожалуйста - беру свои слова обратно.


Сергей М.   (2006-06-08 16:58:00) [5]


> Ega23 ©   (08.06.06 16:24) [26]


При всем при том ты так и не сподобился объяснить, как ты умудряешься вывести "в виде дерева" именно базу данных, а не некий НД)

Про "Не ври" может возьмешь слова обратно ?


Ega23   (2006-06-08 16:24:00) [6]


> Я обычно делаю дерево так:
> Беру обычный TTreeView.
> На событие OnCollapse удаляю все дочерние Nodes текущего
> Node.
> На событие OnExpand создаю дочерние Nodes одним уровнем
> ниже для распахиваемого пункта, обращаясь всякий раз SQL-
> запросом к базе данных.


Это всё, конечно, замечательно. Но только в том случае, когда не нужно дерево с другими DB-контролами синхронизировать.
А у меня задача - есть один набор данных. Есть DBGrid, в котором отражены некоторые поля этого НД. Есть дерево, где все записи этого НД выведены в виде иерархической структуры. И есть картинка, на которой эти объекты изображены.
Ткнулся на запись в гриде - выбрался соответствующий узел в дереве - подсветилась соответствующая картинка на графике.
Сделал принудительный Locate НД "извне" - во всех трёх контролах установились правлиьные текущие объекты.
Выбрал картинку на графике - всё то же самое.
Самое "западло" в этой ситуации - что компановка программы может быть разная. Может быть только дерево. Или только графика. Или только грид. Или и графика и дерево. И т.д.


Сергей М.   (2006-06-08 16:05:00) [7]


> kaif ©   (07.06.06 21:53) [24]


При всем к тебе, Ашот, уважении не кажется ли тебе, что ты (с твоим-то опытом !) мог бы объяснить Авторпу, что "вывод базы данных в виде дерева" - это нонсенс ?


kaif   (2006-06-07 21:53:00) [8]

Извиняюсь, все напутал в текстах триггеров:

В триггере AFTER DELETE делаю:
IF (NOT EXISTS(SELECT ID FROM MyTable WHERE PARENT_ID = OLD.PARENT_ID) THEN
UPDATE MyTable SET HAS_CHILDREN = 0 WHERE ID = OLD.PARENT_ID;

В триггере AFTER INSERT делаю:
UPDATE MyTable SET HAS_CHILDREN = 1   WHERE ID = NEW.PARENT_ID;

В триггере AFTER UPDATE делаю и то и другое вместе:
IF (OLD.PARENT_ID <> NEW.PARENT_ID) THEN
BEGIN
IF (NOT EXISTS(SELECT ID FROM MyTable WHERE ID = OLD.PARENT_ID) THEN
UPDATE MyTable SET HAS_CHILDREN = 0 WHERE ID = OLD.PARENT_ID;
UPDATE MyTable SET HAS_CHILDREN = 1 WHERE ID = NEW.PARENT_ID;
END


kaif   (2006-06-07 21:50:00) [9]

Я обычно делаю дерево так:
Беру обычный TTreeView.
На событие OnCollapse удаляю вседочерние Nodes текущего Node.
На событие OnExpand создаю дочерние Nodes одним уровнем ниже для распахиваемого пункта, обращаясь всякий разSQL-запросом к базе данных. При создании дочернего Node, если пункт имеет в базе дочерние (HAS_CHILDREN = 1), то устанавливаю для таких принудительно свойство Node.HasChildren := True.
При запуске программы создаю корневой Node, запросив одну строку из базы данных.
ID храню в свойстве Node.Data, явно приведя к Pointer.

Структуру таблицы делаю примерно такую:
ID INTEGER,
PARENT_ID INTEGER,
NAME VARCHAR(50),
HAS_CHILDREN INTEGER

В триггере AFTER DELETE делаю:
IF (NOT EXISTS(SELECT ID FROM MyTable WHERE ID = OLD.PARENT_ID) THEN
UPDATE MyTable SET HAS_CHILDREN = 0;

В триггере AFTER INSERT делаю:
UPDATE MyTable SET HAS_CHILDREN = 1;

В триггере AFTER UPDATE делаю и то и другое вместе:
IF (OLD.PARENT_ID <> NEW.PARENT_ID) THEN
BEGIN
 IF (NOT EXISTS(SELECT ID FROM MyTable WHERE ID = OLD.PARENT_ID) THEN
 UPDATE MyTable SET HAS_CHILDREN = 0;
 UPDATE MyTable SET HAS_CHILDREN = 1;
END

Можно, конечно, обойтись и без триггеров и без поля HAS_CHILDREN, сделав такой запрос к базе, который вернет признак наличия потомков у объектов данного уровня. Но моя практика показывает, что удобнее все же иметь такое поле. Это упрощает жизнь и в других ситуациях.

Кайф этого подхода (каждый раз перезапрашивать ветвь) в том, что дерево легко пересвечивать после вставки в него нового пункта. Достаточно вызвать Collapse и Expand родительской ветви.

А вообще я сохраняю в базе данных (для каждого юзера) степень раскрытости его папок просто в виде строки ID, разделенных запятой. При отображении дерева в первый раз я считываю эту строку из базы и просто отыскиваю последовательно Node-ы, у которых в Data лежит следующий ID - затем вызываю Expand для этого Node-а. А при закрытии формы сканирую дерево и формирую строку из ID для тех Nodes[i], которые сейчас распахнуты (HasChildren = True). И сохраняю эту строку в базе данных.

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


ceval   (2006-06-07 20:22:00) [10]

спасиба буду разбираться
может стоит попробывать тогда использываться какой нибудь DBTreeView и db


ANB   (2006-06-06 17:50:00) [11]


> Ega23 ©   (06.06.06 15:26) [7]

Это ежели в mdb гарантировано база mssql и не кривая. :)


Amoeba   (2006-06-06 17:16:00) [12]


> Этой заразы полно: dxDBTreeList, cxDBTreeView, ehDBTree
> (типа того).

Даже в JVCL есть (взят из RALib). Очень приличный компонент, позволяет все редактирование непосредственно в дереве, включая перемещение ветвей. С моей подачи в 3-й версии библиотеки то пофиксили один нехороший баг.


Ega23   (2006-06-06 17:01:00) [13]


> Но он принес больше пользы в плане ООП.


Ну, скажем, мне он помог понять тонкости работы DB-Aware компонентов в Delphi.


Курдль   (2006-06-06 16:50:00) [14]


> Вот на дереве и тренировался...


Да уж... Я как-то тоже тренировался. Осваивал двойную буферизацию, drag-n-drop скроллирование и прочую хрень. Ничего так контрол получился - без тормозов и глюков. Но он принес больше пользы в плане ООП. Столько типов и коллекций в одном компоненте мне раньше не приходилось делать...


Ega23   (2006-06-06 16:32:00) [15]


> А знаменитую функцию IncDay() тоже ты написал


Нет. Но она у меня есть.


> Этой заразы полно: dxDBTreeList, cxDBTreeView, ehDBTree
> (типа того).


Первое денег стоит. Немалых. Про вторые - ничего не знаю. А технологию создания ДБ-компонентов всё равно надо было поднимать: уж больно специфичные компоненты получались. Вот на дереве и тренировался...


Курдль   (2006-06-06 16:16:00) [16]


> А имел ввиду, что написал компонент TDBTreeView.


А знаменитую функцию IncDay() тоже ты написал? :)
Этой заразы полно: dxDBTreeList, cxDBTreeView, ehDBTree (типа того).


Ega23   (2006-06-06 16:12:00) [17]


> Если ты имеешь в виду, что нарисуешь деревянно-упорядоченный
> запрос (не функцию и не на оракле), то мне тоже интересно.
>


Я с MSSQL работаю. А имел ввиду, что написал компонент TDBTreeView. Для работы ему надо задать все эти поля [10] + TDataSource.


Сергей М.   (2006-06-06 16:12:00) [18]


> Ega23 ©   (06.06.06 15:53) [10]


Запросы эти сам строй) .. Оно мне надо ?

До кучи сразу объясняй автору, чем отличается база данных от табличных (и иных) объектов в ее составе.


Курдль   (2006-06-06 16:06:00) [19]

Думаю, что Сергей М. ©   (06.06.06 15:43) [8]имел в виду то, что результат запроса будет линейный, как ни старайся. Т.е. просто набор записей :(
Если ты имеешь в виду, что нарисуешь деревянно-упорядоченный запрос (не функцию и не на оракле), то мне тоже интересно. Можно без картинок :)


Ega23   (2006-06-06 16:02:00) [20]


> И шо оно туда выдаст? Таки настоящие деревья? 8-()

DisplayField - это то, что в TTreeNode.Text будет
ImageField - поле с BLOB, пока bmp 16х16. Будет "присовокуплена к узлу" дерева.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо