Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Компоненты и классы
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 08.02.2013, 06:59
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Нестандартная задача. Создание класса

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

Код:
var
Opt:TMyClass; //экземпляр класса
Var1:integer;
begin
Opt := TMyClass.Create;
Opt['Category']['SubCategory']['SubSubCategory']['Option1'] := 'qwe';
{Строчка выше означает, что класс должен создать (если ранее не создано) категорию 'Category', 
в ней Подкатегорию 'SubCategory', в ней еще подкатегорию 'SubSubCategory' (то есть все в виде дерева), 
в ней опцию 'Option1' и присвоить этой опции значение 'qwe'}
Var1 := Opt['Category']['Option2'];
{Строчка выше означает, что переменной Var1 типа integer должно присвоиться значение опции 'Option2' 
из категории 'Category', если данные опция и категория созданы
}
end;

То есть при первом же рассмотрении встает вопрос, как сделать так, чтобы у дефолтной property функции для read и write имели разные типы данных?
Типа того:
Код:
TCategory = Class;
TMyClass = Class
private
function GetV(Name:string):TCategory;
procedure SetV(Name:string;Value:STRING);
public
property Cat[Name:string]:TCategory read GetV write SetV; default;
end;
Само собой компилятор в этом случае выдает ошибку о несовпадении типов.
Ответить с цитированием
  #2  
Старый 08.02.2013, 09:36
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
По умолчанию

похожее делал так:
Код:
procedure InitIni;
begin
  inimap := TiniManager.Create('ini.ini')
  inimap.define('section', 'somevar', '100', TInt.Create(@intvar));
  inimap.define('section', 'somevar2', 'default', TStr.Create(@strvar));
  inimap.define('section', 'somevar3', 'yes', TBool.Create(@boolvar));
  inimap.define('main', 'form-x', '100', TProp.Create(Form1, 'left'));
  inimap.define('main', 'form-y', '100', TProp.Create(Form1, 'top'));  
end; 

inimap.write;
inimap.read;

хотя TProp.Create(...) можно заменить разными версиями метода .define
__________________
>woweook<

Последний раз редактировалось Pyro, 08.02.2013 в 09:56.
Ответить с цитированием
  #3  
Старый 10.02.2013, 08:42
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Что? Где в вашем сообщении ответ на мой вопрос?
Ответить с цитированием
  #4  
Старый 10.02.2013, 09:53
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
По умолчанию

variant пробовал?
__________________
>woweook<
Ответить с цитированием
  #5  
Старый 11.02.2013, 05:00
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

А разве в варианте можно хранить экземпляр класса? Даже если и можно, я не смогу обращаться с переменной типа вариант, как с экземпляром класса. Ну разве что делать так:
with opt['Category'] as TCategory
with ['SubCategory'] as TCategory
****
И так далее. А должно выглядеть так, как я написал в первом сообщении.
Цель - сделать программу легко перевариваемую программистами, чтобы один мог написать, другой подправить. Уже наделал кучу классов для красивого кодинга в дальнейшем. Споткнулся вот на этом.
Ответить с цитированием
  #6  
Старый 11.02.2013, 08:33
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
Сообщение

вот такие варианты есть
Код:
Var1 := Opt['Category','Option2'];
Var1 := Opt['Category']['Option2'].get

Var0 := Opt['Category','Sub'].get('Option1');
with Opt['Category','Sub'] do
begin
  Var1 := get('Option2')
  Var2 := get('Option3')
end

а предыдущий код который я выкладывал - для того что бы избавиться от дублирования при записи/чтении
__________________
>woweook<

Последний раз редактировалось Pyro, 11.02.2013 в 09:03.
Ответить с цитированием
  #7  
Старый 11.02.2013, 10:34
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Код:
Var1 := Opt['Category','Option2'];
Var1 := Opt['Category']['Option2'].get
 
Var0 := Opt['Category','Sub'].get('Option1');
with Opt['Category','Sub'] do
begin
  Var1 := get('Option2')
  Var2 := get('Option3')
end
Да, это все, что я смог осуществить. Ну, разве что get(string) я сделал в виде дефолтной property. Но количество подкатегорий при этом ограниченное. Не больше и не меньше чем я сделал (то есть если я указал, что их 3, то нужно использовать именно 3).
Это не то, что я хотел, но пока будет так. Во всяком случае, если мне удастся сделать то, что я задумал (переделать класс), то это никак не повлияет на уже написанный код с использованием данного класса. Так что вопрос остается открытым.

Пока что обращение к классу выглядит так:
Код:
var
Var1:string;
Var2:integer;
Opt:TMyClass;
Begin
Opt:=TMyClass.Create;
Opt['Category']['SubCategory']['Option1']:=5;
Opt['Category']['SubCategory']['Option2']:=6;
Opt['Category']['SubCategory']['Option3']:='qwe';

Var1:=Opt['Category']['SubCategory']['Option3'][1];
Var2:=Opt['Category']['SubCategory']['Option2'] - Opt['Category']['SubCategory']['Option1'];
end;
В результате Var1 = 'q'
Var2 = 1
То есть средствами класса определяются нужные типы данных (принимаются и возвращаются не variant, а именно string или integer или real, в зависимости от типа переменной, в которую считывается или из которой записывается).

Не получается лишь сделать путь к опции в виде правильного Х-уровневого дерева. То есть для сей конструкции есть класс Опции, в котором хранится экземпляр класса Категории, в нем экземпляр класса Подкатегории, а в нем уже екземпляр класса Настройки. Если захочу сделать больше подкатегорий, то придется делать дополнительные классы для них. Если завяжу класс категории сам на себя, то не смогу в нужный момент извлечь таким же способом опцию (точнее смогу, только способом .get('Option1'), а мне надо дефолтной property, но в дефолтной property уже будет стоять ссылка на класс категорий). Вот такие дела...
Ответить с цитированием
  #8  
Старый 11.02.2013, 10:49
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Еще можно сделать обращение вида:
Opt['Category/SubCategory/SubSubCategory/Option'], но это не красиво выглядит.

Еще можно было бы сделать так:
Opt['Category','SubCategory',........,'Option1']
То есть переменным числом параметров, но я не знаю как это сделать. Так же работает функция Write/Writeln (и еще некоторые функции) - принимает любое количество параметров, но я не могу понять, как это реализовано.
Ответить с цитированием
  #9  
Старый 11.02.2013, 10:56
stanilar stanilar вне форума
Прохожий
 
Регистрация: 31.08.2009
Сообщения: 30
Репутация: 140
По умолчанию

Может небольшая редакция требований спасет отца русской демократии:


Код:
Opt['Category']['SubCategory']['Option1'].Value:=5;
...
Var1:=Opt['Category']['SubCategory']['Option3'][1].Value;
Ответить с цитированием
  #10  
Старый 11.02.2013, 12:46
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Может небольшая редакция требований спасет отца русской демократии:
А зачем? Это же и так ясно. Я уже даже подкорректировал некоторые компоненты, типа TEdit, TLabel, чтобы не писать имена свойств Text и Caption. Ведь чаще всего от Едита нам нужен именно текст, поэтому к тексту едита я теперь обращаюсь просто по имени компонента (string := Edit1, вместо string := Edit1.Text).
Ответить с цитированием
  #11  
Старый 11.02.2013, 13:29
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
По умолчанию

Цитата:
Сообщение от morebeauty
string := Edit1, вместо string := Edit1.Text
круть, а типы тоже угадывает?
Код:
например intvar := Edit1
Цитата:
Opt['Category','SubCategory',........,'Option1']
с квадратными скобками не сделать, но можно с круглыми:

Код:
Opt(a: array of string)
...
Opt(['Category','SubCategory',........,'Option1'])
__________________
>woweook<

Последний раз редактировалось Pyro, 11.02.2013 в 13:46.
Ответить с цитированием
  #12  
Старый 11.02.2013, 13:58
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
круть, а типы тоже угадывает?
По возможности конвертирует все в string, в противном случае выдает ошибку с грустным смайликом )

Цитата:
с квадратными скобками не сделать, но можно с круглыми:
Write устроена иначе. Хотелось бы использовать такой же метод, но я слишком..... эммм.... мало осведомлен, чтобы это сделать. А именно такой способ (как вы предложили) не удобен и не красив.
Ответить с цитированием
  #13  
Старый 11.02.2013, 14:21
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
По умолчанию

в старших дельфях можно так попробовать:
Код:
type
   TMyClass = record // хз работает ли на классах
     class operator Implicit(a: Integer): TMyClass; //запись?
     class operator Implicit(a: TMyClass): Integer; //чтение?
http://docwiki.embarcadero.com/CodeE...s_%28Delphi%29
__________________
>woweook<
Ответить с цитированием
  #14  
Старый 11.02.2013, 14:48
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
Радость

сделай уже что б хоть как-то работало:
Код:
MyObj['Category\SubCategory\Option'] := '123';
v := MyObj['Category\SubCategory\Option'];
или:
Код:
MyObj.Category.SubCategory.Option := '123';
v := MyObj.Category.SubCategory.Option;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #15  
Старый 12.02.2013, 04:56
Аватар для morebeauty
morebeauty morebeauty вне форума
Начинающий
 
Регистрация: 21.06.2012
Сообщения: 106
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
сделай уже что б хоть как-то работало:
Код:
MyObj['Category\SubCategory\Option'] := '123';
v := MyObj['Category\SubCategory\Option'];
Это просто, но некрасиво. И при переборе опций я не смогу сделать так:
with MyObj['Category\SubCategory']
А опций может быть много...

Цитата:
или:
Код:
MyObj.Category.SubCategory.Option := '123';
v := MyObj.Category.SubCategory.Option;
А это совсем не подходит. Ведь не зря же названия категорий - стринги. Category и SubCategory на самом деле будут выглядеть как
MyObj['Globals']....
MyObj['Locals']['Interface']['MainForm']['Top']...
MyObj['Locals']['Interface']['MainForm']['Left']...
ну и так далее
То есть класс должен быть универсален, а не заточен под конкретное приложение.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 04:14.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter