Printing content inside a scroller in Flex 4 - apache-flex

I am currently working on an Adobe AIR application that shows the user some graphical data. As this data is more in height to fit the screen height, I've placed it inside a scroller.
Now I want to take a print of this visual data, mostly some charts and lists but I only see a single page containing only the part of the screen that is currently visible to the user. I want to have the entire content inside the scroller to appear on the page.
I tried using both PrintJob and FlexPrintJob but couldn't find a way around. Can anyone please help me by providing an insight, some source code will be greatly appreciated.
Looking forward to your replies,
Thanks

This is apparently a known bug with the Flex printing library and Scroller controls. You can read about my discussions on this here:
http://forums.adobe.com/message/3626759
As a workaround, I did the following:
var printer:FlexPrintJob = new FlexPrintJob();
// Display the print dialog to the user. If they choose a printer
// and click "print", this method will return true, and we will
// spool the job to the printer they selected. If they hit cancel,
// this method will return false, and we will not attempt to send
// anything to the printer.
if(printer.start()){
// Add some padding before spooling the object to the printer.
// This will give it a reasonable margin on the printout.
itemsToPrintContainer.paddingBottom = 100;
itemsToPrintContainer.paddingTop = 100;
itemsToPrintContainer.paddingLeft = 100;
itemsToPrintContainer.paddingRight = 100;
this.removeElement(itemsToPrintContainer);
FlexGlobals.topLevelApplication.addElement(itemsToPrintContainer);
printer.addObject(itemsToPrintContainer);
printer.send();
FlexGlobals.topLevelApplication.removeElement(itemsToPrintContainer);
this.addElement(itemsToPrintContainer);
// Reset the margins to 0 for display on the screen.
itemsToPrintContainer.paddingBottom = 0;
itemsToPrintContainer.paddingTop = 0;
itemsToPrintContainer.paddingLeft = 0;
itemsToPrintContainer.paddingRight = 0;
}
That I'm doing is moving the object I want to print outside of the scroller, printing it, and then moving it back inside the scroller, so the user is unaware of any change. The user might see a brief flash on the screen while things are re-arranged, but for my case that was acceptable.
Also, the padding was an attempt to add a margin to my printed output. It will not work quite right if you have multiple pages. You may not want to add padding in your particular case.
-Josh

Related

Qt Aligning contents of top item in combobox

I am working with Qt to create a GUI for a small game theory project I'm working on. I'm using a combobox as a selector for the team. I can align the contents in the dropdown window just fine, e.g.
for(int i = 0; i < ui.comboBox->count(); i++)
{
ui.comboBox->setItemData(i, Qt::AlignLeft, Qt::TextAlignmentRole);
}
I can't figure out how to align the top item that is selected, as you can see here. The contents is not aligned to the left and the name even goes off the screen. Does anyone know how I can align this similarly to the contents in the dropdown list?
I already searched online, but I'm having trouble phrasing the question correctly. Furthermore if I go through the options available to me by the autocompleter when typing ui.combobox-> I don't really see an option that can do what I want.
Not sure if this is the go to fix, but I solved it by setting an icon size for the combobox. What I think goes wrong is that there is probably some default size set, no matter the size of the icons when adding items. My icons were of size 50x15 and so I added the following lines:
QSize size(50, 15);
ui.comboBox->setIconSize(size);
Now it is done correctly and gives the correct view.

Stacking Angular Material 2 Dialogs like toasts

I am using the #angular/material library and am trying to create a sort of bootstrap toast like effect. Where I want potentially multiple dialogs to appear in the top right hand corner and stack up below the most recent one.
By disabling the backdrop and closing features, I have this code:
let dialogRef = this.dialog.open(NotificationInputComponent, {disableClose: true, hasBackdrop: false});
dialogRef.afterClosed().subscribe(result => {
this.selectedOption = result;
});
Which works quite well, so when triggered, I get this in the middle of my screen:
If I manually change the elements css to position: absolute; right: 10px then it goes to the right hand side of the screen and looks correct. The issue is, now if I trigger another dialogue, I have to do the same again, but set the top property to stop it overlaying the existing dialog. I could presumably keep track of all the triggered dialogs in my component and manually update the top margin. But I was wondering if there is a neater way of doing it, either getting them to stack in css, or possibly is there a way to inject the triggered dialog into an #angular/flexbox layout?

Flex DataGrid columns won't resize

I am having serious problems trying to resize columns in a DataGrid. I've been at it for over a day now and am at my wit's end with a headache to boot.
Essentially, I have a TabNavigator component with NavigatorContent children inside. In each one of the NavigatorContent children, I have a DataGrid to which I'm setting the width to 100% (this is needed to be able to handle resizing of the browser window). I am using the excellent filterable DataGrid from Iwo Banas as the DataGrid in each tab.
Now, I am making visible/invisible some columns in each of the DataGrids and this is working fine. However, I find that the column widths are not being set correctly. Whenever I set the column widths (using this code), all of the columns seem to be set to the correct width except for the ones that I have recently made visible and the column immediately to the left of these. The ones recently made visible are very small (though I set their width to 30) and the one to the left of these columns is very large (though I've also set its width to 30).
I think it's something to do with the life cycle of the DataGrids because the first DataGrid behaves fine. It's when I click on the other tabs that I find that the widths of the other DataGrids have not been set correctly.
However, if I "see" one of those problem DataGrids (i.e. it appears on the screen) and the code which resizes the columns runs again, the columns are correctly sized.
I have tried a number of things recommended all over the internet including the questions listed below but to no avail.
This is the code I'm using to resize the columns (taken from this answer)
public static function resizeColumn(col:DataGridColumn, size:int):void
{
var owner:* = col.mx_internal::owner
col.mx_internal::owner = null;
col.width = size;
col.mx_internal::owner = owner;
}
Any and all help would be greatly appreciated.
I have already looked at the following answers.
Flex DataGrid column width: one column to rule them all?
Flex 3 DataGrid Column Width Problem
Flex DataGrid Column Width (<-- this answer got me closest)
Unable to change the column width dynamically in flex datagrid
So, after a huge amount of head wrecking, I finally found a solution (at least to my problem, not sure if it would help anyone else but thought I'd post it here anyway as you never know what could help someone else).
I decided that since calling the resize code when the DataGrid is on screen works then I needed to just do that. So I thought of putting the resize code for the relevant DataGrid depending on the tab clicked. Not that straightforward as there didn't seem to be a straightforward way to implement a click handler for the tabs. I did a quick Google and found this solution.
Essentially, you add a click handler for each tab button by cycling through the children of the tab navigator, getting the button and adding an event listener.
Then, you do what you need to do in the handler.
Code example (slightly different to one from website):
protected function tbGridArea_creationCompleteHandler(event:FlexEvent):void
{
for ( var i:int=0; i < tbGridArea.getChildren().length; i++ )
{
var tab:Object = tbGridArea.getTabAt(i);
tab.addEventListener( FlexEvent.BUTTON_DOWN,myTabClickHandler );
}
}
private function myTabClickHandler(event:Event):void {
switch(event.currentTarget.label) {
// do whatever you need to do here
}
}

Flex : best way to avoid slide transition quirks

I have a custom viewstack that applies automatically a slide in/slide out effect when the view changes. Everything goes smoothly when the views are lightweight but becomes jumpy when the next view requires heavy rendering.
Here are the relevant parts of the code :
_showEffect = new Parallel();
_contentMove = new Move();
_imageMove = new Move();
_showEffect.addChild(_contentMove);
_showEffect.addChild(_imageMove);
_showEffect.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);
I apply the parallel effect to the showEffect of every view :
vis.setStyle("showEffect", _showEffect);
I define the property of the moves depending on the direction of the animation, here to the left (where _views is my resident viewstack in the custom component) :
_contentMove.xFrom = _views.width;
_contentMove.xTo = 0;
_contentMove.yFrom = 0;
_contentMove.yTo = 0;
_imageMove.xFrom = 0;
_imageMove.xTo = -_views.width;
_imageMove.yFrom = 0;
_imageMove.yTo = 0;
_imageMove moves a screen image of the previous view which is set to visible when the animation starts and hidden when it ends.
I have tried some hacks like lengthening the duration of the animation when the next page has never been shown before but this is not quite generic as the required duration to have a smooth transition changes depending on the rendering requirements.
Isn't there any way like in other programming languages to force the layout/rendering process of the next page while it is still out of view ?
Thanks
Viewstack has a creationPolicy property. By default this is set to ContainerCreationPolicy.AUTO, which means the views are rendered as-needed. This explains why the view appears jumpy when switching to it. You can set the creationPolicy property to ContainerCreationPolicy.ALL and it will force the ViewStack to prerender all of its views before they are loaded.
This will solve your problem but note that it will increase overall initialization time of your application because it will now be forced to render everything ahead of time.

Generate a flex image from a hidden component

I'm trying to put an image, generated from some text, in a RichEditableText. Since it's a styled text, I thought about putting it another RichEditableText, style it, then print it to a Bitmap to use as source for InlineGraphicsElement.
I use the following code to do that
var txt:RichEditableText = new RichEditableText();
txt.text = name;
// Appliy given styles to the text flow of input rich editable text
createApplyNamedStyle(name, styles).call(null, txt.textFlow);
var bitmapData:BitmapData = new BitmapData(txt.width, txt.height);
bitmapData.draw(txt);
var bitmap:Bitmap = new Bitmap(bitmapData);
Unfortunatly, when called, it displays an error stack
ArgumentError: Error #2015: BitmapData non valide.
at flash.display::BitmapData()
at RichTextEditor/getTagImage()[E:\FlexWorkspace\Test\src\RichTextEditor.mxml:74]
at RichTextEditor/insertTag()[E:\FlexWorkspace\Test\src\RichTextEditor.mxml:154]
I suspect it is due to the fact that my RichEditableText, not being in visible component, is not laid out.
How can I ensure it is properly laid out ?
And am i doing the right thing to transform my text into an image ?
You're right; since the text is not on the display list, it is never validated and hence has 0 height and width.
A typical workaround is to add the item to the display list and then remove it immediatley. A little more discussion in this SO question.
You should trace txt.width and txt.height. They must be at least greater or equal to one. It does not matter if a DisplayObject is visible or not.

Resources