"Конвейерная печать"

отредактировано May 2009 Раздел: FastReport 4.0
Передо мной встала проблема: в самой программе я выделяю несколько элементов в списке, а потом отправляю их на печать, а точнее отправляю на печать всю развернутую информацию, касающуюся этих элементов. Эта информация должна быть представлена в виде нескольких кросс-табов, идущих один за другим. С одним выбранным элементом проблем нет: инфа, касающаяся его легко кладется в один кросс-таб, но как быть, если их (элементов) несколько? Ведь на этапе разработки я не знаю, сколько у меня будет выделено элементов и поэтому не могу заранее создавать некоторое количество заготовок, да это и глупо: нужно использовать один кросс-таб для всех элементов, чтобы он каждый раз печатался в количестве равном числу выделенных элементов, но с обновляющимся содержимым.
Как решить?

Комментарии

  • RhinoFCRhinoFC Новосибирск
    отредактировано 21:53
    madmech написал: »
    Передо мной встала проблема: в самой программе я выделяю несколько элементов в списке, а потом отправляю их на печать, а точнее отправляю на печать всю развернутую информацию, касающуюся этих элементов. Эта информация должна быть представлена в виде нескольких кросс-табов, идущих один за другим. С одним выбранным элементом проблем нет: инфа, касающаяся его легко кладется в один кросс-таб, но как быть, если их (элементов) несколько? Ведь на этапе разработки я не знаю, сколько у меня будет выделено элементов и поэтому не могу заранее создавать некоторое количество заготовок, да это и глупо: нужно использовать один кросс-таб для всех элементов, чтобы он каждый раз печатался в количестве равном числу выделенных элементов, но с обновляющимся содержимым.
    Как решить?

    Расположи кросс-таб на датабэнде. Датабэнду устанавливай количество записей, равное количеству выбранных элементов. Ну а далее, перед печатью кросс-таба, анализируй для какого из выбранных элементов сейчас будет печататься кросс-таб и передавай соответствующий параметр датасету кросстаба. Примерно так.
  • отредактировано 21:53
    RhinoFC написал: »
    Ну а далее, перед печатью кросс-таба, анализируй для какого из выбранных элементов сейчас будет печататься кросс-таб и передавай соответствующий параметр датасету кросстаба.
    А поподробнее можно?
  • RhinoFCRhinoFC Новосибирск
    отредактировано 21:53
    madmech написал: »
    А поподробнее можно?

    Ну... Допустим запрос для кросса у тебя выглядит так:
    select row_name, column_name, cell_value
      from some_table
     where item_id = :item_id
    

    Здесь item_id - идентификатор некоего элемента, входящего в список выбранных пользователем для печати отчёта.
    Рисуешь кросс, кидаешь его на MasterData. Перед печатью отчёта вычисляешь количество выбранных пользователем элементов и устанавливаешь это значение дата-бэнду:
    procedure Page1OnBeforePrint(Sender: TfrxComponent);
    begin
      MasterData1.RowCount := <items_count>;                                                        
    end;
    

    Далее, на OnBeforPrint датабэнда вешаешь такой обработчик:
    procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
    var
      item_id integer;
    begin
      FIBQuery1.Close; // это датасет кросса
      item_id = GetItemID(<Line>); // это некая твоя функция, возвращающая идентификатор элемента, в зависимости от
                                                   // индекса строки
      FIBQuery1.Params.Items[0].Value := item_id;
      FIBQuery1.Open;                                  
    end;
    

    Вот так примерно.
    Есть ещё варианты. Например датабэнд, на котором кросс лежит, привязать к датасету, который тебе будет индексы выбранных элементов возвращать. Тогда ещё проще.
  • отредактировано 21:53
    написал:
    Есть ещё варианты. Например, датабэнд, на котором кросс лежит, привязать к датасету, который тебе будет индексы выбранных элементов возвращать. Тогда ещё проще.
    У меня кросс заполняется именно через клиент-датасет, а не через запрос, поэтому все выше сказанное мне не подходит, к сожалению. Как мне тогда быть? Я вижу такое решение проблемы: количество элементов в дата-бэнде я задаю через специально созданный датасет, состоящий из одного поля, в котором записаны номера выбранных элементов. Далее я начинаю заполнять кроссы через другой датасет. Причем! Если ничего не предпринимать и не проводить никакой проверки, то все значения элементов записываются в каждый вновь созданный кросс. Поэтому! Я специально создал поле (номер п/п выбранного элемента) в кроссовом датабэнде, отвечающее за раграничение данных, относящихся к определенному элементу. Таким образом, мне теперь нужно каким-то образом проводить в OnBeforePrint проверку на равенство номера п/п выбранного элемента и номера элемента в дата-бэнде, и выводить в кросс только те данные из датасета, которые относятся к зафиксированному спец. полю. Как это сделать?
  • RhinoFCRhinoFC Новосибирск
    отредактировано 21:53
    madmech написал: »
    У меня кросс заполняется именно через клиент-датасет, а не через запрос, поэтому все выше сказанное мне не подходит, к сожалению. Как мне тогда быть? Я вижу такое решение проблемы: количество элементов в дата-бэнде я задаю через специально созданный датасет, состоящий из одного поля, в котором записаны номера выбранных элементов. Далее я начинаю заполнять кроссы через другой датасет. Причем! Если ничего не предпринимать и не проводить никакой проверки, то все значения элементов записываются в каждый вновь созданный кросс. Поэтому! Я специально создал поле (номер п/п выбранного элемента) в кроссовом датабэнде, отвечающее за раграничение данных, относящихся к определенному элементу. Таким образом, мне теперь нужно каким-то образом проводить в OnBeforePrint проверку на равенство номера п/п выбранного элемента и номера элемента в дата-бэнде, и выводить в кросс только те данные из датасета, которые относятся к зафиксированному спец. полю. Как это сделать?

    Да всё тебе подходит. В принципе изменений минимум.
    Во-первых у датасетов есть свойства Filter и Filtered (по крайней мере у TfrxFIBDataSet есть, у остальных, думаю, тоже). Попробуй устанавливать его для датасета кросса в OnBeforePrint дата-бэнда. Я не знаю как отреагирует сам кросс (учитывает он отфильтрованные значения или нет), но стоит попробовать.
    Во-вторых можно ведь перестроить запрос датасета для кросса по тому принципу, который я описал. В случае, если у тебя датабэнд привязан датасету, то кроссовый датасет можно привязать к нему через master-detail и вообще ни какого кода не надо (параметр можно привязать прямо в дизайнере отчёта через свойства датасета). Конечно этот вариант затратнее по временным ресурсам, поскольку датасет для кросса будет открываться несколько раз. Так что попробуй сначала первый вариант, может проканает. А нет - ну, куда деваться? Пусть переоткрывается. Запрос оптимизируй.
  • отредактировано May 2009
    Сразу скажу, что по первому варианту внутренний компилятор FR4 выдает ошибку:
    "Could not convert variant of type (Null) into type (Integer)"
    Это происходит, когда я, например, использую в скрипте самый простой пробный вариант фильтрации:
    procedure Sq_DBCrossOnBeforePrint(Sender: TfrxComponent);                                             
    begin                      
      Sq_DBCross.DataSet.DataSet.Filter := '№SG=''1''';  
      Sq_DBCross.DataSet.DataSet.Filtered := True;
    end;
    
    Чтобы это значило?

    Второй вариант, честно говоря, хочется использовать в последнюю очередь. :) Да и к тому же я смутно представляю себе, как можно запросить данные с помощью TQuery из клиент-датасета. Я черпаю информацию для ДБ-Кросса не из таблицы (базы данных), а из клиентского набора данных. :)
  • отредактировано 21:53
    Все, проблему решил следующим образом:
    procedure TMainForm.EnumPartReportBeforePrint(Sender: TfrxReportComponent);
    begin
      EnterCDS_Sq.Filtered := True;
      if Sender.Name = 'Sq_DBCross' then
        EnterCDS_Sq.Filter := '№SG=''' + EnumPartCDS.FieldByName('№').AsString + '''';
    end;
    
    Если комментарии кому-нибудь понадобятся, могу раскрыть суть решения.

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.