Статьи

Печать навалом с помощью Flex

Это исследование демонстрирует, как использовать PrintAdvancedDataGrid и пользовательский itemRenderer для печати нескольких страниц данных и графики с использованием компонента SWFloader .


Давайте посмотрим на конечный результат, к которому мы будем стремиться — ниже представлен обзор 12-страничного PDF-документа, напечатанного из приложения Flex с использованием методов, описанных в этой статье:

flex_print_preview

  1. Использование класса FlexPrintJob.
  2. Использование PrintAdvancedDataGrid .
  3. Создание пользовательского itemRenderer с помощью SWFLoader .
  4. Печать верхнего и нижнего колонтитула.
  5. Фильтрация collectionView .
  6. Печать DataGrid с высотой, которая превышает 7500.

  1. Все содержимое или строки DataGrid должны быть видны на сцене, иначе они не будут печататься.
  2. Добавление разрывов страниц вручную затруднено и достигается путем установки значения rowHeight соответствующего тому, что вы хотите отображать на каждой напечатанной странице.
  3. Гибкая печать становится PrintAdvancedDataGrid если общая PrintAdvancedDataGrid содержимого PrintAdvancedDataGrid превышает приблизительно 7500 пикселей, что требует обходного пути для нескольких PrintAdvancedDataGrids .

Начните с импорта необходимых классов печати, а также средства визуализации печати в проект Flex:

1
2
3
import mx.printing.FlexPrintJob;
import mx.printing.FlexPrintJobScaleType;
import com.reiman.PrintItemRenderer;

Создайте состояние просмотра для вашей массовой печати. В моем случае я создал состояние с именем printState.

* в качестве альтернативы, вы можете создать экземпляр вашего PrintAdvancedDataGrid и itemRenderer и добавить их на сцену с помощью actionScript, но для проекта массовой печати я обнаружил, что с этим слишком сложно работать, и когда я пытался напечатать SWF-файлы, которые представляют собой XML Я должен был убедиться, что мои SWF-файлы правильно отображались перед печатью.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<mx:PrintAdvancedDataGrid
  paddingTop=»0″
    paddingBottom=»0″
    visible=»true»
    rowHeight=»200″
    sizeToPage=»true»
    showHeaders=»false»
    id=»printGrid»
    creationComplete=»stripQuiz();»
    height=»{grid_height}»
    width=»300″>
<mx:columns>
<mx:AdvancedDataGridColumn
    width=»200″
    id=»printColumn»
    itemRenderer=»com.reiman.PrintItemRenderer»
    sortable=»false» />
</mx:columns>
</mx:PrintAdvancedDataGrid>

Если вам нужна общая область печати более 7500 по высоте, вам понадобится еще одна PrintAdvancedDataGrid для каждой области


Одна вещь, которую я нашел важным, это установить опцию

1
sizetoPage=»true»

Согласно странице ControlDataGrid Control из Adobe Flex 3 LiveDocs , свойство sizeToPage гарантирует, что элемент управления PrintAdvancedDataGrid удаляет все частично видимые или пустые строки и изменяет свой размер, чтобы включать только полные строки в текущем представлении.


Добавьте itemRenderer в свой AdvancedDataGridColumn .

1
2
3
4
5
<mx:AdvancedDataGridColumn
width=»200″
id=»printColumn»
itemRenderer=»com.reiman.PrintItemRenderer»
sortable=»false» />

В моем случае я хотел сделать несколько вещей с itemRenderer :

  1. добавить SWFLoader
  2. добавить заголовок с заголовком страницы
  3. добавить боковой колонтитул с моим URL
  4. добавить интервалы сверху, снизу и по бокам для правильной печати

Поскольку мой URL работал лучше как вертикальный текст, я обнаружил, что гораздо лучше использовать SWF для этого текста вместо текстового поля. Вы можете проявить творческий подход с помощью itemRenderer , добавив элементы данных из вашего XML или источника данных, а также логотипы, URL-адреса и т. Д. Вот элементы отображения из моего кода для компонента itemRenderer , который также находится в src / com / reiman Файл /PrintItemRenderer.mxml в пакете загрузки для этого руководства:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<mx:VBox width=»100%» >
<mx:Spacer height=»10″ width=»100%»/>
<mx:HBox horizontalAlign=»center» width=»100%»>
<mx:Text textAlign=»center» styleName=»printHeader» text=»{appy.printGrid.dataProvider.getItemAt(0).title} — {row.lessonTitle} © Insta Spanish 2011″ width=»92%» x=»10″ y=»-7″/>
<mx:Image right=»20″ source=»{row.lessonIcon==’video’?video:
row.lessonIcon==’worksheet’?worksheet:
row.lessonIcon==’lesson’?activity:
row.lessonIcon==’hover’?hover:
row.lessonIcon==’drag’?matching:
row.lessonIcon==’song’?song:
row.lessonIcon==’memory’?memory:
row.lessonIcon==’downloads’?’assets/images/icons/downloads.swf’:
row.lessonIcon==’hangman’?hangman:
row.lessonIcon==’quiz’?quiz:
row.lessonIcon==’wordgame’?wordgame:
row.lessonIcon==’flashcards’?flashcard:
row.lessonIcon==’oral’?oral:
row.lessonIcon==’cloze’?cloze:empty}» height=»25″ width=»25″/>
</mx:HBox>
</mx:VBox>
<mx:VBox id=»print_vbox» horizontalScrollPolicy=»off» verticalScrollPolicy=»off»
verticalAlign=»middle» height=»100%» width=»100%»>
<mx:Spacer height=»5%» />
<mx:HBox horizontalScrollPolicy=»off» verticalScrollPolicy=»off»
verticalAlign=»middle» height=»100%» width=»100%»>
<mx:Spacer width=»3%» />
<mx:SWFLoader id=»swfPrintLoader» height=»90%» width=»90%» scaleContent=»true» source=»{row.fileName}» autoLoad=»true» />
<mx:Spacer height=»1%» />
<mx:SWFLoader height=»198″ width=»20″ scaleContent=»true» source=»assets/images/wwwinstaspanishcom.swf»/>
</mx:HBox>
</mx:VBox>

1
2
3
4
5
6
7
8
9
public function print():void {
var printJob:FlexPrintJob = new FlexPrintJob();
printJob.printAsBitmap=false;
if(printJob.start())
{
printJob.addObject(printGrid);
printJob.send();
}
}

Выберите printJob масштаба printJob вы хотите использовать (чтобы узнать о FlexPrintJob масштаба FlexPrintJob , проверьте страницу Flex LiveDocs здесь ), и при необходимости установите параметр printasBitmap . Я хотел, чтобы мои элементы печатались как векторные, и на самом деле этот параметр был ключом к правильной печати содержимого.

1
printJob.printAsBitmap=false;

Добавьте любые оповещения или действия, которые вы хотите выполнить при печати (например, оповещение, чтобы сообщить пользователю о включении LANDSCAPE печати). Например:

1
Alert.show («Please set your printer settings to LANDSCAPE » + ‘\n’ + «or your quiz will NOT print correctly!»)

Если вы хотите установить Alert , оно должно быть выполнено до начала печати. Пожалуйста, посмотрите на код, предоставленный в загрузке, связанной с этим руководством для printAlert() в файле main.mxml .


Установите значения ширины и высоты перед печатью для ширины PrintAdvancedDataGrid и rowHeight

1
2
3
4
var before_widdy = printColumn.width;
var before_hiddy = printGrid.rowHeight;
var widdy = printJob.pageWidth;
var hiddy = printJob.pageHeight;

Установите новые значения для height , width и rowHeight чтобы они равнялись значениям FlexPrintJob

1
2
3
printColumn.width = widdy;
printGrid.width = widdy;
printGrid.rowHeight = hiddy;

Добавьте свой код для размещения нескольких страниц в printJob . Согласно Flex LiveDocs, эта nextPage() должна гарантировать, что ваш контент будет печататься правильно, независимо от высоты AdvancedDataGrid , хотя я обнаружил, что после высоты примерно 7500, печать не может завершиться правильно.

1
2
3
4
5
6
7
while(true) {
    printGrid.nextPage();
    if(!printGrid.validNextPage){
    printJob.addObject(printGrid);
    break;
          }
        }

Я обнаружил, что у меня стало меньше ошибок печати, когда я добавил это в код из шага 12:

1
2
printGrid.height = printGrid.measuredHeight;
printGrid.verticalScrollPolicy = «off»;

Итак, теперь мой общий код для шага 12 выглядит следующим образом:

1
2
3
4
5
6
7
8
9
while(true) {
    printGrid.nextPage();
    if(!printGrid.validNextPage){
    printGrid.height = printGrid.measuredHeight;
    printGrid.verticalScrollPolicy = «off»;
    printJob.addObject(printGrid);
    break;
          }
        }

Похоже, это связано с проблемой или ошибкой Flex 3, связанной с печатью сеток данных с большой высотой, что является реальной проблемой при печати таких вещей, как несколько SWF или изображений, поскольку высота вашей сетки данных должна фактически отражать общую высоту изображений или SWF. печатается!


1
2
3
printJob.addObject(printGrid2);
printJob.addObject(swfLoader,
FlexPrintJobScaleType.NONE);

Закройте printJob и выполните любые дополнительные функции, такие как Alert , и printColumn значения printGrid и printColumn до того, что было до печати. Если вы используете состояние просмотра для печати, где у пользователя, возможно, есть интерфейс типа Центра печати, где он может видеть, что он собирается напечатать, это было бы полезно. Если вы решите добавить PrintAdvancedDataGrid на сцену с помощью actionScript, тогда это будет ненужным, и на этом шаге вы вместо этого удалите PrintAdvancedDataGrid из стадии.

1
2
3
4
5
printJob.send();
printColumn.width = before_widdy;
printGrid.width = before_widdy;
printGrid.rowHeight = before_hiddy;
Alert.show(«Print Job Complete!»)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<mx:PrintAdvancedDataGrid
    paddingTop=»0″
    paddingBottom=»0″
    visible=»true»
    rowHeight=»200″
    sizeToPage=»true»
    showHeaders=»false»
    id=»printGrid2″
    creationComplete=»stripQuiz2();»
    height=»{grid_height}»
    width=»300″>
<mx:columns>
<mx:AdvancedDataGridColumn
    width=»200″
    id=»printColumn2″
    itemRenderer=»com.reiman.PrintItemRenderer»
    sortable=»false» />
</mx:columns>
</mx:PrintAdvancedDataGrid>

Изначально мой вызов данных выглядел так:

1
<mx:HTTPService id=»httpService» url=»{myUrl}» resultFormat=»object» result=»httpResult_handler(event)» fault=»Alert.show(‘data load error’)» />

Все, что мне нужно было сделать, это добавить дополнительный обработчик результатов, чтобы данные для второго PrintAdvancedDatagrid были отдельными:

1
<mx:HTTPService id=»httpService» url=»{myUrl}» resultFormat=»object» result=»httpResult_handler(event);httpResult_handler2(event)» fault=»Alert.show(‘data load error’)» />

Затем я добавил новый обработчик результатов:

01
02
03
04
05
06
07
08
09
10
private function httpResult_handler2(evt:ResultEvent):void {
    if (evt.result.lessons.row) {
        var resultAC:ArrayCollection = evt.result.lessons.row as ArrayCollection;
        for (var i:int=0;i&lt;resultAC.length;i++) {
            var row:Row = new Row();
            row.fill(resultAC[i]);
            lessonsDataProvider2.addItem(row);
        }
        getSelectedItem()
}

Этот новый dataProvider для второго PrintAdvancedDatagrid установлен в моей stripQuiz2() фильтра stripQuiz2() .


В моем случае мне нужно было добавить 3 новых ListCollectionView и еще 1 dataProvider :

1
2
3
4
[Bindable]private var removeQuiz:ListCollectionView = new ListCollectionView();
[Bindable]private var removeQuiz2:ListCollectionView = new ListCollectionView();
[Bindable]private var itemsQuiz:ListCollectionView = new ListCollectionView();
[Bindable]private var lessonsDataProvider2:ArrayCollection = new ArrayCollection();

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

  1. Удалите определенные виды деятельности из моего списка печати, поскольку некоторые из них не были необходимы
  2. Усечите данные до 12 записей, так как после обширного тестирования я обнаружил, что это был предел для успешной печати полностраничных SWF-файлов из таблицы данных.
  3. Удалите первые 12 записей из ListCollectionView для 2-го PrintAdvancedDatagrid

Это привело к созданию следующих функций:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private function stripQuiz():void {
    removeQuiz = new ListCollectionView(lessonsDataProvider);
    removeQuiz.filterFunction = quizStripped;
    removeQuiz.refresh();
    quizLimit();
    removeQuiz.refresh();
    printGrid.dataProvider = removeQuiz;
}
private function stripQuiz2():void {
    removeQuiz2 = new ListCollectionView(lessonsDataProvider2);
    removeQuiz2.filterFunction = quizStripped;
    removeQuiz2.refresh();
    quizPage2();
    removeQuiz2.refresh();
    printGrid2.dataProvider = removeQuiz2;
}
private function quizStripped(value:Object):Boolean {
    return String(value.lessonIcon).toUpperCase() != «QUIZ» &&
    String(value.lessonIcon).toUpperCase() != «HANGMAN» &&
    String(value.lessonIcon).toUpperCase() != «FLASHCARDS» &&
    String(value.lessonIcon).toUpperCase() != «DOWNLOADS» &&
    String(value.lessonIcon).toUpperCase() != «VIDEO» &&
    String(value.fileName).toUpperCase() != «ASSETS/ACTIVITIES/WORKSHEET_KIDS_AUDIO.SWF» &&
    String(value.fileName).toUpperCase() != «ASSETS/ACTIVITIES/WORKSHEET_KIDS_AUDIO5.SWF»;
}
 
private function quizLimit():void {
for (var i:int=removeQuiz.length-1; i>=0; i—)
{
    if (removeQuiz.length >= 13)
    removeQuiz.removeItemAt(i);
}
}
             
private function quizPage2():void {
    if (removeQuiz2.length >= 13)
    removeQuiz2.removeItemAt(12);
    removeQuiz2.removeItemAt(11);
    removeQuiz2.removeItemAt(10);
    removeQuiz2.removeItemAt(9);
    removeQuiz2.removeItemAt(8);
    removeQuiz2.removeItemAt(7);
    removeQuiz2.removeItemAt(6);
    removeQuiz2.removeItemAt(5);
    removeQuiz2.removeItemAt(4);
    removeQuiz2.removeItemAt(3);
    removeQuiz2.removeItemAt(2);
    removeQuiz2.removeItemAt(1);
}

Перед отправкой printJob я добавил второй PrintAdvancedDatagrid для печати:

1
2
printJob.addObject(printGrid2);
printJob.send();

Для лучшего ознакомления с полным кодом, пожалуйста, загрузите исходные файлы, связанные с этим руководством, и посмотрите на файл main.mxml .


Возможно, это не самое элегантное решение для массовой печати SWF-файлов из Flex, но это решение, которое я нашел, надежно работает с высоким качеством вывода. Печать во Flex может быть очень полезной, но это не значит, что вам следует упускать из виду доступные вам параметры, в частности, с помощью PrintDatagrid и PrintAdvancedDatagrid . Большое спасибо за чтение моего урока, и я с нетерпением жду ваших вопросов и комментариев.