AS3 Loading dynamically named text files - actionscript-3

I have a preload movie that loads an interface. In the interface I have many buttons. When I click on a button I want to load a text file into a movie called "TextMovie.swf". I want to be able to click on a button, take the name of the button and load a text file that is the same name as the button instance, and have the window appear close to the mouse click. There will be hundreds of buttons and hundreds of text files. I'm sure this is easy for some. Here is the loader for a button:
button_1.addEventListener(MouseEvent.CLICK, fl_ClickToPosition_2);
function fl_ClickToPosition_2(event:MouseEvent):void
{
var my2ndLoader:Loader = new Loader();
var url2:URLRequest = new URLRequest("TextMovie.swf");
my2ndLoader.load(url2);
addChild(my2ndLoader);
my2ndLoader.x = 200;
my2ndLoader.y = 10;
}
Then in the TextMovie.swf I have:
import flash.net.URLLoader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.StyleSheet;
var css:StyleSheet = new StyleSheet();
css.setStyle("a:hover", {textDecoration:"underline"});
var textLoader: URLLoader = new URLLoader();
textLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
textLoader.addEventListener(Event.COMPLETE, textLoaded);
loadText();
function textLoaded(evt: Event): void {
title_txt.htmlText = textLoader.data.txtTitle;
main_txt.htmlText = textLoader.data.txtBody;
URL_txt.htmlText = textLoader.data.txtURL;
URL_txt.styleSheet = css
}
function loadText(): void {
// var fileName: String = "assets/test_01.txt";
var fileName: String = "assets/" + + ".txt";
textLoader.load(new URLRequest(fileName));
}
I'm not sure how to get the name of the button I pushed and apply it to the string that will load the correct text file. I also can't get the window to appear close to the mouse click. Right now I just have it set with an x and y for testing.
I know it's a lot but thanks for any help.

I suggest you take a look at the docs for MouseEvent so you better understand what data is passed as parameters when the event is triggered.
In the event handler, a reference is passed to the object which was clicked: the event target– and from that you can get its name, location, etc. This is good because it means you only need one event handler for all your buttons.
Once you have the name, you can build the string you need for your url. (I wouldn't do it that way if it is a project which is going to have any sort of lifespan but it's an ok approach).
You can get the x and y location of the target, its width and height, and use that data to position your window. The localX and localY properties refer to the click location relative to the rect of the target (button) – with top/left of the target== 0,0.
This is the trace output from the function below:
red red.swf
600 400
25 8.5
button_1.addEventListener(MouseEvent.CLICK, onHandleButtonClick);
function onHandleButtonClick(event:MouseEvent):void
{
var btnName:String = event.target.name;
var swfName:String = btnName + ".swf";
trace(btnName, swfName);
trace(event.target.x, event.target.y);
trace(event.localX, event.localY);
}

Related

Why is my action script event not firing?

Presently, I am attempting to add the ability to capture all the slides of a presentation to images and save them to disk. It works now where the first page is capture, then I want an async event to fire when the second page has loaded to capture that page, and so on. Here is where I have added an event listener, though I'm not sure if I should be using stage or this:
import flash.events.Event;
private var jpgEncoder:JPGEncoder;
// ...
private function init():void{
// ...
// Add async event to capture second page after loading
stage.loaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
// ...
}
private function onPrintButtonClicked():void {
// screen capture code
jpgEncoder = new JPGEncoder(90);
// Page 1 capture
bitmapData1 = new BitmapData(stage.width, stage.height);
bitmapData1.draw(stage, new Matrix());
// move to next page
var curPage:Page = PresentationModel.getInstance().getCurrentPage();
if (curPage != null) {
LOGGER.debug("Go to next page. Current page [{0}]", [curPage.id]);
pageCount++;
dispatchEvent(new GoToNextPageCommand(curPage.id));
} else {
LOGGER.debug("Go to next page. CanNOT find current page.");
}
}
private function onLoadComplete(e:Event)
{
// Get page 2 capture
bitmapData2 = new BitmapData(stage.width, stage.height);
bitmapData2.draw(stage, new Matrix());
// Copy two pages to one bitmap
var rect1:Rectangle = new Rectangle(0, 0, stage.width, stage.height);
var pt1:Point = new Point(0, 0);
bitmapData3 = new BitmapData(stage.width, stage.height * 2);
bitmapData3.copyPixels(bitmapData1, rect1, pt1)
var rect2:Rectangle = new Rectangle(0, 0, stage.width, stage.height);
var pt2:Point = new Point(0, stage.height);
bitmapData3.copyPixels(bitmapData2, rect2, pt2)
// Convert to image
var img:ByteArray = jpgEncoder.encode(bitmapData3);
var file:FileReference = new FileReference();
file.save(img, "capture1.jpg");
}
Does anyone have any ideas as to why the OnLoadComplete function is never called? FYI, here is the full source code: https://github.com/john1726/bigbluebutton/blob/master/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
TIA
Please note that I've found that the stage was still null in the init() method so an exception was being thrown:
stage.loaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
Also, after resolving that stage error I found that I have been receiving this error using this tool: https://github.com/capilkey/Vizzy-Flash-Tracer
Error #2176: Certain actions, such as those that display a pop-up window, may only be invoked upon user interaction, for example by a mouse click or button press.
So the solution is either to re-work the UI so that there is a button press to prepare the files and a second button press to actually save the image or setup them mouseup and mousedown events to call different functions:
s:Button mouseDown="prepare_PDF()" mouseUp="save_PDF()"
Source: Flex's FileReference.save() can only be called in a user event handler -- how can I get around this?
Thank you!

AS3 Retrieving a file from FZip

I am currently coding a game and I am storing all external files in a zip file to save space.
I am trying to use Fzip to load an image out of the Zip file and display it on stage but I am having no luck.
FZip Site - http://codeazur.com.br/lab/fzip/
Example 1 Site - http://www.tuicool.com/articles/7VfQr2
I have got the zip file to load and return me the number of files inside it but I cannot figure out how to retrieve an image called "test.png".
import deng.fzip.FZip;
import deng.fzip.FZipFile;
import deng.fzip.FZipLibrary;
import flash.display.*;
var zip:FZip = new FZip();
var loaderzippy:Loader = new Loader();
function unzipObb():void {
zip.load(new URLRequest("file://"+File.applicationStorageDirectory.nativePath+"/cake2.zip"​));
zip.addEventListener(Event.OPEN, onOpen);
zip.addEventListener(Event.COMPLETE, dosomething); }
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.loadBytes(img_file.content);
var image:Bitmap = Bitmap(loaderzip.content);
addChild(image); }
I just get returned #2007: Parameter child must be non-null.
Any help would be great. Thanks.
When you load the PNG bytes using loaderzip.loadBytes(), you need an event listener to check when it's done loading. The documentation itself states:
The loadBytes() method is asynchronous. You must wait for the "init" event before accessing the properties of a loaded object.
Because you're trying to access the code directly after you called loadBytes(), at which point it hasn't actually loaded anything, you're getting a null bitmap.
Although you can access the data once the "init" event has been dispatched, it's best to wait for the "complete" event, since you want your image to be done loading (rather than halfway done).
I've tweaked your code to something that should work:
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.contentLoaderInfo.addEventListener(Event.COMPLETE, getImage);
loaderzip.loadBytes(img_file.content);
}
function getImage(e:Event):void {
var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo;
var image:Bitmap = Bitmap(loaderInfo.content);
addChild(image);
}
(I haven't tested this myself but it's just to give you the general idea anyway.)
Note that you should add the event listener to loaderzip.contentLoaderInfo, not just loaderzip. That's what actually dispatches the event and it also contains the loaded content.

AS3 simple horizontal gallery

I have a simple horizontal gallery of 24 pictures.
The idea is to show 3 pictures on the screen from all (24) and the middle one to be shown above as the big one automaticly ( like the scheme ). This means that when some of the arrows is pressed the movement of the images have to be by one. Also they have to be auto looped. So the first one can go in the middle to.
Here is my code so far. ( I didn't put the all 24 thumbnails, here are only 3 thumbnails only for the tests ) I've managed to move the thumbnails and select a big picture. But I need it to be auto selected when comes to the middle.
buttonL1_btn.addEventListener(MouseEvent.CLICK, left);
buttonR1_btn.addEventListener(MouseEvent.CLICK, right);
function left(event:Event):void{
box_mc.x -=50;
}
function right(event:Event):void{
box_mc.x +=50;
}
//imgs
img_3_big.visible = false;
box_mc.img_1.addEventListener(MouseEvent.CLICK, img1_show);
function img1_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(3);
}
box_mc.img_2.addEventListener(MouseEvent.CLICK, img2_show);
function img2_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(2);
}
box_mc.img_3.addEventListener(MouseEvent.CLICK, img3_show);
function img3_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(1);
}
Although a different approach than what you have already done, the way I would do it is by keeping all 24 images outside of the .swf in their own image files and keeping track of the current image index. Something similar to this (untested code):
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.MouseEvent;
var allImagePaths:Vector.<String> = new Vector.<String>(); // Holds reference to all big images
var allImageThumbPaths:Vector.<String> = new Vector.<String>(); // Holds reference to all thumbnail images
var currentImageIndex:int = 0; // Keeps track of what image is currently selected
// Loaders that would load big image and thumbnails
var loaderMain:Loader;
var loaderThumb_Left:Loader;
var loaderThumb_Middle:Loader;
var loaderThumb_Right:Loader;
SetupGallery(); // initialize gallery
function SetupGallery()
{
// Setup image loaders
loaderMain = new Loader();
loaderThumb_Left = new Loader();
loaderThumb_Middle = new Loader();
loaderThumb_Right = new Loader();
// Add loaders to existing MovieClips on stage.
imageHolderMain_mc.addChild(loaderMain);
imageHolderThumbLeft_mc.addChild(loaderThumb_Left);
imageHolderThumbMiddle_mc.addChild(loaderThumb_Middle);
imageHolderThumbRight_mc.addChild(loaderThumb_Right);
// Load image paths into a vector collection (like an array)
loadImages();
// Setup arrow button listeners
buttonL1_btn.addEventListener(MouseEvent.CLICK, showImageLeft);
buttonR1_btn.addEventListener(MouseEvent.CLICK, showImageRight);
}
function loadImages()
{
// Initialize collection of images for easier looping/displaying
allImagePaths = new Vector.<String>();
allImageThumbPaths = new Vector.<String>();
// Load up all image paths into the image array(vector).
allImagePaths.push("image1.jpg");
allImageThumbPaths.push("image1_thumb.jpg");
// ... image2 - image23 ...
allImagePaths.push("image24.jpg");
allImageThumbPaths.push("image24_thumb.jpg");
// NOTE: Consider loading paths to image files via xml
}
function showImageLeft(evt:MouseEvent)
{
currentImageIndex--;
showCurrentImage();
}
function showImageRight(evt:MouseEvent)
{
currentImageIndex++;
showCurrentImage();
}
// Call this after each arrow click, direction will be determined by currentImageIndex
function showCurrentImage()
{
// Keep current index within bounds, if out of range then "loop back"
if(currentImageIndex < 0) currentImageIndex = allImagePaths.length - 1;
if(currentImageIndex > allImagePaths.length - 1) currentImageIndex = 0;
// Set right and left thumbnail indexes based on current image
// (Assuming my logic is correct of course :)
var indexRight:int = currentImageIndex - 1;
if(indexRight < 0) indexRight = allImagePaths.length - 1; // "Loop back" if needed
var indexLeft:int = currentImageIndex + 1;
if(indexLeft > allImagePaths.length - 1) indexLeft = 0; // "Loop back" if needed
// clear out any existing images
loaderMain.unload();
loaderThumb_Left.unload();
loaderThumb_Middle.unload();
loaderThumb_Right.unload();
// set correct images based on new indexes
loaderMain.load(allImagePaths[currentImageIndex]);
loaderThumb_Left.load(allImageThumbPaths[indexLeft]);
loaderThumb_Middle.load(allImageThumbPaths[currentImageIndex]);
loaderThumb_Right.load(allImageThumbPaths[indexRight]);
}
There may be some additional things you'll have to handle, but that's the general idea.
Going with this approach you will not deal with keyframes, in fact you would want to have only one keyframe where the AS code is located and you would want to remove all images from the .swf file itself.
This approach will:
Allow for "Looping back" of images when at the end or beginning of the gallery.
Make it easier to add or remove images in the future.
Improve initial load time for the end user.

Label is not showing up

I'm building a simple menu from basic Flash UI components using bare ActionScript 3.0, and the very first Label control doesn't show up during the movie testing(Ctrl+Enter). Why is that?
I have no symbols in the Library or anything on the stage. My document is linked to main.as
What should happen is when the .swf is launched main() gets the instruction to generate mainMenu which in turn will display the only label in the center-top part of the movie screen.
main.as
package {
import flash.display.*;
public class main extends MovieClip{
public function main(){
changeState(null, "mainMenu");
}
public function changeState(currentState, nextState){
if(currentState != null){
removeChild(currentState);
}
if(nextState == "mainMenu"){
var main_menu:mainMenu = new mainMenu(changeState);
addChild(main_menu);
}// else if(nextState == "deckManager"){
// var deck_manager:deckManager = new deckManager(changeState);
// addChild(deck_manager);
// }
}
}
}
mainMenu.as
package {
import flash.display.*;
import flash.events.MouseEvent;
import fl.controls.Label;
import fl.controls.RadioButton;
import fl.controls.ComboBox;
import fl.controls.Button;
public class mainMenu extends Sprite{
const difficultyRadioGroupName:String = "difficultyGroup"; // group name for easy, normal and hard difficulty radio buttons
var difficultyLabel:Label; // "Difficulty" label
var easyDifficultyRadio:RadioButton; // "Easy" difficulty radio button
var normalDifficultyRadio:RadioButton; // "Normal" difficulty radio button
var hardDifficultyRadio:RadioButton; // "Hard" difficulty radio button
var yourDeckLabel:Label; // "Your deck" label
var yourDeckCombo:ComboBox; // combobox to select your deck(1)
var editSelectedDeckButton:Button; // button to edit currently selected deck
var startTheGameButton:Button; // button to start the game
var theCallbackFunction:Function; // callback function to change between mainMenu and deckManager
public function mainMenu(callback){
// create and position the difficulty label
difficultyLabel = new Label();
difficultyLabel.text = "Difficulty";
difficultyLabel.x = width / 2;
difficultyLabel.y = height / 4;
addChild(difficultyLabel);
theCallbackFunction = callback;
}
//public function backButtonClicked(evt:MouseEvent){
// theCallbackFunction(this, "back");
// return;
// }
}
}
On the surface this seems ok.
However, the X/Y coordinates you are assigning to the Label might not be what you are expecting. You set them based on the width/height of the mainMenu Sprite. But that Sprite has no children yet (the child is added on the next line), so the width/height are still 0.
This may not be the problem. To further trouble shoot this I would set some breakpoints and use a debugger, or add a bunch of trace statements to make sure your code is executing using the proper values.
I believe everything in the 'fl.controls' package requires the appropriate asset in your library to show up. If you just import things from fl.controls you get no UI aspect to the control unless you add that element to your library or ingest a swc/swf with the appropriate library assets in it.
So I'd guess that if in the flash IDE, if you dragged the appropriate UI elements from the components tab to your library, they would start showing up. They don't have to be on the stage or anything, just in the library so the UI elements get compiled with your code.

Save JPG from CDROM to PC

I am using following function to Save the output from SWF and send it to a PHP page so that it creates JPG, my problem if there is not INTERNET connection and the SWF is in a CDROM can the Save function be used in FLASH so that it outputs JPG and save it on a computer.
In short can we Save movieclip output as an JPG
/**
Screenshot and jpg output
**/
import flash.display.BitmapData;
import flash.geom.Matrix;
//Buttons handlers. Should add an extra function because delegate doesn't allow to pass parameters
shaF.onPress = mx.utils.Delegate.create(this,makeShadow);
//Helper functions to pass parameters
function makeShadow() { capture(0) }
/*
create a function that takes a snapshot of the Video object whenever it is called
and shows in different clips
*/
function capture(nr){
this["snapshot"+nr] = new BitmapData(abc._width,abc._height);
//the bitmap object with no transformations applied
this["snapshot"+nr].draw(abc,new Matrix());
var t:MovieClip = createEmptyMovieClip("bitmap_mc"+nr,nr);
//positions clip in correct place
//t._x = 350; t._y = 10+(nr*130); t._xscale = t._yscale = 50
//display the specified bitmap object inside the movie clip
t.attachBitmap(this["snapshot"+nr],1);
output(nr);
//attachMovie("print_but", "bot"+nr, 100+nr, {_x:t._x+t._width+50, _y:t._y+t._height/2})
}
//Create a new bitmapdata, resize it 50 %, pass image data to a server script
// using a LoadVars object (large packet)
function output(nr){
//Here we will copy pixels data
var pixels:Array = new Array()
//Create a new BitmapData
var snap = new BitmapData(this["snapshot"+nr].width, this["snapshot"+nr].height);
//Matrix to scale the new image
myMatrix = new Matrix();
myMatrix.scale(1, 1)
//Copy image
snap.draw(this["snapshot"+nr], myMatrix);
var w:Number = snap.width, tmp
var h:Number = snap.height
//Build pixels array
for(var a=0; a<=w; a++){
for(var b=0; b<=h; b++){
tmp = snap.getPixel32(a, b).toString(16)
//if(tmp == "-fcffff")
//{
//tmp="-ff0000";
//}
pixels.push(tmp.substr(1))
}
}
//Create the LoadVars object and pass data to PHP script
var output:LoadVars = new LoadVars()
output.img = pixels.toString()
output.height = h
output.width = w
//The page (and this movie itself) should be in a server to work
output.send("show.php", "output", "POST")
}
stop()
Since you already have the BitmapData, this is fairly easy. Modifying your output function:
//Copy image
snap.draw(this["snapshot"+nr], myMatrix);
//Now check if we want to save as JPG instead of sending data to the server
if (runningFromCdrom) {
var encoder:JPEGEncoder = new JPEGEncoder();
var bytes:ByteArray = encoder.encode(snap);
var file:FileReference = new FileReference();
file.save(bytes);
} else {
// ...the rest of your output method...
}
How to determine the runningFromCdrom value is up to you. If the SWF is being run inside an HTML document, the best way to tell if the program is being run from a CD-ROM would be to specify it in the FlashVars.
Yes, you can save JPEG's directly from Flash. There is no need for the intermediate step to PHP.
You can use one of these JPEG encoders:
https://github.com/mikechambers/as3corelib
http://www.switchonthecode.com/tutorials/flex-tutorial-an-asynchronous-jpeg-encoder
I would recommend the second as it can work asynchronously (kind of) which means your UI shouldn't lock up while encoding the JPEG.