olegenty |
Отправлено: 26.08.2005, 09:07 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
суть.
1. простенькие типы для работы с универсальным справочником:
CODE |
typedef map<AnsiString, Variant> TValMap; // Result Fields Type
typedef auto_ptr<TValMap> TValMapPtr; // Result Fields Pointer Type
typedef pair<bool, TValMapPtr> TResPair; // Result Fields Pointer Pair Type
typedef auto_ptr<TResPair> TResPairPtr; // Result Fields Pointer Pair Pointer Type
|
2. как же это можно использовать. есть некая формёшка, которая по имени справочника выполняет некий запрос к БД и выводит его юзеру. юзер скроллируется, и нет-нет, да выберет какую-нибудь строку. вот что происходит дальше (если он нажал OK):
CODE |
TValMapPtr Fields(new TValMap);
TFields *f = ds->DataSet->Fields;
TField *p = NULL;
for (int i = 0; i < f->Count; ++i)
{
p = (*f)[i];
(*Fields)[p->FieldName] = p->Value;
}
return TResPairPtr(new TResPair(true, Fields));
|
а это, если ничего не выбрал:
CODE |
return TResPairPtr(new TResPair(false, static_cast<TValMapPtr>(NULL)));
|
а пользоваться результатом так:
CODE |
TResPairPtr r = Callback->LookupDict(dbgRouteSpec->InplaceEditor, "Measure");
if ((*r).first)
{
TValMapPtr Fields = (*r).second;
TDataSet *d = dbgRouteSpec->DataSource->DataSet;
if (d->State != dsEdit) d->Edit();
d->FieldByName("Short")->AsString = (*Fields)["Short"];
d->FieldByName("MeasureID")->AsInteger = (*Fields)["MeasureID"];
}
|
в результате, проблема с тормозными лукап полями отваливается раз и навсегда, а код вроде достаточно универсален. кроме прочего, избавляет от переменного числа параметров ссылочного типа, для разного числа используемых полей.
а теперь критикуйте (может как-то ещё лучше можно сделать).
|
|
AVC |
Отправлено: 26.08.2005, 10:08 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Отлично!
Я от lookup отказался много лет назад и использую подобную технологию, правда реализованную "по-старинке" при помощи класса на базе TList и нескольких универсальных форм (функций). Давно чесались руки перевести на stl (но это такой объем работы...). А тут вижу готовую реализацию.
А теперь замечания.
Мне кажется, что pair и далее излишни — можно вернуть NULL при отказе от выбора, или я ошибаюсь?
По собственному опыту могу сказать, что map'а для действительно универсального использования мало. Может map vector'ов? Иногда нужны одноименные поля и поиск "от головы" и "от хвоста". И т.д. и т.д. Но это все для серьезной универсализации. Если будет интересно могу показать перечень методов, которыми за несколько лет "оброс" у меня этот класс. |
|
olegenty |
Отправлено: 26.08.2005, 10:29 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
у меня тоже был TList, но map приятнее, не нужны проверки на уникальность имени поля, проще в использовании. в обёртке auto_ptr — гарантированность от утечки ресурсов. относительно pair, да, наверное можно и просто NULL, но пока оставлю так, имел я проблему, когда "клиент" получал NULL вместо auto_ptr< ...>, потому что потом auto_ptr вызывает delete, a delete NULL приводило к AV. а вот про
map < AnsiString, vector < Variant>> — это вполне, ты только тогда объясни зачем и как хотел бы использовать (мне пока такого было не надо).
Отредактировано olegenty — 26/08/2005, 11:31
|
|
AVC |
Отправлено: 26.08.2005, 10:52 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE |
меня тоже был TList, но map приятнее
|
Когда я его начинал я не использовал stl (из за незнания). Да и до сих пор не очнь активно ее использую (каюсь)
QUOTE |
map < AnsiString, vector < Variant>> — это вполне, ты только тогда объясни зачем и как хотел бы использовать (мне пока такого было не надо).
|
Повторюсь — речь не о справочниках.
Иногда нужны одноименные поля и поиск "от головы" и "от хвоста". И т.д. и т.д
Кроме того пары имя — значение (что дает тебе map) маловато. Например к каждому полю я еще храню заголовок, формат, шаблон ввода и тд (всего 11 описаловок) и этого иногда не хватает. Этот класс я использую практически везде и это позволяет мне делать универсальные, самонастраиваущиеся функции. Параметр — указатель на экземпляр, а это означает переменное число параметров типов, которые можно запихнуть в вариант + практически любой возврат. Это, конечно, где-то противоречит концепции ООП, но так удобно.
|
|
olegenty |
Отправлено: 26.08.2005, 11:07 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
стоп. то, что привёл, возращает значения всего одной строки.
тогда давай так: ты скажи, что должно передаваться, а я изображу это на stl, потом покажем Георгию, он оценит (я с stl всего несколько месяцев, как начал работать. тащусь, как удав по стекловате.)
|
|
AVC |
Отправлено: 26.08.2005, 11:34 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE |
стоп. то, что привёл, возращает значения всего одной строки
|
Справедливо, но
1. Полей в этой строке неограниченное количество — я обычно делаю такую штуку
параметр вызова дочерней функции/формы
= входные параметры формы
+ все значения редактируемые этой формой
+ значения всех полей текущей строки основного ds этой формы
2. У меня естественно есть класс массив таких строк
3. пунк 2 не нужен а надо, наверное, vector.
Как и DataSet я всегда работаю с одной (текущей) строкой. Операции над выборкой пусть делает сервер.
QUOTE |
давай так: ты скажи, что должно передаваться, а я изображу это на stl, потом покажем Георгию
|
Нее. Мне самому интересно перевести свой класс на stl. Такая практика (правда если доживу).
Возвращаясь к первому топику — по моему дилетанскому мнению там все нормально (pair на твоей совести). Разве что стоит предусмотреть возврат MultiSelect, но это на будущее.
Кстати для твоего примера использования у меня в классе предусмотрены два метода ->GetAllFields и ->PutAllFields со всякими наворотами типа анализа RO или списками полей. Но в простом случае rec->GetAllFields(ds2)->PutAllFields(ds1);
|
|
olegenty |
Отправлено: 26.08.2005, 12:14 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
всё, я поплыл. нифига не понял (почти).
массив значений я никогда не передам, как мап вариантов, на это есть TMemTableEh — передавай, не хочу. мультирекорд засуну туда, и как-то оберну в STL. и редактироваться будет стандартным образом.
но напряг в понимании от того, что у меня нет универсальных форм. ЭТО не поддаётся универсализации (вернее, поддаётся, но я ещё не дорос конструировать на лету структуру формы, с подчинёнными деревьями и прочими вещами, с автораскраской по хаданным правилам и т.д.)
|
|
AVC |
Отправлено: 26.08.2005, 12:37 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Считаем со справочниками закончили (по крайней меры мы с тобой )?
QUOTE |
но я ещё не дорос конструировать на лету структуру формы, с подчинёнными деревьями и прочими вещами, с автораскраской по хаданным правилам и т.д.)
|
Не прибедняйся. Просто ты не ставил такой задачи. Ни чего сложного в этом нет если строить не произвольную форму, а одну из заранее разработанного шаблона (не stl а именно шаблона). Что сложного прочитать какие части нужны, как их покрасить и что делать по заранее определенным событиям?
Первый вариант я реализовал около 2 лет назад и с тех пор "тащусь, как удав по стекловате". Попробуй переформулировать свое приложение и свести его к 5-6 универсальным формам, а уж на них можно так развернуться...! |
|
olegenty |
Отправлено: 26.08.2005, 13:13 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
я не про такую раскраску. у меня зело накрашенные гриды. красятся из накоторых соображений, в зависимости от значений полей. я ещё пока не придумал, как это реализовать. придумаю — постараюсь предствить форму как набор "фреймов" — по сути, придётся реализовать что-то своего собственного DFM, с предопределёнными обработчиками событий. но это чуть позже.
|
|
avc* |
Отправлено: 26.08.2005, 13:39 |
|
Не зарегистрирован
|
QUOTE |
не про такую раскраску. у меня зело накрашенные гриды. красятся из накоторых соображений, в зависимости от значений полей. я ещё пока не придумал, как это реализовать
|
И я не про такую. С гридами я сделал так (на уровне идеи)
CODE |
Select ...
-- простой варинт
,Decode(NVL(IsActive,0), 0,''Gray'', ''Black'') as Row_FColor
-- Сложный вариант — условие отбора (а может и цвет) выбиратся
-- пользователем, как один из параметров запроса
<#ifNotEmpty pWhatLight_CMD#>
,(Case
when <#fld pWhatLight_CMD#> then ''red''
else ''black''
end
) as Row_FColor
<#/ifNotEmpty pWhatLight_CMD#>
--
|
Это было по строкам
А так по колонкам
CODE |
vmap := HHC.TFieldsMap(-- Name Visible Len Title Align Format FColor BColor BColorLo
HHC.TFieldMap.NewFormaItem('Grid_StaticColumns', 'MeasureDate')
,HHC.TFieldMap.NewItem('MeasureDate', 1, 12, 'Дата', 'c', 'dd.mm.yy', 'Blue', '#F0F0F0', 'White')
,HHC.TFieldMap.NewItem('RecoundID', 0)
,HHC.TFieldMap.NewItem('ORD', 0)
--
,HHC.TFieldMap.NewItem('PAYSUM1', 1, 7, 'Оплата', 'r', 'd2' )
,HHC.TFieldMap.NewItem('DOLG', 0, 8, 'Долг', 'r', 'd2', 'Red', '#F0F0F0', 'White')
,HHC.TFieldMap.NewItem('DOLGsNDS', 1, 8, 'Долг|с ндс', 'r', 'd2', 'Red', '#F0F0F0', 'White')
,HHC.TFieldMap.NewItem('DOLGNDS', 1, 7, 'НДС', 'r', 'd2', 'Black', '#F0F0F0', 'White')
,HHC.TFieldMap.NewItem('AVANS', 1, 8, 'Аванс', 'r', 'd2', 'Green', '#F0F0F0', 'White')
|
А так весь грид
CODE |
--HHC.AppM.UESetGridColor(vmap, vGroupName);
--
-- Эту форму буду раскрашивать вручную
--
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Grid_FColor', '#000000'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Grid_BColor', '#F6FfF6'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Grid_BColorLo', 'white' ));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Record_ExtendInfo_FColor', '#0000Ff'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Record_ExtendInfo_BColor', '#FfFfF0'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('Record_ExtendInfo_BColorLo', 'white' ));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('SubTitle_FColor', '#000000'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('SubTitle_BColor', '#FfFfFf'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewFormaItem('SubTitle_BColorLo', 'white' ));
--
|
А так, что делать по нажатию клавиш
CODE |
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.Go_AxRec ('AxPing', 'Ping'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.Go_AxRec ('SVLanSub_CheckStateAll', 'Кто в сети', '', 'HCSVISOR', 0,0));
|
А так какие и как считать суммы
CODE |
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewSumItem('Account', 'Count', '0'));
HHC.p_TFieldsMap_Add(vmap, HHC.TFieldMap.NewSumItem('PotC1', 'Sum', '0'));
|
и т.д. (это куски того самого скрипта) на PLSql |
|
olegenty |
Отправлено: 26.08.2005, 13:50 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
PlSQL — тёмный лес, но идея яснее ясного.
|
|
olegenty |
Отправлено: 26.08.2005, 13:55 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
я хочу сделать по-другому. так не нравится, потому что 50% получаемой от сервера информации в этом случае — служебная. поэтому на сервере хочу хранить только некоторым образом описанный алгоритм раскраски. а на клиенте для алгоритмов иметь универсальный и быстрый разборщик, который будет запускаться в OnDrawColumnCell грида.
|
|
AVC |
Отправлено: 26.08.2005, 13:57 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Маленькое добавление. (упустил )
Не смотри на HHC.TFieldMap.New...
У меня это просто способ добавить строку в динамический создаваемый курсор. На Oracle это легко сделать через объект. |
|
AVC |
Отправлено: 26.08.2005, 14:04 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE |
не нравится, потому что 50% получаемой от сервера информации в этом случае — служебная
|
Откуда?
Скрипт читается и анализируется один раз при старте формы, а в рабочий запрос можно (именно можно а не нужно) добавть три поля Row_FColor, Row_BColor и Row_BColorLo. Если их нет, то используются правила колонки — сетки — шаблона формы.
А закон раскраски в этом случае я могу определить очень гибко именно для конкретно сейчас выполняемого запроса.
|
|
|