Форум: "Начинающим";
Текущий архив: 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