Get Notified of Change in Flex Bitmap or BitmapData? - apache-flex

In Flex, how does one hook into a bitmap or bitmapdata variable so that a function is notified whenever the bitmap's data has changed (pixel has changed, or filter's been added)?
I tried setting up binding but it doesn't work.
There must be a way to do it, because I can bind an mx:Image to a bitmap via the 'source' attribute, and the displayed image updates all the time when a I modify the bitmap. How does flex do it? Does it blindly redraw the bitmap at every frame, or is it smart and only redraws when the bitmap changes? If so, how does it know when the bitmap changes?

This is just sort of a semi-educated guess, with no testing behind it, so take it with some salt.
When Flex binds the source attribute of an Image, the value of .source is of type BitmapAsset.
BitmapAsset has a .bitmapData property, which is a reference to the bitmap in question.
I expect that the binding done by Flex is against that .bitmapData property.
I don't see any reason why you shouldn't be able to do that, too. I think you'd have to do a little circular work, though, as you'd have to create a BitmapAsset instance and populate it with the BitmapData you want to keep tabs on, then bind to the .bitmapData property of the BitmapAsset object.
Assuming a var called 'bitmapData', which is an instance of BitmapData, I think the following should work.
var bitmapAsset:BitmapAsset = new BitmapAsset(bitmapData);
var bitmapDataChangeWatcher:ChangeWatcher = BindingUtils.bindSetter(handleChangeToBitmapData, bitmapAsset, "bitmapData");
private function handleChangeToBitmapData(data:BitmapData):void
{
// Handle change to the bitmap data
}

Related

Adobe Scene7 BasicZoomViewer: How to reset zoom

Question
I'm working with Adobe Scene7 BasicZoomViewer and I'm looking for a way to tell the ZoomViewer to reset the zoom so that the user is no longer zoomed in on an image but instead will show the default "zoom" level.
What I've found
The closest thing I found to what I need is this reset property ZoomView.reset which "Resets the viewport when the frame (image) changes. If set to 0 it preserves the current viewport with the best possible fit while preserving the aspect ratio of the newly set image".
This looks close to something I need but it states that it will reset or preserve the aspect ratio when a new image has been inserted but I am not inserting new images.
Demo from Adobe
There is a button on the image that the API inserts into the page that resets the zoom level. Adobe provides a demo page that shows what I'm working with. If you look at the bottom left, the right-most button is the reset button. When clicked, it has to make some kind of API call and I need to figure out which one it is.
Edit
I've been able to find a minified version of the BasicZoomViewer and I am currently attempting to make sense of the code.
There is an event listener placed on the "Zoom Reset Button" that just simply calls a reset() method on line 274 in the uglified version of the file. Currently, I am trying to make sense of the file and figure out how to access this method.
c.zoomResetButton.addEventListener("click", function () {
c.zoomView.zoomReset()
});
I will be answering my own question. If someone finds a better way please feel free to answer as well.
tldr;
Create a variable to hold the instance of your s7viewers.BasicZoomViewer() and inside of that you can access the event handlers and much more.
Example of calling the reset zoom handler
// instantiate the s7viewers class and save it in a variable
var s7BasicZoomViewer = new s7viewers.BasicZoomViewer({
containerId: 's7viewer',
params: {
asset: assetUrl,
serverurl: serverUrl
})
// example of how to call the "zoomReset()" method
s7BasicZoomViewer.zoomResetButton.component.events.click[0].handler()
Explanation
After digging through the minified code that was uglified I found an event listener on the s7zoomresetbutton DOM class name, or perhaps it's watching for the ID of that DOM element which is the same ID as the container div for your S7 BasicZoom Viewer plus some added text to make this ID unique. For example, if the container div is s7viewer then the reset zoom button will have an ID of s7viewer_zoomresetbutton.
Now, going through the code I found this event listener which let me know there must be some way to call the zoomReset() method.
c.zoomResetButton.addEventListener("click", function () {
c.zoomView.zoomReset()
});
In the code above, the value of c is this or in other words it's the instance of your S7 BasicViewerZoom and in my case I have multiple depending on how many images I need to zoom on.
When instantiating the s7viewers class you can then reference that instance later and access the event handlers on each button and other properties and methods.
From there it was just looking through the object returned from the instance and calling the handler for the reset button.

Why JavaFX properties have not getListeners() methods

I am using JavaFX properties since JavaFX 8.0 , they seem to miss something appropriate i think . Let's say i add a change listener to a JavaFX Property :
DoubleProperty doubleProp = new SimpleDoubleProperty(1);
doubleProp.addListener((observable,oldValue,newValue)->{ ...code here }));
and i want to add 3 more including and InvalidationListener
Why to create an instances of ChangeListenerJavaDoc or InvalidationListenerJavaDoc?
Adding lines of code like :
ChangeListener<? super Number> listener = (observable , oldValue , newValue) -> {
if (newValue.intValue() == 1)
//..... code
};
all over the place isn't clear.
Why methods like these doesn't exist:
doubleProp.getChangeListeners().clearAll();
or
doubleProp.getChangeListeners().remove(doubleProp.getChangeListeners().get(0));
or
doubleProp.remove(doubleProp.getChangeListeners().get(0));
or
doubleProp.getInvalidationListeners().get(0));
Does JavaFX 9.0 has methods like these ? Is what i want a bad design ? I need to know the above :).
Allowing access to a collection of all listeners on a property would be a bad design as it would break encapsulation for controls (or other objects) that used those properties. (Specifically, a control would likely want to expose a property while registering listeners on that property and keeping those listeners private. If the property exposed the listeners, this would become impossible.)
Just as one example, if StringProperty exposed a ObservableList<ChangeListener<String>> getListeners() method, then the API would make the following possible:
Label label = new Label("Some text");
label.textProperty().getListeners().clear();
This would completely break the label. The label's skin registers a listener with the label's textProperty(), that ensures the skin updates if the text is changed. If you remove this listener, which is the only possible result of executing the code above, then the label's skin would not know it had to resize or even display new text when you called label.setText(...).
If you need to register a listener that you might need to remove, you just need to retain a reference to it. The overhead in code is minimal, i.e. there is not much difference between
label.textProperty().addListener((obs, oldText, newText) -> { /* code */ });
and
ChangeListener<String> listener = (obs, oldText, newText) -> {/* code */} ;
label.textProperty().addListener(listener);
#James_D, your explanation about what can go wrong when a listener is carelessly removed is good. However, this is really a developer problem, not design. Indeed, it is bad design for any 'add/remove' pattern not to also include access to whatever has been added.
For example, it may be useful to remove ("suspend") all the listeners temporarily in order to perform a process that changes the value (indeed several times) where the value at the end of the process is the same as the start; when the process is finished the listeners are added back ("restored"). While the 'reference' solution works for listeners you know about when designing a control, it doesn't help for listeners added by a developer using your control - these can't be referenced because you don't know what they will be. The 'suspend/restore' technique deals with this, it's up to the developer to use it properly and in the right situation.
JavaFX's property enhancements (object properties, bindings etc) are a huge improvement over Swing, like moving from a covered wagon to a Bugatti. However, the omission of a 'getListeners()' feature is a drawback.

Flex/AS3: Detecting whe the Image's source has changed

I have an image which its source depends on a bindable property of another object.
I'd like to know when this source changes, for example, by capturing the bind event or another related event of the Image control.
Thanks in advance.
There's a few ways to do this. One was is to use Bindsetter
private function creationComplete(event:FlexEvent):void{
BindingUtils.bindSetter(changeImage,hostObject,"image"); //assuming hostObject contains the property "image"
}
private function changeImage(imageSource:String){
//Set the image in here... do whatever else you wanted to do.
}

How to set an event listener for mx:image to kick in after image loads

Is there a way to dispatch an event after Flex loads an mx:image? I'm loading image externally and don't know the width/height until it's loaded. I get an exception when I call width/height to the image before loading.
you should use loader, in this case, like i have used in the below mentioned code
private var loader:loader = new Loader();
loader.load(new URLRequest(rp_product.dataProvider[i].#source));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,productLoadingComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,productLoadingError);
rp_product.dataProvider[i].#source, here rp_product is my repeater's id,
you simply give the image source here which u want to load, now you have productLoadingComplete() method, and productLoadingError() methods available, even if you want to something on image progess, so use this code :
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,onImageLoadProgress);
in this way, you can load an external image, i hope this is wht u wre luking for
you can attach listener for flash.events.Event.COMPLETE event. it is fired when image loading is complete.

Flex SWFLoader Event.COMPLETE not triggering

While trying to load a Bitmap onto a SWFLoader the Event.COMPLETE event is not being triggered
mySWFLoader.source = new Bitmap(Bitmap(someEvent.content).bitmapData);
but if I use a URL as source the complete event is triggered:
mySWFLoader.source = "http://example.com/123.jpg";
Is there some kind of restriction while using Bitmap as source?
I believe if you use data that already exists in memory (which your Bitmap would) then no load operation would happen. It should be usable immediately after construction. I know attaching movies in AS2 worked like that. If it was part of the library you could use it right away and no loading events would happen.
Use
mySWFLoader.addEventListener(Event.ADDED,handleSwfLoadComplete);
It fires when the content is actually created and added to the display list.
I encountered the same issue. The problem is that when you use Bitmap or Class as source, the content is populated only after the Bitmap or class was instantiated.
This happens in swfLoader.loadContent which eventually adds the newly created content to the displayList as the loader's child, and eventually dispatches the ADDED event.

Resources