Добрый день!
Скажите пожалуйста, можно ли каким-то образом задать фильтры на отображаемые в отчете поля (столбцы)?
Запрос возвращает все поля, а мне нужно дать возможность отображать только отмеченные на форме фильтров отчета.
Спасибо!

Нравится

12 комментариев

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

Например, создаём окно фильтрации, в котором галочками будут отмечаться колонки для отображения. В обработчике события OnPrepare отчёта считываем эти значения и записываем их в атрибуты отчёта. Дальше допустим, что у нас есть MasterData с полями Memo1, Memo2, Memo3. Тогда создаём обработчик события OnBeforePrint для MasterData, в котором проверяем: если атрибут, соответствующий полю Memo1, равен false, выполняем:

Memo1.Visible := false;
Memo2.Left := Memo1.Left;
Memo2.Width := ...;
Memo3.Left := Memo2.Left + Memo2.Width;
Memo3.Width := ...;

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

Вариант попроще: если есть несколько (два, три) самых распространённых вариантов отображения полей, можно создать в отчёте три страницы, которые будут отличаться только набором полей. Дальше в окне фильтрации предлагать выбрать один из вариантов отображения, а в обработчике события OnStartReport объекта Report определять вариант отображения, и в зависимости от него делать видимой ту или иную страницу:

if (<Attribute2> = true) then
begin
  Page1.Visible := false;
  Page2.Visible := true;
  Page3.Visible := false;
end
else
...

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Олег, спасибо за помощь!

Подскажите пожалуйста как реализовать вот это:

"Лабьяк Олег Игоревич" написал:В обработчике события OnPrepare отчёта считываем эти значения и записываем их в атрибуты отчёта.

?

Скажите пожалуйста, есть ли в отчетах механизм сортировки по определенному столбцу?

Можно даже не использовать скрипт отчёта, а установить атрибуты напрямую из окна фильтрации. Например, так:

В обработчике btnOKOnClick Вашего окна фильтрации получаем отчёт и устанавливаем ему атрибуты:

function btnOKOnClick(Control) {
    var Report = Self.Attributes('ReportPreviewer').Report;
    Report.Attributes('AttributeName1') = edtControl1.Value;
    Report.Attributes('AttributeName2') = edtControl2.Value;
    ...
    SendNotify(Self, MSG_OK);
}

После этого в коде отчёта Вы сможете обращаться к этим атрибутам так:

if (<AttributeName1> = 1) then ...

"McCoy" написал:Скажите пожалуйста, есть ли в отчетах механизм сортировки по определенному столбцу?

По определённому столбцу можно отсортировать запрос отчёта - непосредственно в сервисе запроса установить тип и порядковый номер сортировки. Другой вариант - установить сортировку по полю датасета в скрипте перед формированием отчёта:

var Dataset = ReportPreviewer.DatasetByUSI('ds_ReportDataset');
Dataset.DataFields('FieldName').OrderType = otAsc;
Dataset.DataFields('FieldName').OrderPosition = 1;

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Большое спасибо!

А как бы оптимизировать данную ситуацию...
К примеру у нас через фастрепорт формируются заявки-анкеты двух типов для физ лиц и для юр.лиц.
В первом случае анкеты выводятся с данными физического лица - серия и номер паспорта
Во втором случае анкеты выводятся данные юр.лица - едрпоу, р/с, мфо и т.д.

Как выводить в отчет только те поля которые заполнены...
Например если заполнены поля паспорт - выводить отчёт с данными для физ лиц, а если заполнен ЄДРПОУ то выводить отчёт с данными для юр лиц.

Александр, попробуйте в коде отчета на OnBeforePrint прописать проверку примерно следующего вида:

if <Table1."Field1"> = Null then...

Пример:

procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
begin
  if (<TSDataset1."SignedQuantity"> = Null) then
       MasterData1.Visible := false
  else
       MasterData1.Visible := true;                                                                         
end;

По аналогии можете скрывать или делать видимыми компоненты отчета (скрывать страницы или печатать выбранные).

Page1.Visible := true;
Page2.Visible := true;
Page3.Visible := false;

Спасибо Татьяна,
но не правильно отрабатывает проверка логики:

(<ds_ReportContractCard."EDRPOU"> = Null)

даже если поле пустое, всё равно срабатывает

MasterData1.Visible := true;

По-моему на Null в скрипте к отчету сравнивать не получится, попробуйте сравнить с пустой строкой:

(<ds_ReportContractCard."EDRPOU"> = '')

Пробовал и одинарные и двойные скобки.
Ругается на синтаксис, просит ")"

Александр, вот так работает:

if <ds_ReportOfferingsInInvoice."Offering"> = '' then

Возможно, проблема с "()" в которые заключено выражение.

Татьяна,
действительно так работает.
Просто насколько мне известно в ObjectPascal не обязательно указывать скобки в случае когда есть всего одно условие, в отличии от JScript.
Но даже если и указать, то отладчик в самом ObjectPascal не ругается,
а вот в FastReport ему почему то не нравятся "()"
Спасибо за помощь...

Показать все комментарии

Добрый день.

В Dataset есть вычисляемое поле, но, к сожалению, я не могу в реестре вычислить итог по этому полю. Для выхода из ситуации я создал в таблице, выборке и датасете еще одно поле и попытался вставить в него вычесленное значение:

function ds_ContractOnDatasetCalcFields(Dataset) {
Dataset.Values('OVK') = Dataset.Values('Amount')/2........
Dataset('OVKNew') = Dataset.Values('OVK');
}

контекстное меню итогов у этого поля стало активным, в колонке отображаются нужные значения, но итоги (max, min, sum) равны нулю.

Может есть какой-нибудь способ подсчета итоговых значений по вычисляемым полям?

Спасибо.

Нравится

38 комментариев

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

Поэтому ответ на Ваш вопрос

"Павел Крышкин" написал:Может есть какой-нибудь способ подсчета итоговых значений по вычисляемым полям?

:сделать это поле хранимым или вычисляемым во view.

:сделать это поле хранимым или вычисляемым во view.

Вы имеете ввиду
function grdDataOnCalcSummary(DataGrid, DataField, Value, SummaryType, DoCalcSummary)
?

Я так понимаю без исправления ошибки в ядре, из-за которой не работают итоги по калк-филдам, ничего не будет. Тот путь, по которому Вы пошли, он порочен :) Использовать поле в БД для хранения каких-то времнных данных, которые в общем случае у каждого клиента могут быть свои не совсем хорошо.
К тому же если работает строка

Dataset('OVKNew') = Dataset.Values('OVK');

то это, наверное, еще одна бага. Нельзя менять значение поля датасета без перевода его в состояние редактирования.

Я такое смог обойти только используя view

--
www.it-sfera.com.ua
Terrasoft Solution Partner

Если можно, поподробней.

Да, можно и вьюхой. Но не всегда :(
Или CustomSQLColumn. Добавляем в запрос такую колонку, в тексте которой и описываем формулу вычисления калкфилда. В датасете делаем обычное поле для этой колонки.

Не создавать вычисляемое поле в Датасете, а создать на стороне SQL новое представление ( VIEW ) где и проводить расчеты. Потом подключить в админке VIEW, как таблицу, а дальше - стандартно - SelectQuery.. Dataset.. Работаем :)

--
www.it-sfera.com.ua
Terrasoft Solution Partner

По CustomSQLColumn итоги в реестре не рассчитываться

--
www.it-sfera.com.ua
Terrasoft Solution Partner

"Виталий Ковалишин aka samael" написал:По CustomSQLColumn итоги в реестре не рассчитываться

Хм, не знал, спасибо.

"Underscore a.k.a. _" написал:Я так понимаю без исправления ошибки в ядре, из-за которой не работают итоги по калк-филдам, ничего не будет

Ну не то что бы это была ошибка :) Они не "не работают", итоги физически нельзя выбрать по Calc-полям.
В версии 3.3.1 появился метод OnDatasetCalcSummary, в котором можно реализовать собственный рассчет итогов. Эту функциональность мы специально реализовали для MemoryDataset. Но можно будет ее использовать и для Calc-полей. Для этого нам осталось дать возможность выбирать в гриде необходимость рассчета итогов по Calc полям - сейчас, как я уже говорил, она закрыта.

Ну да, итоги можно расчитать только для текущего пейджа:) И тогда будет слегка сбивать столку, если в одной колонке считаем для всех пейджей, а в другой только для текущего.

Почему только для текущего?

Ну допустим мы считаем калкполе A = 2*B, где B это поле БД. Стоя на первой странице грида мы будем иметь информацию для расчета значений поля A только для записей с первой страницы. Таким образом для калкполя мы можем посчитать итог только для текущей страницы.

Итог для calc-поля нужно посчитать отдельным запросом и все.

Про то что можно отедельным запросом понятно. Но придется создавать отдельный SQ для каждого такого поля. Как это сделать универсально (как сделано для обычных полей) я не представляю. А зная свойство человеческой натуры, можно сказать что разработчики будут ленится делать расчет итогов для каждого калкполя, которе они добавили в конфигурацию :)

В будущих версиях обязательно придумаем что нибудь более универсальное.

"Underscore a.k.a. _" написал:А зная свойство человеческой натуры, можно сказать что разработчики будут ленится

странно слышать такие слова :)

"Раловец Ольга" написал:странно слышать такие слова :)

Да ладно. Думаю каждый время от времени ленится. Просто для некоторых это становится нормой и они сами этого уже не замечают :)

Разработчик может не полениться, а следовать ТЗ, в котором явно не прописана необходимость вычисления итогов по хитрому полю))

ООО "Лайнсервис"
www.ls-crm.ru

Или же он может помнить про особенность этих полей, но решить, что раз в ТЗ не прописано... :)

"Underscore a.k.a. _" написал:Думаю каждый время от времени ленится

думаю, я знаю как минимум одного человека, который никогда не ленится :)

Надеюсь это Путин? :) Потому что писать таким образом о себе как минимум не скромно :)

что Вы, что Вы! как можно :) я говорю о своих коллегах

Подлизываться к начальству тоже к добродетелям не относится :)

Итоги не работают и по колонкам с под запросом.
Самое вменяемое решение - таки использовать отображение.
Хорошо б такой сервис создать.
А то

"Underscore a.k.a. _" написал:разработчики будут ленится

вначале создавать на стороне сервера, а потом сам сервис :)

Так вроде приняли идею про сервис. Осталось дождаться реализации.

Здравствуйте, Алексей!

"Ключник Алексей" написал:В версии 3.3.1 появился метод OnDatasetCalcSummary, в котором можно реализовать собственный рассчет итогов. Эту функциональность мы специально реализовали для MemoryDataset

Подскажите пожалуйста как это работает. Как подсчитать сумму в MemoryDataset и отобразить ее в итогах?

В обработчике события OnDatasetCalcSummary во второй аргумент SummaryValues можно заносить итоговое значение. Например, SummaryValues('Name')=555. В результате, в итоге для колонки Имя будет значение 555. При этом нужно присваивать DoCalc.Value = false, чтобы отключить стандартный подсчет итогов.
Относительно MemoryDataset: Вы можете создать его и наполнять значениями на событии OnDatasetAfterOpen. Наполнение реализовать согласно требуемой логики подсчета итогов. Но можно и напрямую заносить итоговое значение, без MemoryDataset, как я описал выше.

"Стоян Виталий" написал:В обработчике события OnDatasetCalcSummary во второй аргумент SummaryValues можно заносить итоговое значение. Например, SummaryValues('Name')=555. В результате, в итоге для колонки Имя будет значение 555. При этом нужно присваивать DoCalc.Value = false, чтобы отключить стандартный подсчет итогов.
Относительно MemoryDataset: Вы можете создать его и наполнять значениями на событии OnDatasetAfterOpen. Наполнение реализовать согласно требуемой логики подсчета итогов. Но можно и напрямую заносить итоговое значение, без MemoryDataset, как я описал выше.

Сделал, как Вы написали, но при нажатии правой кнопкой в строке итогов выходит исключение:
Объект TSObjectLibrary.MemoryDataset ({64250DFB-C6AA-4BC8-B4C6-515C52D98244}) не поддерживает интерфейс IDBDataset ({B77D78C1-40FD-4A5A-9592-DC0A6072AA3B})

Есть ли какой-нибудь способ подсчета значений поля в MemoryDataset минуя переход по записям, или может посоветуете какой нибудь другой компонент.
Задача следующая вывести общую сумму непосредственно после изменения значения колонки сумма в определенной строке, как в excel'e.

Вы можете использовать стандартные итоги по сумме, а обновлять значение по событию OnAfterPost, обращаясь к датасету реестра раздела, например таким способом: RefreshDataset(Self.Attributes('NotifyObject').ComponentsByName('dlData').Dataset)

"Стоян Виталий" написал:
Дело в том, что я пытаюсь реализовать все это на MemoryDataset'е, без окна редактирования, и вроди бы даже подсчет выполняется, но при изменении поля, для подсчета итогов приходится делать перебор всех записей и получается, указатель записи постоянно находися на последней записе. Можно ли как-то обрабатывать MemoryDataset не используя перемещение по его записям?

"Стоян Виталий" написал:Вы можете использовать стандартные итоги по сумме, а обновлять значение по событию OnAfterPost, обращаясь к датасету реестра раздела, например таким способом: RefreshDataset(Self.Attributes('NotifyObject').ComponentsByName('dlData').Dataset)

Спасибо Виталий!
Что-то я сразу не сообразил, что при редактировании непосредственно в Grid'е также срабатывает осбытие OnAfterPost.
Сделал на событиии OnAfterPost.

 Dataset.DisableEvents();
	var ID=Dataset.Values('ID');
	suma=0;
	Dataset.GotoFirst();
	for (var i = 0; i < Dataset.RecordsCount; i++) {
		suma=suma+Dataset.Values('Summa');
		Dataset.GotoNext();
	}	
	Dataset.Locate('ID',ID);
    Dataset.EnableEvents();
    LabelSum.Caption= suma;

Но только один вопросик на будущее: существует ли недокументированная возможность обращаться к MemoryDataset'у как к массиву значений? Ведь имхо он таковым и является.

Он-то конечно по структуре является, но реализует интерфейс IMemoryDataset, в котором не прописано обращение напрямую к определенной записи, как в массиве. Вот, например, перечень свойств интерфейса.
Можно считать вашу проблему решенной?

Спасибо, Виталий за помощь! Проблема решена.

Здравствуйте!
При работе с данным обработчиком OnDatasetCalcSummary возникает вопрос
Как различить вызываемые агрегатные функции при обработке события Dataset'a OnDatasetCalcSummary
Кстати говоря, пройдя по ссылке, можно найти решение, как различать различные поля Dataset'a по которым вызван итог.

Ответ на вопрос пользователя АльфаКрыса был предоставлен в теме по ссылке:

http://www.community.terrasoft.ua/forum/topic/8468

Дмитрий, спасибо за помощь. Пример своего кода с использованием Ваших рекомендаций можно посмотреть тут

Здравствуйте АК.

Если у Вас возникнут дополнительные вопросы - пожалуйста, обращайтесь. Всегда рады помочь ;)

Показать все комментарии

Следующий материал описывает работу с окном напоминаний. Очень часто пользователи хотят отобразить дополнительную информацию элемента по которому создано напоминание: приоритет задачи, тип и т.п. в "некой" дополнительной колонке. Но не все знают как же добавить эту дополнительную колонку...

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

Удачи!

Нравится

Поделиться

0 комментариев
Показать все комментарии