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

Вниз

Прошу помощи по сохранению TreeView   Найти похожие ветки 

 
Vervolfe   (2013-09-14 06:34) [0]

Всех приветствую. Я нашел на этом форуме вот такую статью http://www.delphimaster.net/view/2-1278064750

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


 
Туповатый ©   (2013-09-14 08:20) [1]

это не статья. это - ветка форума, иными словами - многолог кого-то с кем-то и тем-то. и далеко не всегда там есть истина.
так что, неудивительно, что которую неделю не разобраться.
лучше прочитай это http://ln.com.ua/~openxs/articles/smart-questions-ru.html


 
wervolfe ©   (2013-09-14 08:29) [2]

Тем не менее, кто-нибудь может ответить на вопрос - помочь разобраться с сохранением данных TreeView в файл? В сети я не нашел ответа.
Есть несколько ссылок вот на эту процедуру : http://k210.org/delphi/main/1/

Объясните тогда как работать с ней! Или все горазды только в поиск отправлять?


 
sniknik ©   (2013-09-14 09:33) [3]

> ответить на вопрос - помочь разобраться с сохранением данных TreeView в файл? В сети я не нашел ответа.
потому, что это не вопрос.

> Объясните тогда как работать с ней!
там код для копипаста, это высшая форма объяснений... ну сохраняет только не файл, а в стрим, но есть же "стрим в файл", стандартный. все очевидно.
тебе не объяснения нужны, а багаж базовых знаний.

> Или все горазды только в поиск отправлять?
и кто тебя здесь отправил в поиск? хотя это дело хорошее, учится искать... но здесь тебе явно привели ссылку на статью которая точно поможет... если советам из нее следовать. и которую ты явно проигнорировал судя по посту после нее.


 
Туповатый ©   (2013-09-14 09:40) [4]

Я дал Вам ссылку "Как правильно задавать вопросы" а не в поиск отправлял.
На Ваш текущий общий вопрос ответа не будет, по крайней мере от меня, пока не будет точной формулировки требуемого и попыток самостоятельного решения.
Вы хотя бы понимаете, что данные бывают разные? Текст, картинки, объекты?
Файлы, они, конечно, все из байтов, но зато структура этих байтов так же разная, не говоря уже о некотором количестве стандартов форматов.
И судя по всему, на экране это дерево уже отображается, перебор веток понятен, равно как и удаление-добавление-изменение?


 
wervolfe ©   (2013-09-14 09:42) [5]

Я предупредил в первом сообщении, что я не программист. Я работаю с сетями и мне 43 года! Это разовая программа для автоматизации одного процесса.
Я ее уже написал. Весь затык только в сохранении дерева. Я вообще плохо себе представляю что такое стрим, как работают указатели и пр. Поэтому я и попросил помощи в примере. Извините, если кого обидел!

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


 
wervolfe ©   (2013-09-14 09:46) [6]

Да. Удаление и добавление понятно. Данные вводятся в TEdit. Все text. Все до 255. Не более десяти полей. Я заполняю дерево и мне его нужно сохранить кликом кнопки в файл. При открытии формы (или по клику-не суть) загрузить назад. Все.


 
sniknik ©   (2013-09-14 10:10) [7]

> Извините, если кого обидел!
спасибо я уже пообедал.

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


 
wervolfe ©   (2013-09-14 10:20) [8]

У меня нет здесь никаких программистов! Это программа лично для меня. Я над этой проблемой сижу уже неделю безвылазно. В избранном сотни уже ссылок.
Так что не нужно говорить, что не пытался.
Я надеюсь, что все таки найдется человек без понтов, который просто поможет? Или все такие забубенные "программисты" что не могут снизойти до просьбы постороннего? Ну тогда так и напишите, что вопросы не задавать в эом форуме-все равно на них никто отвечать не станет. С вашим,sniknik , лично отношением к людям мне все понятно.


 
Кирюха   (2013-09-14 11:03) [9]

Тут вроде про сабж: http://www.cyberforum.ru/delphi/thread608168.html


 
sniknik ©   (2013-09-14 11:06) [10]

> что вопросы не задавать в эом форуме-все равно на них никто отвечать не станет.
на ВОПРОСЫ то как раз отвечают, достаточно посмотреть соседние ветки.

> С вашим,sniknik , лично отношением к людям мне все понятно.
не к людям, а лично к тебе... и даже это вопрос, скорее к тому как ты "себя подаешь" в этой ветке.


 
Юрий Зотов ©   (2013-09-14 11:33) [11]

> wervolfe ©   (14.09.13 10:20) [8]

Если Вам нужно сохранить/загрузить только сами ветки дерева, то у TreeView есть методы SaveToFile и LoadFromFile. Они очень простые и описаны в справке, которую Вы, конечно же прочитали (разве не так?). Поэтому проблема непонятна.

const
 FileName = "D:/Temp/TV.nodes";

procedure TForm1.FormCreate(Sender: TObject);
begin
 TreeView1.SaveToFile(FileName);
 TreeView1.Items.Clear;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 TreeView1.LoadFromFile(FileName);
end;

Если же Вам нужно сохранить/загрузить еще и данные веток (свойство TTreeNode.Data), то ссылку на статью Вам дали, там все расписано. Но, как уже говорилось, Вы должны понимать, что данные бывают разными (текст, рисунок, число, объект  и пр.) и поэтому сохраняются/читаются они тоже по-разному. Ну а поскольку никто, кроме Вас, не знает, что это за данные, а Вы о них ничего не сказали, то и дать Вам готовый код невозможно. Либо пользуйтесь статьей самостоятельно (там нужно будет написать 2 процедуры), либо расскажите, какие именно данные Вы хотите сохранять/загружать. Иначе помочь Вам не сможет даже самый добрый программист на свете (ну, Вы уже поняли, что это я, конечно же...).


 
wervolfe ©   (2013-09-14 11:46) [12]

Кирюха -Спасибо. Сейчас посмотрю.

Подскажите вот в этом коде записи из потока в файл есть ошибка в указаной строке? У меня на ней выскакивает ошибка...

SL : tStringList;
N :TTreeNode;

SL:= tStringList.Create;
ANode:= TreeView.Items.GetFirstNode;
while ANode <> nil do
begin
        SL.Add(Rec(ANode.Data^).Str); // здесь ругается. Что такое "rec"?  
                                                    //Правильна  ли эта фраза вообще?
n := ANode.GetNext;  
end;
SL.SaveToFile("Value.dat");
FreeAndNil(SL);


 
wervolfe ©   (2013-09-14 11:50) [13]

Юрий Зотов
Нет. У меня в каждой ноде содержатся текстовые данные. В каждой около  10.
Вот так:

type
 PNodeOptions = ^NodeOptions;
 NodeOptions=record
  Name:     String[255];
  Surname: String[255];
  Address:  String[255];
  EMail:      String[255];
 end;

Это из примера, который я пытаюсь сохранить.


 
wervolfe ©   (2013-09-14 13:02) [14]

Юрий Зотов . Спасибо за участие.
Сейчас это элементарная программа из учебника Фленова.

unit UnitMain;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, ComCtrls, StdCtrls, Buttons, ExtCtrls;

type
 PNodeOptions = ^NodeOptions;
 NodeOptions=record
  Name: String[255];
  Surname: String[255];
  Address: String[255];
  EMail: String[255];
 end;

 TMainForm = class(TForm)
   TreeView: TTreeView;
   Panel1: TPanel;
   NewBtn: TBitBtn;
   DelBtn: TBitBtn;
   SaveBtn: TBitBtn;
   Label1: TLabel;
   Label2: TLabel;
   Label4: TLabel;
   Label5: TLabel;
   NameEdit: TEdit;
   SurnameEdit: TEdit;
   AddressEdit: TEdit;
   EMailEdit: TEdit;
   procedure NewBtnClick(Sender: TObject);
   procedure SaveBtnClick(Sender: TObject);
   procedure TreeViewChanging(Sender: TObject; Node: TTreeNode;
     var AllowChange: Boolean);
   procedure DelBtnClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.NewBtnClick(Sender: TObject);
var
NodeName:String;
NodeData:PNodeOptions;
NewNode:TTreeNode;
begin
if not InputQuery("Новый элемент", "Введите имя нового элемента",
    NodeName) then exit;

NewNode:=TreeView.Items.AddChild(TreeView.Selected, NodeName);

// Инициализация начальных данных структуры
NodeData:=new (PNodeOptions);
NodeData.Name:="";
NodeData.Surname:="";
NodeData.Address:="";
NodeData.EMail:="";

NewNode.Data:=NodeData;
end;

procedure TMainForm.SaveBtnClick(Sender: TObject);
begin
if TreeView.Selected=nil then exit;

PNodeOptions(TreeView.Selected.Data).Name:=NameEdit.Text;
PNodeOptions(TreeView.Selected.Data).Surname:=SurnameEdit.Text;
PNodeOptions(TreeView.Selected.Data).Address:=AddressEdit.Text;
PNodeOptions(TreeView.Selected.Data).EMail:=EMailEdit.Text;
end;

procedure TMainForm.TreeViewChanging(Sender: TObject; Node: TTreeNode;
 var AllowChange: Boolean);
begin
if Node=nil then exit;

NameEdit.Text:=PNodeOptions(Node.Data).Name;
SurnameEdit.Text:=PNodeOptions(Node.Data).Surname;
AddressEdit.Text:=PNodeOptions(Node.Data).Address;
EMailEdit.Text:=PNodeOptions(Node.Data).EMail;
end;

procedure TMainForm.DelBtnClick(Sender: TObject);
begin
if TreeView.Selected=nil then exit;
TreeView.Selected.Delete;
end;

end.



Если в ней я смогу сохранить данные, то в своей я уже сохраню. Дальше я разберусь. У меня написана достаточно большая программа, которую я писал руководствуясь учебником и примерами из интернета. Она уже готова, полностью работоспособна. Затык только с сохранением сабжа. Примеров с исходниками в интернете нет! Я уже трое суток просто занимаюсь поиском, хоть какого-нибудь законченного примера.

Нашел два приемлемых варианта.
1. http://k210.org/delphi/main/1/ - он много где упоминается. Но я не понимаю как получить и считать из него файл. Я вижу, что для этого нужна процедура saveProc ( writer: TWriter; data: Pointer ); однако написать эту процедур я не могу. выше мне было сказано, что это очень просто-для программиста может и просто.

2. http://www.delphimaster.net/view/2-1278064750 - здесь тоже два куска, причем, видимо с описками. Некоторых враз я не понимаю (вше спрашивал) и поэтому не могу связать эти части вместе и найти ошибку. Хотя топикстартер там говорит, что она у него заработала.

Больше ничего я найти не могу. Все остальное слишком сложное для меня или просто не по теме.
Программу я пишу для себя. поэтому хлеб ни у кого не отнимаю. Профессионально программированием заниматься не собираюсь, потому что у меня совершенно другой профиль (информационная безопасность (Сертификаты CISCO ASA, КАT6), Программистов у меня знакомых здесь нет. Я здесь в командировке на год.

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


 
Юрий Зотов ©   (2013-09-14 14:00) [15]

> wervolfe ©   (14.09.13 13:02) [14]

Ну, положим, примеры с исходниками в Интернете все же есть - хотя бы, все тот же пример, который Вы обозначили "Вариант 1". Естественно, код в нем неполный - и теперь, надеюсь, Вы понимаете, что полным он быть не может, потому что только Вам (а не автору примера) известно, какие именно данные Вы собираетесь сохранять.

Так что пример есть, просто он рассчитан на немного более "продвинутого" программиста - который понимает, как определить функцию обратного вызова, как ее написать, как работать с указателями и потоками.

Вот те 2 функции обратного вызова, которые нужны для варианта 1:

type
 PNodeOptions = ^TNodeOptions;
 TNodeOptions = record // Тип переименован - так принято в Delphi
   Name: string[255];
   Surname: string[255];
   Address: string[255];
   EMail: string[255];
 end;

procedure NodeSaveDataProc(Writer: TWriter; Data: Pointer);
begin
 Writer.WriteListBegin;
 with TNodeOptions(Data^) do
 begin
   Writer.WriteString(Name);
   Writer.WriteString(Surname);
   Writer.WriteString(Address);
   Writer.WriteString(EMail);
 end;
 Writer.WriteListEnd;
end;

function NodeLoadDataProc(Reader: TReader): Pointer;
var
 P: PNodeOptions;
begin
 New(P);
 Reader.ReadListBegin;
 with P^ do
 begin
   Name := Reader.ReadString;
   Surname := Reader.ReadString;
   Address := Reader.ReadString;
   EMail := Reader.ReadString;
 end;
 Reader.ReadListEnd;
 Result := P
end;

А вот, собственно, и само сохранение/чтение в варианте 1:

const
 FileName = "D:/Temp/TreeViewWithData.bin";

procedure TForm1.SaveButtonClick(Sender: TObject);
var
 S: TFileStream;
begin
 S := TFileStream.Create(FileName, fmOpenWrite);
 try
   SaveTreeViewToStream(TreeView1, S, NodeSaveDataProc);
 finally
   S.Free;
 end;
end;

procedure TForm1.LoadButtonClick(Sender: TObject);
var
 S: TFileStream;
begin
 S := TFileStream.Create(FileName, fmOpenRead);
 try
   LoadTreeViewFromStream(TreeView1, S, NodeLoadDataProc);
 finally
   S.Free;
 end;
end;

Писал "с ходу" и код не проверял, поэтому возможны ошибки - ну это уже пусть будет Вашим "домашним заданием". Дебаггер поможет. Ну и спрашивайте, если что (только уже конкретно а не так, как в сабже).

Удачи!

PS
А string[255] лучше заменить на просто string. Во-первых, избавитесь от ограничения длины, а во-вторых (скорее всего) сэкономите память.


 
Юрий Зотов ©   (2013-09-14 14:08) [16]

> wervolfe ©   (14.09.13 13:02) [14]
> Я вообще был  шоке, когда узнал, то у дерева
> нет этого свойства по умолчанию.


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


 
Юрий Зотов ©   (2013-09-14 14:13) [17]

Небольшая поправка (так будет лучше):

function NodeLoadDataProc(Reader: TReader): Pointer;
var
 P: PNodeOptions;
begin
 New(P);
 try
   Reader.ReadListBegin;
   with P^ do
   begin
     Name := Reader.ReadString;
     Surname := Reader.ReadString;
     Address := Reader.ReadString;
     EMail := Reader.ReadString;
   end;
   Reader.ReadListEnd;
 except
   Dispose(P);
   raise;
 end;
 Result := P
end;


 
wervolfe ©   (2013-09-14 14:25) [18]

Спасибо огромное!!!! Сейчас проверю все. Вы не представляете как Вы мне помогли!!!


 
wervolfe ©   (2013-09-14 14:54) [19]


Procedure SaveTreeviewToStream( tv: TTreeview; S: TStream;
       saveProc: TNodeSaveDataProc );

Procedure LoadTreeviewFromStream( tv: TTreeview; S: TStream;
                 loadProc: TNodeLoadDataProc );


Где и каким образом правильно объявить TNodeLoadDataProc & TNodeSaveDataProc ?


 
wervolfe ©   (2013-09-14 15:18) [20]

С первым разобрался. Сделал как в примере.

Вот второе не пойму..((

Procedure LoadTreeviewFromStream( tv: TTreeview; S: TStream; loadProc: TNodeLoadDataProc );
Var
 reader: TReader;
 node: TTreenode;
 level: Integer;
Begin
 Assert( Assigned( tv ));
 Assert( Assigned( S ));
 Assert( Assigned( loadProc ));
 tv.Items.BeginUpdate;
 try
   tv.Items.Clear;
   reader:= TReader.Create( S, 4096 );
   try
     node:= nil;
     reader.ReadListBegin;
     While not Reader.EndOfList Do Begin
       level := reader.ReadInteger;
       If node = nil Then
       // create root node, ignore its level
         node:= tv.Items.Add( nil, "" )
       Else Begin
         If level = node.level Then
           node := tv.Items.Add( node, "" )
         Else If level > node.level Then
           node := tv.Items.AddChild( node, "" )
         Else Begin
           While Assigned(node) and (level < node.level) Do
             node := node.Parent;
           node := tv.Items.Add( node, "" );
         End; { Else }
       End; { Else }
       node.Text := Reader.ReadString;
       node.ImageIndex := Reader.ReadInteger;
       node.Data := loadProc( Reader );            // Ошибка. Incompatible Types                    
                                                                  TWriter & TReader
     End; { While }
     reader.ReadListEnd;
   finally
     reader.Free;
   end;
 finally
   tv.items.Endupdate;
 end;
End; { LoadTreeviewFromStream }


 
wervolfe ©   (2013-09-14 15:38) [21]

Юрий Зотов

Все! Все прекрасно работает! Ошибся сам. Спасибо, Юрий! Я уже не надеялся что получится как задумано!!!

Здесь нельзя редактировать собственные сообщения? (((


 
Туповатый ©   (2013-09-14 22:28) [22]

Можно. Но это привилегия красных штанов (админов т.е.)


 
wervolfe ©   (2013-09-15 07:09) [23]

Туповатый>  понял! Два раза Ку сделал (и присел)! ))

Юрий Зотов>  Юрий, я понмимаю, что наглость, но не могли бы Вы в примере №1 и в своих программах написать комментарии к строкам. Хотя бы к основным моментам. Это не срочно-если у Вас будет время. Хотелось бы понят как это делается, а не копировать как обезьяна! )))


 
Юрий Зотов ©   (2013-09-15 15:57) [24]

> wervolfe ©   (15.09.13 07:09) [23]

К основным моментам - можно. Главное для Вас - понять суть, основную идею кода. После этого уже можно будет переходить к разбору деталей реализации.

Итак, ставим себя на место создателя примера 1 и начинаем думать. Наша задача - сохранить данные, о которых нам заранее ничего не известно. Мы лишь знаем адрес этих данных (его содержит свойство Data) и знаем, что сами данные могут быть любыми. Как ни странно, именно последнее и дает ключ к решению.

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

Задаемся вопросом - а что это за параметры? Мы решили сохранять данные в поток (почему именно в поток - об этом скажу позже). Значит, пользовательской процедуре сохранения нужно передать:
1. Адрес данных (Data), которые надо записать.
2. Вспомогательный объект (TWriter) - который, собственно, их и пишет.

Сам поток (TStream) передавать не надо, потому что TWriter его и так знает. Ура! - мы определили заголовок пользовательской процедуры сохранения:
procedure <любое_имя> (Writer: TWriter; Data: Pointer);

Аналогично и с пользовательской процедурой чтения. За исключением того, что:
1. Вместо TWriter ей нужен TReader - именно он, собственно, и читает данные.
2. Удобнее сделать ее не процедурой, а функцией - ведь она должна создать экземпляр данных в памяти, заполнить его из потока и вернуть нам его адрес.

Сам поток (TStream) тоже передавать не надо, потому что TReader его тоже знает. В итоге получаем такой заголовок пользовательской процедуры чтения:
function <любое_имя> (Reader: TReader): Pointer;

Теперь наша задача стала более конкретной - надо пройти по дереву и для каждой его ветки вызвать пользовательскую процедуру сохранения (или чтения). Но как мы ее вызовем? - ведь мы же не знаем ее имени, а оно может быть любым. Значит, вызывая нашу процедуру, юзер должен передать ей свою процедуру, как параметр. Такой прием называется "обратный вызов" (callback) - юзер вызывает наш код, а из нашего кода снова вызывается код юзера. Для реализации этого приема нужно определить прототипы пользовательских функций обратного вызова - что мы и делаем:
type
 TNodeSaveDataProc = procedure(Writer: TWriter; Data: Pointer);
 TNodeLoadDataProc = function(Reader: TReader): Pointer;


Теперь наш код, получив в своих параметрах юзерскую функцию обратного вызова будет знать, как именно ее нужно вызвать. Кроме этой функции, в параметрах наш код должен получить сам TreeView (чьи даннные нужно писать/читать) и поток TStream (в который/из которого нужно писать/читать). Еще раз ура! - мы определили заголовки наших процедур чтения/записи:
procedure SaveTreeViewToStream(TV: TTreeview; S: TStream; SaveProc: TNodeSaveDataProc);
procedure LoadTreeViewFromStream(TV: TTreeview; S: TStream; LoadProc: TNodeLoadDataProc);


Собственно, наша задача уже практически решена. Остался пустяк - написать код этих двух наших процедур. Но это уже вопрос реализации, к идее он не относится и мы его пока рассматривть не будем - сначала надо понять саму идею.

И последнее - почему мы решили, что данные следует читать/писать именно из потока/в поток TStream?

Для универсальности. Потоки бывают самые разные, но все они имеют общего предка - класс TStream. Хочет юзер работать с файлом - использует TFileStream (что мы в данном случае и сделали). Хочет работать с памятью - использует TMemoryStream. Хочет работать с базой данных - использует TBlobStream. Хочет, чтобы чтобы данные писались на сервер на Мальдивах, а читались с сервера на Канарах - создает нужные ему потомки TStream и использует их. А наш код во всех случаях остается неизменным - он универсален и может читать/писать что угодно и откуда/куда угодно.

Фуф! Для начала, думаю, Вам хватит. Осмыслите все это, потом можно будет переходить к вопросам конкретной реализации.

PS
И еще - осмыслите, что такое указатели и как с ними работать. Без этого Вы код не поймете.


 
[ВладОшин] ©   (2013-09-15 16:27) [25]


> Туповатый ©   (14.09.13 08:20) [1]

что именно 12(с) сказал не так?


 
Туповатый ©   (2013-09-15 17:07) [26]


> [ВладОшин] ©   (15.09.13 16:27) [25]

Не понял вопроса.


 
[ВладОшин] ©   (2013-09-15 17:48) [27]


> Туповатый ©   (14.09.13 08:20) [1]
>
> это не статья. это - ветка форума, иными словами - многолог
> кого-то с кем-то и тем-то. и далеко не всегда там есть истина.
>  

Там говорил 12 (с) и еще кто-то
Что неправильно гоаорил 12?


 
Туповатый ©   (2013-09-15 18:23) [28]

А... нет, я вовсе не про конкретно ту ветку конкретно того форума. Имел ввиду вообще, что форумы не всегда содержат истину.


 
wervolfe ©   (2013-09-15 22:05) [29]

Юрий Зотов> Спасибо. Учу теорию! Буду разбираться.

У меня такой вопрос...
Вот таким кодом (из того же примера) добавляем ноды.
procedure TMainForm.NewBtnClick(Sender: TObject);
var
NodeName:String;
NodeData:PNodeOptions;
NewNode:TTreeNode;
begin
if not InputQuery("Новый элемент", "Введите имя нового элемента",
    NodeName) then exit;

NewNode:=TreeView.Items.AddChild(TreeView.Selected, NodeName);

// Инициализация начальных данных структуры
NodeData:=new (PNodeOptions);
NodeData.Name:="";
NodeData.Surname:="";
NodeData.Address:="";
NodeData.EMail:="";

NewNode.Data:=NodeData;
end;


Происходит это так...Если не производить ни одного клика внутри TreeView, то нажатием кнопки добавляется корневая нода (level=0). Одна, две - сколько нужно.
Однако, если крикнуть по любой из них, то после клика происходит уже добавление ветвей (level  1?2 и тд). Еще одну ноду 0 уже добавить никак нельзя. Поэтому я на кнопку "создать" повесил
TreeView.Items.Add
а на двойной клик мыши уже TreeView.Items.AddChild.
Level=2 мн не нужен (наоборот, его создание у меня запрещено) поэтому все прекрасно работает.
Однако, я думаю, что это решение не красивое. Как следовало сделать?


 
Юрий Зотов ©   (2013-09-15 23:22) [30]

> wervolfe ©   (15.09.13 22:05) [29]

Я тоже думаю, что это решение не лучшее. Во-первых, оно не очевидно для юзера - ну как он догадается, что для создания Subitem нужно делать двойной клик? Во-вторых, двойной клик юзер может сделать и случайно (а иногда это делает и сама мышка, если она не совсем исправна - так называемый "дребезг контактов").

Посмотрите, как устроен редактор дерева в самой Delphi - чем плохо? Я бы сделал так же.


 
Юрий Зотов ©   (2013-09-15 23:29) [31]

> wervolfe ©   (15.09.13 22:05) [29]

Кроме того, программа должна уметь работать и с клавиатуры, вообще без всякой мышки. Поэтому привязываться только к двойному клику нельзя. Нужны две кнопки (New item и New subitem) c горячими клавишами.


 
wervolfe ©   (2013-09-15 23:31) [32]

Добавлять правой кнопкой мыши? Попробую...Спасибо.


 
wervolfe ©   (2013-09-15 23:37) [33]

Две кнопки - жутко неудобно. Самое лучшее решение было бы по правой кнопке мыши вызвать всплывающее меню и в нем выбирать. Его и буду, наверное пытаться реализовывать.


 
wervolfe ©   (2013-09-15 23:45) [34]

А...Я понял о чем Вы! Отдельная форма с кнопками, вызываемая правым кликом. Да. Я не подумал об этом! Спасибо!


 
Туповатый ©   (2013-09-15 23:45) [35]


> по правой кнопке мыши вызвать всплывающее меню

туда еще можно добавить свертку-развертку всего дерева


 
Юрий Зотов ©   (2013-09-16 00:05) [36]

> wervolfe ©   (15.09.13 23:45) [34]

Ну да, отдельная (причем модальная) формочка редактора. Как и в самой Delphi.


 
wervolfe ©   (2013-09-17 13:28) [37]

Варианты с отдельной формой неудобны в моем случае. Сделал просто менюшку  из стандартной попАп.

Разбираюсь с теорией. Я так понимаю, что если данные заведомо текстовые, то можно было не наворачивать такие конструкции как разобраны выше, а сделать только :

procedure TMainForm.SaveTreeToFile;
const
TabChar = #9;
EndOfLine = #13#10;
var
i: Integer;
Node: TTreeNode;
Str: string;
p: pointer;
fs:TStringList;
begin
  fs:=TStringList.Create;
  Node := TreeView.Items.GetFirstNode;
  while Node <> nil do
  begin
    Str := "";
    for i := 0 to Node.Level - 1 do Str := Str + TabChar ;
    Str := Str + Node.Text + EndOfLine + PNodeOptions(Node.Data).Name + EndOfLine + PNodeOptions(Node.Data).Surname + EndOfLine + PNodeOptions(Node.Data).Address + EndOfLine + PNodeOptions(Node.Data).EMail + EndOfLine;
    p:=@Str;
    fs.Add(string(p^));
    Node := Node.GetNext;
  end;
  fs.SaveToFile("Tree.dat");
  fs.Free;
end;


?? если из этого, конечно, получится восстановить теперь...))


 
Туповатый ©   (2013-09-17 23:50) [38]

Слишком сложно, как-то.
если данные фиксированы, т.е. есть Некий Некиевич Некиев, у которого есть адрес телефон и еще что-то, и у всех остальных точно так же (нет вариантов, что у одного 6 свойств, у другого 4  вместо 4 и 2 пустых), то получается, что их можно без всяких табов и вк свалить в стринглист. И тогда легко восстановить, ведь мы знаем, что с начиная с первой и через каждые (к примеру из 6 свойств) 5 строк - фамилия, со второй через каждые 5 - имя и т.д.

fs:=TStringList.Create;
 Node := TreeView.Items.GetFirstNode;
 while Node <> nil do
 begin
   for i := 0 to Node.Level - 1 do begin
     fs.Add(Node.Text);
     fs.Add(PNodeOptions(Node.Data).Name);
и т.д.

   end;
   Node := Node.GetNext;
 end;
 fs.SaveToFile("Tree.dat");
 fs.Free;

уже очень плохо помню обращение к нодам, поэтому этот пример - просто переделка [37], без претензии на абсолютную правильность


 
Туповатый ©   (2013-09-17 23:53) [39]

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


 
wervolfe ©   (2013-09-18 10:26) [40]

Туповатый>
Да. Так тоже работает. Получается такой длинный столбик! Это уже так...Я просто разбираюсь. Код написанный Юрием прекрасно работает. А, как известно, работает - не трогай! ))


 
wervolfe ©   (2013-09-18 10:32) [41]

В моем случае такой способ тоже пойдет. У меня в программе для внесения данных пользователь заполняет форму. Добавлять или убавлять он поля не может. Производится проверка на обязательность заполнения всех полей. И все это можно делать только в level=1. Все делево у меня имеет только уровень 0 и уровень 1. Данный содержаться только в уровне 1. Так что все просто. (когда разберешься! ))



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

Форум: "Начинающим";
Текущий архив: 2014.07.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.62 MB
Время: 0.003 c
15-1388917568
Kerk
2014-01-05 14:26
2014.07.27
Загадки УФМС


15-1388437065
wl
2013-12-31 00:57
2014.07.27
Москва, врачи lasik


15-1388818291
EsetNOD32
2014-01-04 10:51
2014.07.27
Anatoly Podgoretsky - как это понимать?


15-1388477504
antonn
2013-12-31 12:11
2014.07.27
непонятная физика =)


15-1388955474
Рифмоплет
2014-01-06 00:57
2014.07.27
Можно ли поручить Дельфи творчество?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский