Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2005.08.28;
Скачать: [xml.tar.bz2];

Вниз

Господа, как можно "привязать" к TTreeNode номер записи   Найти похожие ветки 

 
mmms   (2005-07-11 08:52) [0]

Т.е. предположим есть ветка в TTreeView "Продукты", от нее дочерние ноды "Колбаса", "Хлеб" и т.п. Нужно, чтобы юзер кликнул на "Хлеб", узнать, какой ID записи у "Хлеб", TTreeView заполняю записями из БД. Можно ли TTreeNode заполнить кроме Значениями ещё и скрытые параметры у каждого значения, например как Tag у многих компанетов, и потом, при клике на строку, определять этот параметр, а там всего цифровой код товара (по нему далее вся работа и идет).

Или, как вариант, по LIKE определять ID выбранной строки, но это лишняя нагрузка на БД, т.к. даже скольжение по TTreeView создаст множество запросов к серверу... хотя конечно, ID методом LIKE, по названию, можно не постоянно определять при скольжении, а например при двойном клике не этом товаре.

Т.е. вопрос, можно ли как то рядом с позицией в TTreeView "вбивать" ее код.


 
k2 ©   (2005-07-11 08:54) [1]

node.data


 
mmms   (2005-07-11 09:00) [2]

Можно ли данного примера показать, заполняюю этой процедурой..


{ **** UBPFD *********** by delphibase.endimus.com ****
>> Процедура заполнения компонента TTreeView данными из TDataSet-совместимой выборки

Процедура заполнения компонента TTreeView данными из TDataSet-совместимой
выборки типа: idNode int, idParentNode int, cNodeName varchar, ...

Важно: корневой узел дерева должен быть первой записью выборки.

Зависимости: Windows, SysUtils, DB, ComCtrls
Автор:       Delirium, Master_BRAIN@beep.ru, ICQ:118395746, Москва
Copyright:   Master BRAIN (Delirium)
Дата:        18 октября 2002 г.
***************************************************** }

procedure FillTree(Tree: TTreeView; Query: TDataSet; idNode, idParent,
 cNodeName: string);
var
 i: integer;
begin
 // Корневой узел, должен быть первым в выборке Query
 Query.First;
 Tree.Items.Clear;
 Tree.Items.AddObject(nil, Query.FieldByName(cNodeName).AsString,
   Pointer(Query.FieldByName(idNode).asInteger));
 Query.Next;
 while not Query.Eof do
 begin
   i := 0;
   while i < Tree.Items.Count do
     if Tree.Items.Item[i].Data = Pointer(Query.FieldByName(idParent).asInteger)
       then
     begin
       Tree.Items.AddChildObject(Tree.Items.Item[i],
         Query.FieldByName(cNodeName).AsString,
         Pointer(Query.FieldByName(idNode).asInteger));
       break;
     end
     else
       Inc(i);
   Query.Next;
 end;
end;


 
k2 ©   (2005-07-11 09:15) [3]

вместо idParent писать при заполнении дерева в Data букмарку, например:
Tree.Items.AddObject(nil, Query.FieldByName(cNodeName).AsString, Query.GetBookmark);

при клике по нодам дерева переходить в датасете на соответствующую запись


 
evvcom ©   (2005-07-11 09:23) [4]

А что, запрос не может возвратить уже отсортированное нужным образом дерево, чтобы не сканить после каждого Next весь TreeView? При большом количестве записей в этом месте наступят бАльшие тормоза. База-то какая?


 
mmms   (2005-07-11 09:30) [5]

k2 ©   (11.07.05 09:15)
Интересное предложение, с GetBookmark попробовал, может что делаю не так (никогда до этого не сталкивался), перестала строится структура с ним, т.е. без Pointer(Query..

[4] evvcom ©   (11.07.05 09:23)
Да, таблица может быть и 1000 позиций, может и 10000 быть. Поэтому захотелось сделать древовидное меню, для быстроты выбора товара по его типу. Процедура от Delirium идеально подходит, вот только как "получить" значение ID товара не знаю.


 
Anatoly Podgoretsky ©   (2005-07-11 09:39) [6]

Третий параметр AddChildObject - это пользовательские данные, если у тебя ID = Integer, то можешь его прямо писать через приведение к Pointer и обратно.


 
ANB ©   (2005-07-11 09:42) [7]


> mmms   (11.07.05 09:30) [5]
- есть предложение. Имхо. Сами товары храни в плоской таблице с привязкой к древовидной с группами товаров. Тогда легко переключать - дерево / алфавитный список (не всем пользователям и не во всех режимах работы нравится работать с деревом) и инфы в дереве можно по минимуму хранить, а товары группы можно доставать отдельным запросом с любыми полями. И тормозить при закачке сильно не будет, так как групп сильно много не бывает. Кстати, в оракле есть CONNECT BY, который сам дерево строит.


 
evvcom ©   (2005-07-11 09:50) [8]


> как "получить" значение ID товара не знаю

В примере Query.FieldByName(idNode).asInteger - это и есть "получение ID", в чем проблема?

> может быть и 1000 позиций, может и 10000 быть

Удивляет игнорирование авторами уточняющих вопросов! 10000 - это довольно много. Даже при одноразовом пробеге по такому количеству записей для построения TreeView будет заметна пауза. А уж при
> while not Query.Eof do
>  begin
>    i := 0;
>    while i < Tree.Items.Count do

эта пауза превратится в "смерть"!
Во-первых, надо подумать о сокращении количества выбираемых данных.
Во-вторых, отсортировать возвращаемый набор средствами SQL. Как? Для этого мы должны услышать ответ на вопрос
> База-то какая?
Который был проигнорирован.


 
evvcom ©   (2005-07-11 09:54) [9]


> Кстати, в оракле есть CONNECT BY

Вот и я к тому же. Только фиг знает какой сервак у автора, а то может у него вовсе базы dBase или Paradox? А мы тут надрывайся ему, советуй из чего космический корабль построить, когда у него инструментов на велосипед недостаточно.


 
mmms   (2005-07-11 10:18) [10]

evvcom ©   (11.07.05 09:54)
прошу прощения, MSSQL2000, в принципе понятно, лучше старым дедовским способом, связанные таблицы, вид-товар. Сортировать... под данную процедуру это сложно, если надо что бы родители были всегда вверху.


 
mmms   (2005-07-11 10:20) [11]

rowid idnode idchildnode caption
1 1 1 Магазин
2 2 1 Продукты
3 30 1 Электроника
4 40 1 Бытовая химия
5 50 2 Фрукты
6 51 2 Овощи
7 52 2 Молочные
8 1 52 Молоко
9 1 52 Кефир
10 1 52 Сгущ. молоко
11 1 52 Ряженка
12 1 52 Сыр
13 1 52 Творог
14 1 51 Картофель
15 1 51 Морковка
16 1 51 Огурцы
17 1 50 Яблоки
18 1 50 Груша
19 1 50 Слива
20 100 30 DVD-плеер
21 101 30 Телевизор
22 102 30 Видеомагнитофон
23 103 30 Музыкальные центры
24 1 100 BBK 911 S
25 1 100 BBK 911
26 1 100 BBK 912 S
27 1 100 BBK 912
28 1 101 Sony 21""
29 1 101 Sony 25""
30 1 102 LG 944
31 1 102 LG 945


Как пример, вывод на экран только DVD-плеера...


 
msguns ©   (2005-07-11 10:24) [12]

>mmms

Дай мыло, вышлю форму-модуль древовидного справочника


 
mmms   (2005-07-11 10:28) [13]

msguns ©   (11.07.05 10:24)
worldsite2000 @ mail.ru
Заранее благодарю :)


 
evvcom ©   (2005-07-11 10:35) [14]

1. idchildnode заменить на idparentnode или вообще на idparent
2. НД лучше отсортировать в виде:

id idparent caption level
1 1 Магазин 1
30 1 Электроника 2
...
40 1 Бытовая химия 2
2 1 Продукты 2
50 2 Фрукты 3
1 50 Яблоки 4 ***
1 50 Груша 4 ***
1 50 Слива 4 ***
51 2 Овощи 3
1 51 Картофель 4 ***
1 51 Морковка 4 ***
1 51 Огурцы 4 ***
52 2 Молочные 3
1 52 Молоко 4 ***
1 52 Кефир 4 ***
1 52 Сгущ. молоко 4 ***
1 52 Ряженка 4 ***
1 52 Сыр 4 ***
1 52 Творог 4 ***

3. id должен быть уникальным, поэтому записи помеченные *** имеют неверные id
4. добавить поле level, для более простого анализа на клиенте
5. пример построения дерева для MSSQL давали мастера на этом форуме. Уже не помню кто. Сейчас сделал поиск: не нашел. Привожу тот код:

CREATE FUNCTION TreeFromTable (@Root INT)  
RETURNS @T TABLE (ID INT, Owner INT, level INT) AS  
BEGIN
DECLARE @level INT
SET @Level=0
INSERT @T SELECT @Root, 0, 0

while exists(SELECT * FROM @T T, Structure S WHERE
T.level=@level and S.Owner=T.ID)
begin
INSERT @T (ID,Owner,Level)
SELECT S.ID, S.Owner, @level+1 from @T T, Structure S WHERE T.level=@level and S.Owner=T.ID
SET @level=@level+1
end

RETURN
END


 
msguns ©   (2005-07-11 11:08) [15]

Лови. Комментарии в письме.


 
mmms   (2005-07-11 11:18) [16]

msguns ©   (11.07.05 11:08)
Сергей, пока ничего нет, там пробелы между собачкой, если в них дело, или должно позже подойти, буду ждать, спасибо.

evvcom ©   (11.07.05 10:35)
Так же спасибо за решение, idnode и idchildnode это не ID товара, а указатели для древовидного меню (кстати, рисуется очень хорошо :) ) а вот rowid и есть ID товара, из за нее весь сыр бор.


 
msguns ©   (2005-07-11 11:31) [17]

>mmms   (11.07.05 11:18) [16]

БД там интербэйз и "ветки" вытаскиваются хранимкой. Уже отсортированной по узлам.
Основа же в том, что записи БД помещаются в объекты, указатели на которых и "засовываются" в тривью. Весь справочник не считывается (для этого есть режим линейного просмотра), т.к. одномоментно надо показывать лишь одну (текущую в тривью) группу/подгруппу. Т.е. юзер кликает на узле тривью и в гриде отображается содержимое его листьев, а также листьев подчиненных узлов.


 
msguns ©   (2005-07-11 11:33) [18]

>msguns ©   (11.07.05 11:31) [17]
>Т.е. юзер кликает на узле тривью и в гриде отображается содержимое его листьев, а также листьев подчиненных узлов.

Отображаются только листья текущего узла. Извиняюсь за путаницу - проект старый, уже подзабыл ;)


 
evvcom ©   (2005-07-11 11:36) [19]


> а вот rowid и есть ID товара

Тогда idparent должен ссылаться на этот rowid. А вообще смысл rowid несколько иной, поэтому, чтобы избежать кривотолков в будущем, советую все же row из этого названия убрать.


 
mmms   (2005-07-11 11:37) [20]

[18] msguns ©   (11.07.05 11:33)
Да ничего, хорошо, посмотрю как у других это делается :)


 
Ega23 ©   (2005-07-11 11:39) [21]


unit uKdrDBTreeView;

interface

uses Windows, SysUtils, Classes, comctrls, stdctrls, db, graphics, controls,
    Dialogs, contnrs;

Type

TCustomKdrDBTreeView=class;

TKdrDBTreeViewItemIdent = class(TObject)
 private
   FParentKeyFieldValue: Variant;
   FKeyFieldValue: Variant;
   FDisplayFieldValue: String;
   FImageFieldValue: Integer;
   FNode: TTreeNode;
 public
   property KeyFieldValue:Variant Read FKeyFieldValue Write FKeyFieldValue;
   property ParentKeyFieldValue:Variant Read FParentKeyFieldValue Write FParentKeyFieldValue;
   property DisplayFieldValue:String Read FDisplayFieldValue Write FDisplayFieldValue;
   property ImageFieldValue:Integer Read FImageFieldValue Write FImageFieldValue;
   property Node:TTreeNode Read FNode Write FNode;
end;

TTreeDataLink = class(TDataLink)
 private
   FTree: TCustomKdrDBTreeView;
   FMinParent: Integer;
   FMinValue: Integer;

 public
   constructor Create(ATree:TCustomKdrDBTreeView);
   procedure DataSetChanged; override;
   procedure ActiveChanged; override;

   property MinParent:Integer Read FMinParent Write FMinParent;
   property MinValue:Integer Read FMinValue Write FMinValue;

end;

TCustomKdrDBTreeView = class(TCustomTreeView)
 private
   FDataLink: TTreeDataLink;
   FTreeItems:TObjectList;
   FKeyField: String;
   FDisplayField: String;
   FParentField: String;
   FDataSource: TDataSource;
   Inh_TVChange: TTVChangedEvent;
   procedure SetFDataSource(const Value: TDataSource);

 protected

   function LocateByNode(Node:TTreeNode):Boolean;
   procedure TVChange(Sender: TObject; Node: TTreeNode);
   procedure AddAllNodes(ParentID: Integer; ParentNode:TTreeNode);
   function SetSelectedNode(const Value:Variant):TTreeNode;
   property DataSource:TDataSource Read FDataSource Write SetFDataSource;
   property DisplayField:String Read FDisplayField Write FDisplayField;
   property KeyField:String Read FKeyField Write FKeyField;
   property ParentField:String Read FParentField Write FParentField;

 public

   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   procedure Clear;
   procedure DataChanged;
   procedure ActiveChanged;

   function AddItem:Integer;
end;

TKdrDBTreeView = class (TCustomKdrDBTreeView)
 published
  property DataSource;
  property DisplayField;
  property KeyField;
  property ParentField;
end;

implementation

{ TTreeDataLink }

//*****************************************************************************

procedure TTreeDataLink.ActiveChanged;
var
i:Integer;
begin
 inherited;
 FTree.Clear;
 if (DataSet.Active) and (FTree<>nil) and (dsBrowse in [DataSet.State]) then
  begin
   BufferCount:=DataSet.RecordCount;
   i:=0;
   ActiveRecord:=i;
   MinParent:=DataSet.FieldByName(FTree.KeyField).Value;
   MinValue:=DataSet.FieldByName(FTree.ParentField).Value;

   While (i<BufferCount) do
    begin
     FTree.AddItem;
     With DataSet do
      begin
       if MinValue>FieldByName(FTree.KeyField).AsInteger then
        MinValue:=FieldByName(FTree.KeyField).AsInteger;
       if MinParent>FieldByName(FTree.ParentField).AsInteger then
        MinParent:=FieldByName(FTree.ParentField).AsInteger;
      end;
     Inc(i);
     ActiveRecord:=i;
    end;
   FTree.ActiveChanged;
   ActiveRecord:=0;
  end;
end;

//*****************************************************************************

constructor TTreeDataLink.Create(ATree: TCustomKdrDBTreeView);
begin
 inherited Create;
 FTree:=ATree;
 VisualControl:=True;
end;


 
Ega23 ©   (2005-07-11 11:39) [22]


//*****************************************************************************

procedure TTreeDataLink.DataSetChanged;
begin
 inherited;
 if (DataSet.Active) and (FTree<>nil) and (dsBrowse in [DataSet.State]) then
  FTree.DataChanged;
end;

//*****************************************************************************

{ TKdrDBTreeView }

procedure TCustomKdrDBTreeView.ActiveChanged;
begin
 Items.BeginUpdate;
 AddAllNodes(FDataLink.MinParent, nil);
 Items.EndUpdate;
end;

//*****************************************************************************

procedure TCustomKdrDBTreeView.AddAllNodes(ParentID: Integer;
 ParentNode: TTreeNode);
var
k:Integer;
CurrNode:TTreeNode;
begin
for k:=0 to FTreeItems.Count-1 do
 begin
  With TKdrDBTreeViewItemIdent(FTreeItems.Items[k]) do
   begin
    if (Node<>nil) or (ParentKeyFieldValue<>ParentID) then Continue;
    if ParentNode=nil then
     CurrNode:=Items.Add(nil, DisplayFieldValue)
    else
     CurrNode:=Items.AddChild(ParentNode, DisplayFieldValue);
    CurrNode.ImageIndex:=ImageFieldValue;
    CurrNode.SelectedIndex:=ImageFieldValue;
    Node:=CurrNode;
    CurrNode.Data:=FTreeItems.Items[k];
    AddAllNodes(KeyFieldValue, CurrNode);
   end; // With
 end; // for

end;

//*****************************************************************************

function TCustomKdrDBTreeView.AddItem: Integer;
var
i:Integer;
begin
try
 i:=FTreeItems.Add(TKdrDBTreeViewItemIdent.Create);
 With TKdrDBTreeViewItemIdent(FTreeItems.Items[i]) do
  begin
   KeyFieldValue:=FDataLink.DataSet.FieldByName(KeyField).Value;
   ParentKeyFieldValue:=FDataLink.DataSet.FieldByName(ParentField).Value;
   DisplayFieldValue:=FDataLink.DataSet.FieldByName(DisplayField).AsString;
  end;
except
 Result:=-1;
end;

end;

//*****************************************************************************

procedure TCustomKdrDBTreeView.Clear;
var
i:Integer;
begin
 FTreeItems.Clear;
 Items.Clear;
end;

//*****************************************************************************

constructor TCustomKdrDBTreeView.Create(AOwner: TComponent);
begin
 inherited;
 HideSelection:=False;
 FDataLink:=TTreeDataLink.Create(Self);
 FTreeItems:=TObjectList.Create(True);

 if Assigned(Self.OnChange) then Inh_TVChange:=Self.OnChange;
 Self.OnChange:=TVChange;

end;

//*****************************************************************************

procedure TCustomKdrDBTreeView.DataChanged;
begin
Selected:=SetSelectedNode(FDataLink.DataSet.FieldByName(KeyField).AsInteger);
end;

//*****************************************************************************

destructor TCustomKdrDBTreeView.Destroy;
begin
 FTreeItems.Free;
 FDataLink.Free;
 inherited;
end;

//*****************************************************************************

function TCustomKdrDBTreeView.LocateByNode(Node: TTreeNode): Boolean;
var
i:Integer;
V:Variant;
keyFields:String;
begin
Result:=False;
for i:=0 to FTreeItems.Count-1 do
 if TKdrDBTreeViewItemIdent(FTreeItems.Items[i]).Node=Node then
  begin
   V:=VarArrayCreate([0,1], varVariant);
   V[0]:=TKdrDBTreeViewItemIdent(FTreeItems.Items[i]).KeyFieldValue;
   V[1]:=TKdrDBTreeViewItemIdent(FTreeItems.Items[i]).ParentKeyFieldValue;
   keyFields:=KeyField+";"+ParentField;
   Result:=FDataLink.DataSet.Locate(KeyFields,V , []);
  end;
end;

//*****************************************************************************

procedure TCustomKdrDBTreeView.SetFDataSource(const Value: TDataSource);
begin
 if (Value<>nil) and (FDataSource<>Value) then
  begin
   FDataSource := Value;
   FDataLink.DataSource:=Value;
  end;
end;

//*****************************************************************************

function TCustomKdrDBTreeView.SetSelectedNode(
 const Value: Variant): TTreeNode;
var
i:Integer;
begin
Result:=nil;
for i:=0 to FTreeItems.Count-1 do
 With TKdrDBTreeViewItemIdent(FTreeItems.Items[i]) do
  if KeyFieldValue=Value then
   begin
    Result:=Node;
    Break;
   end;
end;

//*****************************************************************************

procedure TCustomKdrDBTreeView.TVChange(Sender: TObject; Node: TTreeNode);
begin
 LocateByNode(Node);
 if (@Inh_TVChange<>nil) then Inh_TVChange(Sender, Node);
end;

//*****************************************************************************

end.


 
Андрей Жук ©   (2005-07-11 16:20) [23]

{
Формат елементів усіх дерев
mem_id - обовязково. Ідентифікатор елемента
mem_pid - обовязково. Ідентифікатор "батьківського" елемента
is_leaf -  обовязково. Ознака, чи є елемент елементом нижнього рівня
outlevel - обовязково. Рівень елемента
mem_order - обовязково. Порядковий номер в структурі
mem_name - обовязково. Назва елемента
mem_desc - обовязково. Описання елемента
mem_type - не  обовязково. Тип елемента
}
type
 TMyTreeNodes = record
   mem_id: integer;
   mem_pid: integer;
   is_leaf: boolean;
   outlevel: integer;
   mem_order: integer;
   mem_name: string;
   mem_desc: string;
   mem_type: string;
   changing: boolean; // чи змінювалися дані в обєкті
   inserting: boolean; //чи є обєкт доданим (без відображення в базі)
   ParentNode: TTreeNode;
 end;
 PTMyTreeNodes = ^TMyTreeNodes;

function GenerateTree(Tree: TTreeView; DataSet: TDataSet): TFunctionResult;
var
 FunctionResult: TFunctionResult;
 vData: PTMyTreeNodes;
 Node, LastNode: TTreeNode;
begin
 Result.Successful := false;
// якщо дерево чи датасет не ініціалізовані, зупинити виконання
 if not Assigned(Tree) or not Assigned(DataSet) then
 begin
   Result.MessageOnError := "Programmer error - not initilized objects on creating tree";
   Exit;
 end;
// якщо датасет не активний, то зупинити виконання
 if not DataSet.Active then
 begin
   Result.MessageOnError := "Programmer error - not activated Dataset";
   Exit;
 end;
// очистимо дерево, якщо помилка зупинити виконання
 try
 LockWindowUpdate(Tree.Parent.Handle);
 FunctionResult := ClearTree(Tree);
 if not FunctionResult.Successful then
 begin
   Result.MessageOnError := FunctionResult.MessageOnError;
   Exit;
 end;
// заповнимо дерево
 with DataSet do
 begin
   LastNode := nil;
   First;
   while not Eof do
   begin
     New(vData); // створимо елемент
     with vData^ do
     begin
       // заповнюємо його поля
       try
         mem_id := FindField("mem_id").AsInteger;
         mem_pid := FindField("mem_pid").AsInteger;
         is_leaf := boolean(FindField("is_leaf").AsInteger);
         outlevel := FindField("outlevel").AsInteger;
         mem_order := FindField("mem_order").AsInteger;
         mem_name := FindField("mem_name").AsString;
         mem_desc := FindField("mem_desc").AsString;
         if Assigned(FindField("mem_type")) then
           mem_type := FindField("mem_type").AsString
         else
           mem_type := "general";
         changing := false;
         inserting := false;
       except on E: Exception do
         begin
           Result.MessageOnError := "Programm error - incompatible structure" + #10#13 + "Details: " + E.Message;
           Exit;
         end;
       end;
     // якщо це елемент верхнього рівня, то додамо його в корінь
       if vData.outlevel = 1 then
       begin
         Node := Tree.Items.Add(nil, vData^.mem_desc);
         vData.ParentNode := nil;
       end
     // якщо елемент нижчого рівня, то додати як "сина"
       else if PTMyTreeNodes(LastNode.Data)^.outlevel < vData.outlevel then
       begin
         Node := Tree.Items.AddChild(LastNode, vData^.mem_desc);
         vData.ParentNode := LastNode;
       end
     // якщо елемент одного рівня, то додати як "брата"
       else if PTMyTreeNodes(LastNode.Data)^.outlevel = vData.outlevel then
       begin
         Node := Tree.Items.AddChild(LastNode.Parent, vData^.mem_desc);
         vData.ParentNode := LastNode.Parent;
       end
     // якщо елемент вищогого рівня, то знайти "підходящого батька" та додати як "сина"
       else if PTMyTreeNodes(LastNode.Data)^.outlevel > vData.outlevel then
       begin
         while PTMyTreeNodes(LastNode.Data)^.outlevel >= vData.outlevel do
           LastNode := LastNode.Parent;
         Node := Tree.Items.AddChild(LastNode, vData^.mem_desc);
         vData.ParentNode := LastNode.Parent;
       end;
     // занесення даних до структури
       Node.Data := vData;
       LastNode := Node;
       Next;
     end;
   end;
 end;
 Result.Successful := true;
 finally
  LockWindowUpdate(0);
 end;
end;


 
Ega23 ©   (2005-07-11 16:27) [24]

2 Андрей Жук ©   (11.07.05 16:20) [23]

Я бы на твоём месте вот сюда
// заповнимо дерево
with DataSet do
begin
  LastNode := nil;
  First;
  while not Eof do

ещё DisableControls поставил (в конце - EnableControls).


 
mmms   (2005-07-18 10:24) [25]

Приветствую всех!
Снова с TreeView,
Код от mmms   (11.07.05 09:00)
Как можно узнать вот это Pointer(Query.FieldByName(idNode).asInteger) значение, например в Showmessage("");, т.е. привести к string.


 
mmms   (2005-07-18 10:25) [26]

Делаю так, ошибка:
procedure TForm1.tvClick(Sender: TObject);
begin
 Showmessage(PString(tv.Selected.Data)^);
end;


 
Ega23 ©   (2005-07-18 10:46) [27]

Слушай, может ты сначала какую-нибудь книжку почитаешь? Про типы данных, например? Про указатели? Про классы?
Чтобы вот с таим-вот Showmessage(PString(tv.Selected.Data)^) не позориться?


 
Anatoly Podgoretsky ©   (2005-07-18 10:56) [28]

Ega23 ©   (18.07.05 10:46) [27]
Не царское дело!


 
mmms   (2005-07-18 11:26) [29]

Послать к книге понятно, проще всего, я понять не могу, как через указатель, прочитать значение. В данном случае это нетипизированный указатель, который может указывать на данные произвольного типа. Видимо не туда "обращаюсь" чтобы прочитать данные...

И 2й вопрос, можно ли запихнуть в коде
[2] mmms   (11.07.05 09:00)
Data типа String. Я просто туда буду писать 2 строки, вместо теперешноего одного числа. Вопрос в том, что делая это, у меня не происходит "отрисовки меню", т.е. дальше строки
if Tree.Items.Item[i].Data = Pointer(Query.FieldByName(idParent).asString)

Как будто String не сравнивается...


 
Ega23 ©   (2005-07-18 11:28) [30]

Читай про PChar


 
evvcom ©   (2005-07-18 11:35) [31]


> Я просто туда буду писать 2 строки

Это как? В Pointer можно записать только один указатель. Неважно на что: string, char, integer или вообще на мусор. Важно, как этот указатель будешь потом интерпретировать.

> Как будто String не сравнивается

В [2] никаких указателей на string я не увидел, поэтому делать какие-то выводы просто не из чего.


 
mmms   (2005-07-18 13:57) [32]

Ega23
Хорошо, почему так ошибку выдает, что я не так пишу? (прошу извинить за такие вопросы)
procedure TForm1.tvClick(Sender: TObject);
begin
 Showmessage(PChar(tv.Selected.Data));
end;
evvcom
Ну да, сейчас пишется ссылка на Integer, я хотел вместо этого Integer TStringList хранить, текст типа "fdfg"+#13#10+"fdgfgfg"... и по TStringList делать сравнение в условии, да что то не сравнивается, и в итоге кроме одного итема на Tree больши ничего нет, что и логично. Но это заморочки мои, мне надо всего лишь записать + вытащить число в Data. Был бы Tag, как бы хорошо было :) То что тут код был.. он конечно хорош, но процедура [2] мне очень подходит, осталось только достать Data.


 
evvcom ©   (2005-07-18 14:08) [33]


> почему так ошибку выдает

Что за ошибка? Неужели влом написать?

> ... и по TStringList делать сравнение в условии, да что
> то не сравнивается

Ну долго мы в телепатов будем играть? Ну прям Пельш новоиспеченный с игрой "Угадай, мою писанину!"


 
mmms   (2005-07-18 14:31) [34]

EAccessViolation
"Access violation at address ..."


 
Anatoly Podgoretsky ©   (2005-07-18 14:34) [35]

У тебя указатель не верный!


 
mmms   (2005-07-18 14:45) [36]

Анатолий, так я понял, я с утра хочу спросить, как верный то написать :(
Showmessage(PChar(tv.Selected.Data));


 
mmms   (2005-07-18 14:45) [37]

Удалено модератором


 
Ega23 ©   (2005-07-18 14:47) [38]

Блин, ты сначала разберисть, что ты в tv.Selected.Data раньше положил. В каком виде?


 
Anatoly Podgoretsky ©   (2005-07-18 14:48) [39]

mmms   (18.07.05 14:45) [36]
Если в tv.Selected.Data ASCIIZ то приведение правильное


 
mmms   (2005-07-18 14:59) [40]

Блин, ты сначала разберисть, что ты в tv.Selected.Data раньше положил. В каком виде?
Разобрался.. Ложу Integer, (код [2] mmms   (11.07.05 09:00)), как этот интегер считать?
В режиме отладки посмотрел, tv.Items.Item[0].Data=$64,
procedure TForm1.tvClick(Sender: TObject);
begin
if tv.Items.Item[0].Data<> nil then
 Showmessage(PChar(tv.Items.Item[0].Data)); //=$64
end;


 
mmms   (2005-07-18 14:59) [41]

Ну и тут же ошибка.. Access...


 
evvcom ©   (2005-07-18 15:07) [42]

А что ты хотел увидеть? Ты преобразовываешь $64 к указателю на строку. Естественно? при чтении по адресу $64 ты получаешь AV. Ложить надо туда валидный указатель на строку, чтобы так читать.


 
Ega23 ©   (2005-07-18 15:09) [43]

2 mmms   (18.07.05 14:59) [40]
Разобрался.. Ложу Integer, (код [2] mmms   (11.07.05 09:00)), как этот интегер считать?

Чтобы показать Integer в виде строки, воспользуйся функцией IntToStr.
А вообще у тебя полная каша в голове. Тебе надо сначала разобраться и понять, что такое адрес и значение по адресу.


 
mmms   (2005-07-18 15:17) [44]

Причем тут каша, я столкнулся с единственным препятствием, может мне теперь и застрелится ещё :) Спрашиваю, если это не сложно, то хотелось бы получить ответ, как прочитать этот Data. На счет ф-и IntToStr, но куда ее тут применить? Ega23, всмотритесь внимательно в код. Data возвращает Pointer а не Integer.


 
mmms   (2005-07-18 15:18) [45]

Но там лежит Integer...


 
Ega23 ©   (2005-07-18 15:33) [46]

Вот смотри:
var
p:PInteger;
i:Integer;
begin
New(p); // Чему сейчас равно значение p? Это может быть что угодно, например $364F5CAD
        // Так вот, это - адрес Integer"а
i:=6; //
p^:=i; // Значение ПО АДРЕСУ изменилось, но значение АДРЕСА - нет.


end;


 
Anatoly Podgoretsky ©   (2005-07-18 15:37) [47]

mmms   (18.07.05 15:17) [44]
А что ему еще выдавать, что бы это были универсальные данные? Ты знаешь такой тип?


 
mmms   (2005-07-18 15:54) [48]

[46] Ega23 ©   (18.07.05 15:33)
Да, у меня только значения не меняются, и хочется ТОЛЬКО считать это значение.
Так, что ли? :(
Showmessage(String(PInt(tv.Items.Item[0].Data)));
Ошибка Access...
Интересно тоже:
Showmessage(Pchar(@tv.Items.Item[0].Data));
Выдает букву "D"

Вот только как обратится к памяти, где лежит Data, так и не понял :(


 
evvcom ©   (2005-07-18 16:04) [49]

Объясни, наконец, что ты хочешь? К ноду привязать стринг, а потом его где-то использовать? Ну так и пиши:
tv.Items[0].Data := Pointer(MyString);
читай:
ShowMessage(string(tv.Items[0].Data));

Только надо быть осторожным. Любое присвоение переменной MyString, после того как она была запомнена в Data, может сделать этот указатель (Data) недействительным, и опять получишь AV при попытке чтения данных по указателю Data.


 
msguns ©   (2005-07-18 16:05) [50]

>mmms  

Ты смотрел то, что я посылал тебе ?
А если смотрел, то не мог не орбратить внимание на это :

type
 // Описатели объектов справочника
 PGR_Info = ^GR_Info;   // Группа - узел TreeView
 GR_Info = record
   ID: integer;         // ID группы
   IDP: integer;        // ID родителя группы
   Txt: string;         // Отображаемая метка группы
   Lev: integer;        // Уровень группы в дереве (0 для корневых)
   ChQ: integer;        // Кол-во непосредственных потомков ("деток")
 end;


и это:

function TfrbaseSpr.GetGroupsInTreeView: boolean;
// Процедура извлечения информации о группах справочника в список и дерево
var
 gline: PGR_Info;
 i,j: integer;
begin
 result := false;
 sttAction.Caption := "Загрузка дерева..";
 sttOpStatus.Caption := "";
 pnStatus.Update;
 // Инициализация TreeView
 trvSpr.Items.Clear;
 GR_List.Clear;
 with quTree do
   try
     if Active then Close;
     Open;
     First;
     // Цикл по записям НД, полученного из записей справочника запросом со
     // след.обязательными условиями:
     //  - Выбираются только записи групп (поле XXGROUP>"")
     //  - Записи упорядочены по PID, ID, т.е. "родители" раньше "детей"
     //  - Поля в НД следуют в след.порядке: IDP, ID, NAME
     While not Eof do
       begin
        NEW(gline);
        gline^.ID := Fields[1].AsInteger;
        gline^.IDP := Fields[0].AsInteger;
        gline^.Txt := Fields[2].AsString;
        gline^.Lev := 0;      // Уровень по умолчанию = корню
        gline^.ChQ := 0;      // Кол-во "детишек"
        GR_List.Add(gline);   // Добавить в список групп
        Next;
       end;
   except
     sttOpStatus.Caption := "Ошибка чтения справочника";
   end;
 quTree.Close;
 if GR_List.Count>0 then
    // Загрузка из списка в TreeView
    for i := 0 to GR_List.Count-1 do    // Перебор списка сверху вниз
      begin
       gline := GR_List.Items[i];
       if gline^.IDP=0 then // Узел не входит никуда, добавляем его "в корень" "дерева"
          trvSpr.Items.AddObject(nil,gline^.Txt,gline)
       else // Узел куда-то входит. Ищем "папашку" в TreeView
          for j := 0 to trvSpr.Items.Count-1 do
             if PGR_Info(trvSpr.Items[j].Data)^.ID=gline^.IDP  then  // Нашли !
               begin
                trvSpr.Items.AddChildObject(trvSpr.Items[j],gline^.Txt,gline);  // Добавить как "дитя"
                gline^.Lev := PGR_Info(trvSpr.Items[j].Data)^.Lev+1; // Уровень
                inc(PGR_Info(trvSpr.Items[j].Data)^.ChQ);      // Кол-во "детишек" у "папки"
                break;
               end;
      end;
 for i := 0 to trvSpr.Items.Count-1 do
   begin  // Рисуем рядом с наименованием узла "красивую" иконку
    trvSpr.Items[i].ImageIndex := 1;
    trvSpr.Items[i].SelectedIndex := 1;   // Если false, то при выборке иконка не рисуется ;(
   end;
 if trvSpr.Items.Count>0 then
   begin  // Сортируем дерево по наименованиям узлов и первый делаем активным
    trvSpr.CustomSort(@CustSortTreeNodes,0);
    trvSpr.Selected := trvSpr.Items[0];
   end;
 sttAction.Caption := "Просмотр";
 pnStatus.Update;
end;


Кроме того, у Андрей Жук ©   (11.07.05 16:20) [23]
схема использования для хранения в дереве данных о записях аналогичная.
И заключается в том, что объявляем объект (record), типизированный указатель на него и добавляем в TTreeView указатель на этот объект. При извлечении информации из "дерева" (св-во Data) используем явное преобразование к нужному типу и корректно работаем с любыми данными объекта.


 
Ega23 ©   (2005-07-18 16:07) [51]

Вот только как обратится к памяти, где лежит Data, так и не понял :(

(tv.Items.Item[0].Data^)

А что у тебя там лежит - это ты, брат, сам знать должен. Если String, то
ShowMessage(tv.Items.Item[0].Data^),
если Integer, то
ShowMessage(IntToStr(tv.Items.Item[0].Data^))
и т.д.


 
Anatoly Podgoretsky ©   (2005-07-18 16:10) [52]

evvcom ©   (18.07.05 16:04) [49]
Никакой проблемы с DATA надо и работать, а не с копиями.


 
evvcom ©   (2005-07-18 16:15) [53]


> Никакой проблемы с DATA надо и работать, а не с копиями.

Я-то знаю, я автора предупреждаю.


 
mmms   (2005-07-18 16:35) [54]

[50] msguns ©   (18.07.05 16:05)
msguns, благодарю, так и не получил, горе у меня :(, гроза была в четверг, комп вылетел, не успел почту принять, а аккаунт прописан только там, ладно ноут на гарантии, сдал, сейчас через интерфейс mail.ru зайду, приму.

А что у тебя там лежит - это ты, брат, сам знать должен. Если String, то
Спасибо Ega23, теперь понятно. Только строка ShowMessage(IntToStr(tv.Items.Item[0].Data^)) не компилится, но сейчас разберусь.


 
Ega23 ©   (2005-07-18 16:38) [55]

ShowMessage(IntToStr(PInteger(tv.Items.Item[0].Data)^))


 
evvcom ©   (2005-07-18 16:38) [56]


> не компилится

В таком виде и не скомпилится, потому как Pointer нетипизированный указатель. Могу подсказать как скомпилится, но толку не будет никакого, потому что показывать надо обе стороны: и запись, и чтение. А по отдельности говорить об этом, значит опять AV получить с большой долей вероятности.


 
msguns ©   (2005-07-18 16:42) [57]

>Ega23 ©   (18.07.05 16:38) [55]
>ShowMessage(IntToStr(PInteger(tv.Items.Item[0].Data)^))

И ЧТО он увидит ?


 
evvcom ©   (2005-07-18 16:43) [58]


> И ЧТО он увидит ?

"100"!


 
Ega23 ©   (2005-07-18 16:43) [59]

2 msguns ©   (18.07.05 16:42) [57]
И ЧТО он увидит ?

а ЧТО?????


 
Anatoly Podgoretsky ©   (2005-07-18 17:01) [60]

Нифига, а увидит он 17


 
Ega23 ©   (2005-07-18 17:01) [61]

Что положит, то и увидит...


 
Anatoly Podgoretsky ©   (2005-07-18 17:03) [62]

Ega23 ©   (18.07.05 17:01) [61]
А я сомневаюсь


 
Ega23 ©   (2005-07-18 17:06) [63]

2 Anatoly Podgoretsky ©   (18.07.05 17:03) [62]
А я сомневаюсь

Основание?


 
msguns ©   (2005-07-18 17:21) [64]

>Ega23 ©   (18.07.05 17:06) [63]
>Основание?

Для начала ты объясни мне, дураку, что делать вот с этим ?
PInteger(tv.Items.Item[0].Data)^))

Кому и для чего надо значение адреса фиг знает чего ?


 
Ega23 ©   (2005-07-18 17:26) [65]

2 msguns ©   (18.07.05 17:21) [64]

var
p:PInteger;
begin
p:=PInteger(tv.Items.Item[0].Data);
ShowMessage(IntToStr(P^));
end;

А такая запись тебя не смущает???


 
msguns ©   (2005-07-18 17:36) [66]

>Ega23 ©   (18.07.05 17:26) [65]

Ты мне не ответил на вопрос.
ЧТО лежит В tv.Items.Item[0].Data ?


 
Ega23 ©   (2005-07-18 17:39) [67]

То, что ты туда поклал. Судя по теме, аффтар кладёт туда указатель на Integer.
В чём проблема-то?


 
evvcom ©   (2005-07-19 08:36) [68]


> Судя по теме, аффтар кладёт туда указатель на Integer.
> В чём проблема-то?

Может я чего не углядел, но в [2]
Tree.Items.Item[i].Data = Pointer(Query.FieldByName(idParent).asInteger)
я увидел единственное присваивание, и оно совсем не похоже на "кладет указатель". Вот в том-то и проблема, что автор игнорирует советы, что рассматривать чтение/запись надо в паре, но никак не по отдельности.


 
Ega23 ©   (2005-07-19 10:36) [69]

2 evvcom ©   (19.07.05 08:36) [68]

Ну я же не виноват, что он этот указатель туда по-идиотски кладёт. Я о том, что он ХОЧЕТ туда положить.


 
msguns ©   (2005-07-19 10:43) [70]

>Ega23 ©   (19.07.05 10:36) [69]
>Ну я же не виноват, что он этот указатель туда по-идиотски кладёт. Я о том, что он ХОЧЕТ туда положить.

Вот именно. Чел использует св-во TTreeView.Items[].Data, грубо говоря по-идиотски, не понимая сути. Ты же упорно пытаешься научить его пользоваться именно таким методом, который предусматривает наличие в данных только одного значения какого-либо типа. Так, как ты советуешь, делать можно, конечно.
Но вот нужно ли ?


 
alex_***   (2005-07-19 10:55) [71]

Не проще держать в Data указатель на объект с данными, а список объектов вести в TObjectList?


 
Ega23 ©   (2005-07-19 11:25) [72]

Вот именно. Чел использует св-во TTreeView.Items[].Data, грубо говоря по-идиотски, не понимая сути. Ты же упорно пытаешься научить его пользоваться именно таким методом, который предусматривает наличие в данных только одного значения какого-либо типа. Так, как ты советуешь, делать можно, конечно.
Но вот нужно ли ?


А ему честно сказал, что всё это по-идиотски. И не только я. Дальше - проблемы автора, ты не находишь?


 
mmms   (2005-07-19 11:46) [73]

msguns
Я письма не получил по почте, может архив запароленный, или exe есть? На mail антивирусы это не пропускают, если не сложно перешлите еще раз на этот же адрес, worldsite2000@mail.ru
all
Я эту процедуру взял из FAQ, хотел "прикрутить" под свои нужды. Копирайт тоже есть, во втором посте. Все для меня подходит (формирование меню). Как автор ложит код в итем, я переделывать не стал.

Если можно по другому его туда писать, без переделки самого принципа, то хотелось бы написать. И добавить в FAQ рядом с этим кодом. Т.к. тот код ещё не мало вызовет вопросов у новичков.. Но факт тот, что выбрал имено его, так это простота формирования меню, и минимальный(!) код. Ну а то, что загвоздки с Data.. как ее тогда можно избежать?


 
msguns ©   (2005-07-19 11:56) [74]

>alex_***   (19.07.05 10:55) [71]

Об этом мы ему и толкуем (см. приведенный выше код)

>mmms   (19.07.05 11:46) [73]

Какая версия архиватора ?
Щас пошлю нативные файлы


 
msguns ©   (2005-07-19 12:02) [75]

лови


 
mmms   (2005-07-19 14:27) [76]

Сергей (msguns), я написал вам письмом. Проверте пожалуйста.


 
msguns ©   (2005-07-19 15:05) [77]

отправил


 
msguns ©   (2005-07-19 15:05) [78]

Письмо получил, по указанному адресу отправил


 
mmms   (2005-07-19 15:08) [79]

Вот теперь дошло, спасибо!



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2005.08.28;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.71 MB
Время: 0.04 c
3-1121691780
GekaNaz
2005-07-18 17:03
2005.08.28
Ошибка - конец файла


1-1123426043
Demidoff
2005-08-07 18:47
2005.08.28
Из книжной в альбомную в richedit


3-1121339475
ks
2005-07-14 15:11
2005.08.28
Изменение даных в TQuery


1-1122983796
Tack
2005-08-02 15:56
2005.08.28
WebBroser не дает таскать текст в режиме редактирования


3-1121836820
Ольга
2005-07-20 09:20
2005.08.28
Проектирование БД. Учет ретроспективы.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский