Вопросы по табличному отчету

Stalker4Stalker4 123
отредактировано 12:44 Раздел: FastReport 4.0
Привет All,

Есть стандартный табличный отчет:

Header - заголовок таблицы (печатать на каждой странице)
MasterData - данные таблицы (растягиваемый, держать заголовок и подвал)
Footer - подвал таблицы

В таблице данных много, поэтому в отчете соответственно будет много страниц.

Вопросы:

1) Как определить, что сейчас будет напечатана последняя запись на текущей странице ?

2) Как определить, что сейчас будет напечатана первая запись на текущей странице ?

Комментарии

  • gpigpi
    отредактировано 12:44
    Вот кое-что надумал, правда не знаю, насколько это решение универсально, но со слегка модифицированным примером демо Simple List работает. Отчёт должен быть двухпроходным
    var PageNum: array of Integer;
        NumRec: Integer;
        PageOrder: string;                                     
    
    procedure PageHeader1OnBeforePrint(Sender: TfrxComponent);
    begin
         NumRec:=0;                                 
    end;
    
    procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
    begin
        if not Engine.FinalPass then
          begin
            inc(NumRec);
            SetLength(PageNum, NumRec);
            PageNum[NumRec-1]:=<Page>;
          end
         else
           begin
            inc(NumRec);
            PageOrder:='';
            if (NumRec=1) or (PageNum[NumRec]>PageNum[NumRec-1]) then PageOrder:='first' else
              if PageNum[NumRec+1]>PageNum[NumRec-1] then PageOrder:='last';            
           end;                  
    end;
    
    procedure Footer1OnBeforePrint(Sender: TfrxComponent);
    begin
         if not Engine.FinalPass then 
           begin                                   
             SetLength(PageNum, NumRec+2);
             PageNum[NumRec]:=<Page>;
             PageNum[NumRec+1]:=<Page>+1;
           end
         else
           SetLength(PageNum, 0);                                            
    end;
    
  • Stalker4Stalker4 123
    отредактировано February 2007
    Спасибо за ответ.

    Смысл MasterData1OnBeforePrint мне понятен - сначала для каждой записи сохраняем ее номер страницы, а потом это используем.
    Единственный тут момент - часть "if not Engine.FinalPass then" ИМНО надо делать, не в Before, а в After - иначе не учтется опция "растягивание".


    А вот смысл Footer1OnBeforePrint мне не очень понятен.


    Есть еще один вопрос, частично связанный с предыдущим.

    Есть достаточно стандартный табличный Master-Detail отчет :

    MasterHeader - заголовок master-данных (печатать на каждой странице)
    MasterData - master-данные таблицы (растягиваемый, держать заголовок)
    DetailHeader - заголовок detail-данных таблицы
    DetailData - detail-данные таблицы (растягиваемый)

    Запускаем формирование отчета. В результате может получиться примерно вот что:
    Page 1
    MasterHeader
    MasterData (строка 1)
    DetailHeader
    DetailData (строки 1-50)
    Page 2 (Вар 1)
    MasterHeader
    DetailData (строки 51 - 70)
    Page 3
    MasterData (строка 2)

    То есть получается, что хотя на странице 2 нет ни одной master-записи, master-заголовок там все равно печатается.
    Может быть еще подобный вариант, типа
    Page 2 (Вар 2)
    MasterHeader
    DetailData (строки 51 - 70)
    MasterData (строка 2)
    Но и в этом случае страница ведь начинается с Detail-данных, так зачем же к ним лепить MasterHeader ?
    Я конечно понимаю, что у него включена соответствующая опция, но ИМНО для такой ситуации (как на странице 2) она (опция) не имеет смысл.

    Вопрос: Как этого избежать ? То есть надо, что бы MasterHeader не лез не к своим данным. То есть для (Вар 1) MasterHeader вообще не должен появляется на странице 2, а для Вар 2, он должен появится только перед первой мастер-записью на странице.

    Ситуация ИМНО в общем то стандартная ...

  • gpigpi
    отредактировано 12:44
    написал:
    А вот смысл Footer1OnBeforePrint мне не очень понятен
    В массив добавляются ещё два элемента, значения которых имитируют конец страницы для последней записи в датасете. В событии MasterData1OnBeforePrint при выводе текущей записи проверяется номер страницы двух следующих. Вот для последней записи и нужны два дополнительных элемента
    написал:
    То есть надо, что бы MasterHeader не лез не к своим данным. То есть для (Вар 1) MasterHeader вообще не должен появляется на странице 2, а для Вар 2, он должен появится только перед первой мастер-записью на странице
    Может попробовать вместо MasterHeader использовать GroupHeader с таким условием группировки, чтобы GroupHeader появлялся перед каждым MasterData?
  • Stalker4Stalker4 123
    отредактировано 12:44
    GroupHeader тут использовать не желательно, так как во первых в отчете могут и так использовать группы, а во вторых есть некоторые проблемы при использовании опции "Держать данные группы" у GroupHeader. В частности я наталкивался на ситуацию, когда в этом случае отваливался MasterFooter.

    ИМНО описанная с заголовком ситуация достаточно стандартная для многих табличный master-detail отчетов. И соответственно для этой ситуации хотелось бы иметь простое решение. Например добавить для Header соответствующую опцию.

    Скажем опция "Печатать заголовок на каждой странице" будет работать по старому (для совместимости с предыдущими отчетами), а опция "Печатать заголовок на каждой странице перед данными" уже будет работать по новому.
  • gpigpi
    отредактировано 12:44
    Ну тогда
    procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
    begin
         if not (MasterData1.DataSet.RecNo=0) then Engine.ShowBand(Header1);
    end;
    
    Header1 повторять на каждой странице не нужно
  • Stalker4Stalker4 123
    отредактировано 12:44
    Не понял ответ ...

    Чем этот обработчик поможет в решении последнего вопроса ?
  • gpigpi
    отредактировано 12:44
    Перед каждым MasterData будет выводиться заголовок данных
  • Stalker4Stalker4 123
    отредактировано February 2007
    Зачем же мне перед каждым MasterData выводить заголовок ???
    Ведь у Master-записи может и не быть Detail-данных и следовательно на одной странице могут быть несколько Master-записей. Причем у одних Master-записей есть Detail-данные, а у других нет.

    MasterHeader должен выводиться на каждой странице только один раз перед самой первой Master-записью на этой странице. Если же на странице нет Master-записей, то соответственно и MasterHeader там выводится не должен.
    Ну и конечно должны учитываться опции типа "держать заголовок" и "растягивание". Все это учесть в скрипте мне кажется довольно сложно, если вообще возможно (особенно это касается учета опций).
    Именно поэтому я предложил добавить свойство "Печатать заголовок на каждой странице перед данными" к DataBand'у. Задача ведь в общем достаточно стандартная.
  • gpigpi
    отредактировано 12:44
    Вот только возьмётся ли Цыганенко за реализацию этой опции? Ведь ему придётся городить в коде то, что нужно было бы делать в скрипте, да и ещё с учётом всех особенностей работы движка FR
  • Stalker4Stalker4 123
    отредактировано February 2007
    Скажем так, пока он в личной переписке упирается руками и ногами ;(
    Говорит что это только мне нужно, а остальных все устраивает. Возможно если не один я его попрошу про это, то он все же реализует это улучшение.

    Насчет того что это нужно делать в скрипте я не согласен. Предложенная мною ситуация ИМНО стандартная для табличный MD-отчетов.
    А на мой взгляд стандартные отчеты должны делаться без использования скриптов или с их минимальным участием. А уже всякие навороты, хитрости и отклонения от стандарта - тут действительно скрипт в зубы и вперед.

    Хорошо, а можешь ли ты сделать такой отчет пусть даже и со скриптом ?
    Я пробовал такое сделать, но у меня к сожалению не получилось ;(
  • gpigpi
    отредактировано 12:44
    Применительно к демо Nested groups такой скрипт
    var PrintHeader: Boolean;                                                             
    
    procedure PageFooter1OnBeforePrint(Sender: TfrxComponent);
    begin
         PrintHeader:=True;    
    end;
    
    procedure MasterData1OnAfterCalcHeight(Sender: TfrxComponent);
    begin
         if Engine.FreeSpace<MasterData1.Height then PrintHeader:=True;                                                                                                                                                          
         if PrintHeader then Engine.ShowBand(Child1);
         PrintHeader:=False;  
    end;
    
    procedure ReportTitle1OnBeforePrint(Sender: TfrxComponent);
    begin
         PrintHeader:=True;  
    end;
    
    работает
  • Stalker4Stalker4 123
    отредактировано 12:44
    Большое спасибо за скрипт.

    Это почти то что надо. Но в некоторых случаях получается так, что заголовок печатается в самом конце страницы, а на следующей странице печатается одна master-строка (т.е. эта строка не поместилась в конце предыдущей страницы и ее перенесло на следующую страницу), потом заголовок и дальше продолжается печать master-detail строк.

    То есть как я понимаю в данном случае не учитывается (или плохо учитывается) растяжение MasterBand'а.



  • gpigpi
    отредактировано 12:44
    А если попробовать так?
    procedure MasterData1OnAfterCalcHeight(Sender: TfrxComponent);
    begin
        if Engine.FreeSpace<MasterData1.Height then
          begin
             Engine.NewPage;
             PrintHeader:=True; 
          end;     
        if PrintHeader then Engine.ShowBand(Child1);
        PrintHeader:=False;  
    end;
    
  • Stalker4Stalker4 123
    отредактировано 12:44
    Против заголовка в конце страницы помогло.

    Но появилась другая проблема, хотя и менее нехорошая чем предыдущая.

    На странице N печатается master-запись, потом ее detail-данные.
    На странице N+1 продолжается печать detail-данных (несколько строк).

    После этого на странице X+1 должна напечататься очередная master-запись, но из за Engine.NewPage она начинается печататься на странице N+2. И соответственно на странице N+1 остается куча пустого места.

  • gpigpi
    отредактировано 12:44
    А свободного места точно хватает для печати MasterData? Можно проверить, отключив в скрипте Engine.NewPage при печати на странице N+1
  • Stalker4Stalker4 123
    отредактировано 12:44
    Да места для печати MasterData на странице N хватает.

    См. картинку err1.png в атаче

    Верхний лист (N) - там окончания очередной порции Detail-данных.
    Нижний лист (N+1) начинается с заголовка плюс несколько в подряд идущих MasterData.
    Как видишь на листе N уместился бы заголовок и как минимум 1-2 Master-строки.

    Так же посмотри err2.png. Там как видишь места на верхнем листе еще больше осталось.
  • gpigpi
    отредактировано 12:44
    а на шаблон отчёта посмотреть можно?
    Также желательно бы получить данные (2 dbf или база Access) для построения отчёта
  • Stalker4Stalker4 123
    отредактировано 12:44
    написал:
    а на шаблон отчета посмотреть можно?
    Шаблон посмотреть можно. Только учти, что там используются мои компоненты диалога и frxSDComponents в качестве Engine.

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

    Но в принципе смотреть в шаблоне особо не на что. Это самый обычный табличный MD-отчет.
  • gpigpi
    отредактировано 12:44
    Надеюсь, этот вариант будет работать
    var
      PrintHeader  :Boolean;      
    
    procedure PageFooter1OnBeforePrint(Sender: TfrxComponent);
    begin
     PrintHeader:=True;  
    end;
    
    procedure MasterDataOnAfterCalcHeight(Sender: TfrxComponent);
    begin
     if Engine.FreeSpace < MasterData.Height then 
       begin                    
         Engine.NewPage;
         Engine.ShowBand(MasterHeader);
       end
     else             
       if PrintHeader then Engine.ShowBand(MasterHeader);
     PrintHeader:=False;  
    end;
    
    procedure ReportTitle1OnBeforePrint(Sender: TfrxComponent);
    begin
     PrintHeader:=True;  
    end;
    
  • Stalker4Stalker4 123
    отредактировано 12:44
    Да, этот скрипт лучше всех предыдущих.

    Я только внес в него небольшое исправление
    if Engine.FreeSpace < MasterData.Height+5
    (на одной из страниц, в конце напечатался master-заголовок без данных).


    На одной из страниц выплыл другой глюк (но я не уверен, появился ли он вследствие ручного вывода банда, или это глюк самого FR4)

    В той форме что я тебе кинул:
    MasterData (растягиваемый, печатать если Detail пуст)
    DivDetailData (растягиваемый, держать заголовок и подвал)
    Параметры у остальных бандов не изменял.

    Так вот получилась такая ситуация
    DivDetailHeader напечатался в конце одной страницы, а DivDetailData (одна запись) и DivDetailFooter в начале следующей страницы.
    То есть получается, что у DivDetailData не сработала опция держать заголовок.

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

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