![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Подскажите как сделать вывод базы данных в виде дерева [D7]
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. Будет "присовокуплена к узлу" дерева.