Timeout XMLHttpRequest in QML - qt

How do I time out a XMLHttpRequest in QML? I have the following code, but it won't time out. It seems the timeout functionality is not implemented!? Is there any other way to achieve timeouts?
var http = new XMLHttpRequest();
http.open("POST", "http://localhost/test.xml", true);
http.setRequestHeader('Content-type', 'application/json; charset=utf-8')
http.timeout = 4000;
http.ontimeout = function () {
console.log("timed out")
}
http.onreadystatechange = function() {
if (http.readyState === XMLHttpRequest.DONE) {
// Do something
}
}
http.send(JSON.stringify(data));
Edit:
The code is not in a qml, but in a js file. And it won't go into a qml file as it is part of the model (MVC).

It looks that QML XMLHttpRequest does not support timeout function.
This is a list of supported subset of functions/properties:
http://qt-project.org/doc/qt-5/qtqml-javascript-qmlglobalobject.html#xmlhttprequest
But you can use QML Timer item for this purposes, for example:
import QtQuick 2.3
Item {
id: root
width: 600
height: 400
Text {
anchors.fill: parent
id: response
text: "Click me"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
MouseArea {
anchors.fill: parent
onClicked: {
response.text = "Loading...";
var req = new XMLHttpRequest();
var timer = Qt.createQmlObject("import QtQuick 2.3; Timer {interval: 4000; repeat: false; running: true;}",root,"MyTimer");
timer.triggered.connect(function(){
req.abort();
response.text = "timed out";
});
req.open("GET","http://google.com--",true); // correct me
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE && req.status == 200) {
response.text = req.getAllResponseHeaders();
timer.running = false;
}
}
req.send();
}
}
}
}

A global setTimeout() and setInterval() utility that models the functionality found in browsers.
It can be used to indirectly timeout an XMLHttpRequest. Or used sparingly elsewhere within the application.
timeoutId = util.timer.setTimeout(function() {}, 4500);
util.timer.clearInterval(timeoutId);
Main QML Snippet
With the following code, any child is able to access the methods under the app.util.timer namespace (or util.timer namespace if JS code is loaded in the main codebehind file).
import "CodeBehind.js" as CodeBehind
id: appWindow
QtObject {
id: app
property var util: CodeBehind.util
}
Component.onCompleted: {
CodeBehind.util.timer.init(appWindow);
}
CodeBehind JS Snippet
var util = util || {};
Qt.include("qrc:/Util/Timer.js");
Utility JS File
var util = util || {};
/**
Mimics the window.setTimeout() and window.setInterval() functionality
found in browsers.
#namespace timer
#memberof util
*/
util.timer = new function() {
var _timer;
var _timerList = [];
var _currentTime = 0;
var _api = {};
var _private = {};
var _enums = {};
/*************** Private ENUMS ***************/
_enums.type = {
timeout: 0,
interval: 1
};
/*************** Public API Methods ***************/
/**
Mimics the window.setTimeout() functionality found in browsers.
#param {function} callback
#param {int} interval Milliseconds
#public
#memberof util.timer
*/
_api.setTimeout = function(callback, interval) {
var timer, id;
id = parseInt(Math.random() * Date.now());
timer = new Timer(id, callback, interval, _enums.type.timeout);
_timerList.push({ id: id, timer: timer });
return id;
};
/**
Mimics the window.setInterval() functionality found in browsers.
#param {function} callback
#param {int} interval Milliseconds
#public
#memberof util.timer
*/
_api.setInterval = function(callback, interval) {
var timer, id;
id = parseInt(Math.random() * Date.now());
timer = new Timer(id, callback, interval, _enums.type.interval);
_timerList.push({ id: id, timer: timer });
return id;
};
/**
Clears an interval or timout by the interval id that is returned
when setTimeout() or setInterval() is called.
#param {int} intervalId
#public
#memberof util.timer
*/
_api.clearInterval = function(intervalId) {
var idx, len, idxOfTimer;
if (_timerList) {
// Find the index of the timer
len = _timerList.length;
for (idx = 0; idx < len; idx++) {
if (_timerList[idx].id === intervalId) {
idxOfTimer = idx;
break;
}
}
// Remove the timer from the array
_timerList.splice(idxOfTimer, 1);
}
// If: There are no more timers in the timer list
// Then: Stop the QML timer element
if (!_timerList || _timerList.length === 0) {
_private.stop();
}
};
/*************** Private Helper Methods ***************/
_private.start = function() {
_timer.start();
};
_private.stop = function() {
_timer.stop();
_currentTime = 0;
};
_private.runInterval = function() {
var idx, len, tempList;
// Increment the current timer
_currentTime++;
if (_timerList) {
// Create a temp list of timers
tempList = [];
len = _timerList.length;
for (idx = 0; idx < len; idx++) {
tempList.push(_timerList[idx].timer);
}
// Trigger each method
len = tempList.length;
for (idx = 0; idx < len; idx++) {
tempList[idx].trigger();
}
}
};
/*************** Objects ***************/
/**
A timer object contains a trigger to check and see if it needs
to run the callback.
#param {int} id
#param {function} callback
#param {int} interval Milliseconds
#param {enum} type type.interval | type.timeout
#public
#memberof util.timer
*/
var Timer = function(id, callback, interval, type) {
var _obj = {};
_obj.api = {};
_obj.hasRun = false;
_obj.endTime = _currentTime + interval;
_obj.api.trigger = function() {
if (_currentTime >= _obj.endTime && !_api.hasRun) {
_obj.hasRun = true;
callback();
if (type === _enums.type.interval) {
_obj.endTime += interval;
_api.hasRun = false;
}
else {
_api.clearInterval(id);
}
}
};
_private.start();
return _obj.api;
};
/*************** Initialize ***************/
_api.init = function(appWindow) {
_timer = Qt.createQmlObject("import QtQuick 2.3; Timer { interval: 1; repeat: true; running: false;}", appWindow, "timer");
_timer.triggered.connect(_private.runInterval);
};
return _api;
};

Related

A button to start in highcharts

Here is my charts, dynamically update. Now im trying to add a button which, to start the dynamic charts.
Ideally, i wish the data to be initialized when i press the button, however it seems that the data could not be initialized simultaneously with the method.Or let's be simply, is it possible to add a button that i could control, when to start the chart and, when to stop or pause?
var time = null;
var bol = false;
var chart;
var data = [];
// function play(){
// var time = (new Date()).getTime(), i;
// for(i = -1999; i <= 0; i += 1){
// data.push([
// time + i *1000,
// Math.round(Math.random() * 100)
// ]);
// }
// }
data = (function () {
var data = [], time = (new Date()).getTime(), i;
for (i = -1999; i <= 0; i += 1) {
data.push([time + i * 1000, Math.round(Math.random() * 100)]);
}
return data;
}());

Checkbox itemrender of Advanced grid does not hold proper selections on next open event of tree in Flex 4

I have a checkbox in AdvancedDataGrid as GroupItemrenderer.I have selected certain child nodes in tree and closed its parent,later when I reopen the same parent node,selected child nodes are not those that i selected.How to retain the correct selections in checkbox.??
Also am unable to set the value for checkbox (GroupItemRenderer) by default from component and also unable to access the value for checkbox in Data property.
package
{
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import mx.collections.ICollectionView;
import mx.collections.IHierarchicalCollectionView;
import mx.collections.IHierarchicalData;
import mx.collections.IViewCursor;
import mx.controls.AdvancedDataGrid;
import mx.controls.Alert;
import mx.controls.CheckBox;
import mx.controls.Image;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.controls.advancedDataGridClasses.AdvancedDataGridGroupItemRenderer;
import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
import mx.core.FlexGlobals;
import mx.core.mx_internal;
use namespace mx_internal;
public class CheckADGRenderer extends AdvancedDataGridGroupItemRenderer
{
protected var myImage:Image;
public var status:String = "false";
// set image properties
private var imageWidth:Number = 6;
private var imageHeight:Number = 6;
private var inner:String = "inner.png";
protected var myCheckBox:CheckBox;
static private var STATE_SCHRODINGER:String = "schrodinger";
static private var STATE_CHECKED:String = "checked";
static private var STATE_UNCHECKED:String = "unchecked";
public function CheckADGRenderer ()
{
super();
mouseEnabled = false;
}
private function toggleParents(item:Object,adg:AdvancedDataGrid,state:String):void
{
if (item == null)
{
return;
}
else
{
item.#state = false;
toggleParents(adg.getParentItem(item), adg, getState (adg, adg.getParentItem(item)));
}
}
private function toggleChildren (item:Object, adg:AdvancedDataGrid, state:String):void
{
if (item == null)
{
return;
}
else
{
//item.#state = state;
var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
var adgHD:IHierarchicalData = adgCollection.source;
if (adgHD.hasChildren(item))
{
var children:ICollectionView = adgCollection.getChildren (item);
var cursor:IViewCursor = children.createCursor();
while (!cursor.afterLast)
{
toggleChildren(cursor.current, adg, state);
cursor.moveNext();
}
}
}
}
private function getState(adg:AdvancedDataGrid, parent:Object):String
{
var noChecks:int = 0;
var noCats:int = 0;
var noUnChecks:int = 0;
if (parent != null)
{
var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
var cursor:IViewCursor = adgCollection.getChildren(parent).createCursor();
}
if ((noChecks > 0 && noUnChecks > 0) || (noCats > 0))
{
return STATE_SCHRODINGER;
}
else if (noChecks > 0)
{
return STATE_CHECKED;
}
else
{
return STATE_UNCHECKED;
}
}
private function imageToggleHandler(event:MouseEvent):void
{
myCheckBox.selected = !myCheckBox.selected;
checkBoxToggleHandler(event);
}
var selectArr:Array = new Array();
private function checkBoxToggleHandler(event:MouseEvent):void
{
if (data)
{
var myListData:AdvancedDataGridListData = AdvancedDataGridListData(this.listData);
var selectedNode:Object = myListData.item;
var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
var toggle:Boolean = myCheckBox.selected;
if (toggle)
{
toggleChildren(data, adg, STATE_CHECKED);
}
else
{
toggleChildren(data, adg, STATE_UNCHECKED);
}
var parent:Object = adg.getParentItem (data);
toggleParents (parent, adg, getState (adg, parent));
//Alert.show(selectArr.toString()+"\t\t"+selectArr.length+"\t\t"+selectArr[0].length+"\t\t"+adg.selectedIndices.length);
}
}
override protected function createChildren():void
{
super.createChildren();
myCheckBox = new CheckBox();
myCheckBox.setStyle( "verticalAlign", "middle" );
myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxToggleHandler );
addChild(myCheckBox);
}
private function setCheckState (checkBox:CheckBox, value:Object, state:Boolean):void
{
if (state == STATE_CHECKED)
{
checkBox.selected = state;
}
else if (state == STATE_UNCHECKED)
{
checkBox.selected = false;
}
else if (state == STATE_SCHRODINGER)
{
checkBox.selected = false;
}
checkBox.selected = state;
}
override public function set data(value:Object):void
{
super.data = value;
var myListData:AdvancedDataGridListData = AdvancedDataGridListData(this.listData);
//var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
var selectedNode:Object = myListData.item;
myCheckBox.selected = AdvancedDataGridListData(super.listData).item.show;
//var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
//setCheckState (myCheckBox, value, Boolean(value.state));
}
override protected function commitProperties():void
{
super.commitProperties();
var dg:AdvancedDataGrid = AdvancedDataGrid(listData.owner);
var column:AdvancedDataGridColumn =
dg.columns[listData.columnIndex];
label.wordWrap = dg.columnWordWrap(column);
}
/**
* #private
*/
override protected function measure():void
{
super.measure();
var w:Number = data ? AdvancedDataGridListData(listData).indent : 0;
if (disclosureIcon)
w += disclosureIcon.width;
if (icon)
w += icon.measuredWidth;
if (myCheckBox)
w += myCheckBox.measuredWidth;
// guarantee that label width isn't zero because it messes up ability to measure
if (label.width < 4 || label.height < 4)
{
label.width = 4;
label.height = 16;
}
if (isNaN(explicitWidth))
{
w += label.getExplicitOrMeasuredWidth();
measuredWidth = w;
}
else
{
label.width = Math.max(explicitWidth - w, 4);
}
measuredHeight = label.getExplicitOrMeasuredHeight();
if (icon && icon.measuredHeight > measuredHeight)
measuredHeight = icon.measuredHeight;
if (myCheckBox && myCheckBox.measuredHeight > measuredHeight)
measuredHeight = myCheckBox.measuredHeight;
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(super.data)
{
if (super.icon != null)
{
myCheckBox.x = super.icon.x;
myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
super.icon.x = myCheckBox.x + myCheckBox.width + 17;
if (icon.x + icon.width > unscaledWidth)
icon.setActualSize(0, unscaledHeight);
super.label.x = super.icon.x + super.icon.width + 3;
super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
}
else
{
myCheckBox.x = super.label.x;
myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
super.label.x = myCheckBox.x + myCheckBox.width + 17;
super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
}
if (myCheckBox.x + myCheckBox.width > unscaledWidth)
myCheckBox.visible = false;
}
trace(label.width);
}
}
}
I am using 2D array as dataprovider to ADG.
My post :
how to add an attribute to an existing array dynamically in Flex , is associated with the above post.
I suspect you haven't written any code to set the default state of the Checkbox based on data.
Generically, your itemRenderer's Checkbox state should be stored as part of the data. When the
itemRenderer is initialized, set the checkbox to checked--or not--based on the property in your data element. When the Checkbox is clicked; change that same property in your data element.
This approach will sync your itemRenderer's display state up with your data.
If you want a more specific answer, you'll have to share some code so we can see what you're doing.

How to change the loading clock in Flex

How can I replace the loading clock in Flex at the cursor to something like loading wheel in the middle of page instead of cursor
I loathe that little clock. A clock on the mouse just tells the user that something is busy, but they don't know what. It is much better to display a progress indicator visually NEAR the thing that it is showing the progress of!
So, my solution is to enforce a ban on CursorManager, and instead supply your own progress indicator.
Example: A submit button in a form. You know that the submittal is asynchronous and it will take an indeterminate amount of time. So after the user clicks the button and the request is executed, display a little spinner to the direct right of the button. When the request is complete, hide the spinner. It's very sad to see a user who is worried that her actions did not accomplish anything--so give them a way of determining that your application is indeed functioning!
To go along with Jonathon Dumaine's answer, here's an example of the Spinner class I use as a busy indicator in my apps. Just remember to call the stop() method when you first load it since it will use memory in your app if it's playing even when visible is set to false. You can call the play() method when you want it to start spinning again.
Spinner.as
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
[Style(name="tickColor",type="uint",format="Color",inherit="no")]
public class Spinner extends UIComponent {
private static var STYLE_TICK_COLOR:String = "tickColor";
private var tickColorChanged:Boolean;
private static var classConstructed:Boolean = classConstruct();
// Make sure we create the ticks the first time updateDisplayList is called
private var creation:Boolean = true;
private var fadeTimer:Timer;
private var _isPlaying:Boolean;
private var _numTicks:int = 12;
private var numTicksChanged:Boolean;
private var _size:Number = 30;
private var sizeChanged:Boolean;
private var _tickWidth:Number = 3;
private var tickWidthChanged:Boolean;
private var _speed:int = 1000;
[Bindable] public var fadeSpeed:int = 600;
public var autoPlay:Boolean = true;
public function Spinner() {
super();
addEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
addEventListener(FlexEvent.REMOVE, handleUnloading)
}
private function handleCreationComplete(e:FlexEvent):void {
removeEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
if (autoPlay) {
play();
}
}
/**
* Set the height and width based on the size of the spinner. This should be more robust, but oh well.
*/
override protected function measure():void {
super.measure();
width = _size;
height = _size;
}
/**
* Override the updateDisplayList method
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
if (tickColorChanged || numTicksChanged || sizeChanged || tickWidthChanged || creation) {
creation = false;
// Find out whether it's playing so we can restart it later if we need to
var wasPlaying:Boolean = _isPlaying;
// stop the spinning
stop();
// Remove all children
for (var i:int = numChildren - 1; i >= 0; i--) {
removeChildAt(i);
}
// Re-create the children
var radius:Number = size / 2;
var angle:Number = 2 * Math.PI / _numTicks; // The angle between each tick
var tickWidth:Number = (_tickWidth != -1) ? _tickWidth : size / 10;
var tickColor:uint = getStyle(STYLE_TICK_COLOR);
var currentAngle:Number = 0;
for (var j:int = 0; j < _numTicks; j++) {
var xStart:Number = radius + Math.sin(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
var yStart:Number = radius - Math.cos(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
var xEnd:Number = radius + Math.sin(currentAngle) * (radius - tickWidth);
var yEnd:Number = radius - Math.cos(currentAngle) * (radius - tickWidth);
var t:Tick = new Tick(xStart, yStart, xEnd, yEnd, tickWidth, tickColor);
t.alpha = 0.1;
this.addChild(t);
currentAngle += angle;
}
// Start the spinning again if it was playing when this function was called.
if (wasPlaying) {
play();
}
tickColorChanged = false;
numTicksChanged = false;
sizeChanged = false;
tickWidthChanged = false;
}
}
private static function classConstruct():Boolean {
if (!FlexGlobals.topLevelApplication.styleManager.getStyleDeclaration("Spinner")) {
// If there is no CSS definition for StyledRectangle,
// then create one and set the default value.
var newStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
newStyleDeclaration.setStyle(STYLE_TICK_COLOR, 0x000000);
FlexGlobals.topLevelApplication.styleManager.setStyleDeclaration("Spinner", newStyleDeclaration, true);
}
return true;
}
override public function styleChanged(styleProp:String):void {
if (styleProp == STYLE_TICK_COLOR) {
tickColorChanged = true;
invalidateDisplayList();
}
}
/**
* Begin the circular fading of the ticks.
*/
public function play():void {
if (! _isPlaying) {
fadeTimer = new Timer(speed / _numTicks, 0);
// addEventListener for the ticking going forward
fadeTimer.addEventListener(TimerEvent.TIMER, handleTicking);
fadeTimer.start();
_isPlaying = true;
}
}
/**
* Start the Tick at each Timer.
*/
public function handleTicking(e:TimerEvent):void {
var tickNum:int = int(fadeTimer.currentCount % _numTicks);
if (numChildren > tickNum) {
var tick:Tick = getChildAt(tickNum) as Tick;
tick.fade(fadeSpeed != 1 ? fadeSpeed : speed * 6 / 10);
}
}
/**
* Start the Tick at each Timer.
*/
public function handleUnloading(e:FlexEvent):void {
stop();
removeEventListener(FlexEvent.REMOVE, handleUnloading);
trace("Removing "+this.uid.toString());
}
/**
* Stop the spinning.
*/
public function stop():void {
if (fadeTimer != null && fadeTimer.running) {
_isPlaying = false;
fadeTimer.removeEventListener(TimerEvent.TIMER, handleTicking);
fadeTimer.stop();
}
}
/**
* The overall diameter of the spinner; also the height and width.
*/
[Bindable]
public function set size(value:Number):void {
if (value != _size) {
_size = value;
sizeChanged = true;
invalidateDisplayList();
invalidateSize();
}
}
public function get size():Number {
return _size;
}
/**
* The number of 'spokes' on the spinner.
*/
[Bindable]
public function set numTicks(value:int):void {
if (value != _numTicks) {
_numTicks = value;
numTicksChanged = true;
invalidateDisplayList();
}
}
public function get numTicks():int {
return _numTicks;
}
/**
* The width of the 'spokes' on the spinner.
*/
[Bindable]
public function set tickWidth(value:int):void {
if (value != _tickWidth) {
_tickWidth = value;
tickWidthChanged = true;
invalidateDisplayList();
}
}
public function get tickWidth():int {
return _tickWidth;
}
/**
* The duration (in milliseconds) that it takes for the spinner to make one revolution.
*/
[Bindable]
public function set speed(value:int):void {
if (value != _speed) {
_speed = value;
fadeTimer.stop();
fadeTimer.delay = value / _numTicks;
fadeTimer.start();
}
}
public function get speed():int {
return _speed;
}
public function get isPlaying():Boolean {
return _isPlaying;
}
}
}
Tick.as
package {
import flash.display.Sprite;
import mx.effects.Fade;
public class Tick extends Sprite {
private var tickFade:Fade = new Fade(this);
public function Tick(fromX:Number, fromY:Number, toX:Number, toY:Number, tickWidth:int, tickColor:uint) {
this.graphics.lineStyle(tickWidth, tickColor, 1.0, false, "normal", "rounded");
this.graphics.moveTo(fromX, fromY);
this.graphics.lineTo(toX, toY);
}
public function fade(duration:Number):void {
tickFade.alphaFrom = 1.0;
tickFade.alphaTo = 0.1;
tickFade.duration = duration;
tickFade.play();
}
}
}
You can hide the cursor rather than calling setBusyCursor on the CursorManager use http://www.igorcosta.com/flex3/doc/mx/managers/CursorManager.html#hideCursor() then just toggle the visibility of an overlay with your loading graphic.
You can use CursorManager.showCursor(); and CursorManager.removeBusyCursor(); to show and remove busy cursor.

How to capture Alert Dialog Box Selection?

Within an event handler I have an Alert.show(...) that prompts a user for confirmation. How can I capture the selection of the alert prompt and use it within the event handler. For example:
private function mainEvtHandler(event:DynamicEvent):void {
var alert:Alert = Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this, alertHandler);
// How can I retrieve the selection and use it within this event handler?
// i.e. if (alert == Alert.Yes) { ...
var index:int = arrayColl.getItemIndex(event.data)
...
...
You can declare the alertHandler as nested function ...
private function mainEvtHandler(event:DynamicEvent):void {
var alertResult: int = -1;
function alertHandler(evt:CloseEvent):void {
alertResult = evt.detail;
}
var alert:Alert = Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this, alertHandler);
if (alertResult == Alert.Yes) {
var index:int = arrayColl.getItemIndex(event.data);
...
}
... or you can use an anonymous function
private function mainEvtHandler(event:DynamicEvent):void {
Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this,
function (nestedCloseEvent:CloseEvent):void {
if (nestedCloseEvent.detail == Alert.Yes) {
var index:int = arrayColl.getItemIndex(event.data);
...
}
}
);
}

as3: reloading an image

I have an image that I am attempting to load, and then reload. Here is my code for the loading of the image:
public function loadImage(url:String, _w:int, _h:int):void
{
this._stwidth = _w;
this._stheight = _h;
this._imageURL = url;
if(!_imageURL)
{
return;
}
this.alpha = 1.0; //need this because we might have just faded the image out
_ldr.alpha = 0.0;
_prog.alpha = 1.0;
_sqr.alpha = 0.0;
_sqr.graphics.clear();
if(_hasLoaded)
{
try
{
_ldr.close();
_ldr.unload();
}
catch(e:Error)
{
//trace("bmdisplay has loaded once, but there was an error: " + e.message);
}
}
_ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
_ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
_ldr.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
_ldr.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
_ldr.contentLoaderInfo.addEventListener(Event.INIT, onOpen);
_ldr.load(new URLRequest(_imageURL));
}
For some reason, this code will not load the image without issuing an Error upon the 2nd load.
Can someone please help me figure this out?
I am totally lost on why my variable _asLoaded would do me wrong.
I have an onComplete() handler, which sets that var to true, and I never set it to false after that.
I don't know what else I should be trying...
Thanks
Sometimes back I wrote a helper class to achieve something similar. The helper class extends Loader and provides automatic scaling of image. Here is the code for that class:package {
import flash.display.Loader;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
public class ImageLoader extends Loader {
private var _imageURL:String; // URL of image
private var _imageBoundary:Rectangle; // boundary rectangle for the image
private var _loaded:Boolean; // flag which tells whether image is loaded or not.
private var _isLoading:Boolean; // flag which say if any loading is in progress
//Constructor function, which calls Loader's constructor
// and loads and resize the image
public function ImageLoader(url:String = null, rect:Rectangle = null):void {
super();
_imageURL = url;
_imageBoundary = rect;
_loaded = false;
_isLoading = false;
loadImage();
}
// sets the image for the loader and loads it
public function set imageURL(url:String):void {
_imageURL = url;
loadImage();
}
// sets the boundary of the image and resizes it
public function set boundary(rect:Rectangle):void {
_imageBoundary = rect;
resizeImage();
}
private function removeListeners():void {
this.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete);
this.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onError);
this.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
}
private function onComplete(e:Event):void {
_loaded = true;
_isLoading = false;
removeListeners();
resizeImage();
}
//In case of error, we are not propogating the event
private function onError(e:Event):void {
e.stopImmediatePropagation();
removeListeners();
}
// real loading goes here
// it first closes and unloads the loader and
// then loads the image
private function loadImage():void {
if (_isLoading) {
trace("Some loading is in progess");
return;
}
try {
this.close();
this.unload();
}
catch(e:Error) {
//discarded
}
if (!_imageURL)
return;
_loaded = false;
_isLoading = true;
this.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
this.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
this.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
this.load(new URLRequest(_imageURL));
}
// standard resizing function for image so that it's
// aspect ratio is maintained.
private function resizeImage():void {
if (!_imageBoundary || !_loaded)
return;
var aspect:Number = width / height;
var cAspect:Number = _imageBoundary.width / _imageBoundary.height;
if (aspect <= cAspect) {
this.height = _imageBoundary.height;
this.width = aspect * this.height;
}
else {
this.width = _imageBoundary.width;
this.height = this.width / aspect;
}
this.x = (_imageBoundary.width-this.width)/2 + _imageBoundary.x;
this.y = (_imageBoundary.height-this.height)/2 + _imageBoundary.y;
}
}
} And you can use it like this:var _imageLoader:ImageLoader = new ImageLoader();
_imageLoader.imageURL = "http://some-image-url";
_imageLoader.boundary = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight); // or whatever suits you
ImageLoader extends Loader class so you can listen to all the Events dispatches by Loader class. Hope it helps.
i would declare _ldr inside the function so its dead every time you start this function. and i also would not use this unload() and close() methods. its much simpler if make some thing like this (you need to have a empty movieclip called "ldrHelper"):
public function loadImage(url:String, _w:int, _h:int):void
{
// do your job and die bravely, no need to be global
var _ldr:Loader = new Loader();
this._stwidth = _w;
this._stheight = _h;
this._imageURL = url;
if(!_imageURL)
{
return;
}
this.alpha = 1.0; //need this because we might have just faded the image out
// now you will need to make alpha = 1 on ldrHolder since _ldr is dead after this function
ldrHolder.alpha = 0.0;
_prog.alpha = 1.0;
_sqr.alpha = 0.0;
_sqr.graphics.clear();
// remove the old image, doesn't matter whether its empty or not
while(ldrHolder.numChildren > 0){
ldrHolder.removeChildAt(0);
}
//add image
ldrHolder.addChild(_ldr);
_ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
_ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
_ldr.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
_ldr.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
_ldr.contentLoaderInfo.addEventListener(Event.INIT, onOpen);
_ldr.load(new URLRequest(_imageURL));
}
Try instantiating new Loader, probably trying to recycle it is giving you the problem

Resources