How would I go about making a print screen run in flash. So when a user has arranged some artwork via a drag and drop flash/app - they click a button to 'Print' and there current design activates a printer?
Is this straight forward?
Thanks
I had a similar project and managed with something like the following example:
//creating a container as main canvas
var artworkContainers:Sprite = new Sprite();
addChild(artworkContainers);
//example adding content
var anyContentIWantToPrint:Sprite = new Sprite();
anyContentIWantToPrint.graphics.beginFill(0xf67821, 1);
anyContentIWantToPrint.graphics.drawRect(0, 0, 100, 100);
anyContentIWantToPrint.graphics.endFill();
artworkContainers.addChild(anyContentIWantToPrint);
var button:Sprite = new Sprite();
button.graphics.beginFill(0xf67821, 1);
button.graphics.drawRect(0, 0, 120, 60);
button.graphics.endFill();
addChild(button);
button.addEventListener(MouseEvent.CLICK, startPrintJobHandler, false, 0, true);
function startPrintJobHandler(event:MouseEvent):void
{
var printJob:PrintJob = new PrintJob();
printJob.start()
var printJobOptions:PrintJobOptions = new PrintJobOptions();
printJobOptions.printAsBitmap = true;
//When 'artworkContainer' will be your artwork canvas, where the user will drag and drop. Replace for the instance name you are using.
printJob.addPage(artworkContainer, null, printJobOptions);
printJob.send();
}
You can check out the PrintJob class.
You use the FlexPrintJob class to print one or more Flex objects, such as a Form or VBox container. For each object that you specify, Flex prints the object and all objects that it contains. The objects can be all or part of the displayed interface, or they can be components that format data specifically for printing. The FlexPrintJob class lets you scale the output to fit the page, and automatically uses multiple pages to print an object that does not fit on a single page.
You use the FlexPrintJob class to print a dynamically rendered
document that you format specifically for printing. This capability is
especially useful for rendering and printing such information as
receipts, itineraries, and other displays that contain external
dynamic content, such as database content and dynamic text.
You often use the FlexPrintJob class within an event listener. For
example, you can use a Button control with an event listener that
prints some or all of the application.
Note: The FlexPrintJob class causes the operating system to display a
Print dialog box. You cannot print without some user action.
Here is an example from Adobe's Live Docs.
private function doPrint():void {
// Create an instance of the FlexPrintJob class.
var printJob:FlexPrintJob = new FlexPrintJob();
// Start the print job.
if (printJob.start() != true) return;
// Add the object to print. Do not scale it.
printJob.addObject(myDataGrid, FlexPrintJobScaleType.NONE);
// Send the job to the printer.
printJob.send();
}
You probably want to look at the PrintJob functionality. You can add and arrange pages, etc. Examples on the Adobe help page.
Related
I've created a series of classes that can be used to generate and render images. I want to store a copy of the last frame displayed so I can mix it with the current frame to create a video sustain effect. A brief overview of the classes involved in this example:
MasterContainer: a subclass of Sprite used as the main display object. Generative classes are placed in the MasterContainer, and redrawn when the container is told to render
CustomWave: a subclass of Shape used to contain, draw, and manipulate a GraphicsPath object. One of the aforementioned 'generative classes'
My current attempt involves the use of two MasterContainer objects - one for the current frame, and one for the last frame. If I'm not mistaken, the current appearance of one MasterContainer (and its children) can be copied to the other with a command like lastMaster.graphics.copyFrom(master.graphics);. Consider the following code:
var time:Number;
var master:MasterContainer = new MasterContainer(); //current frame
var lastMaster:MasterContainer = new MasterContainer(); // last frame
var wave:CustomWave = new CustomWave(new <Number>[0,0,0,0],0xffffff,5); //generator for current frame
master.RegisterComponent(wave); //adds CustomWave and registers with the rendering loop
addChild(lastMaster); //add last frame to stage
addChild(master); //add current frame to stage
addEventListener(Event.ENTER_FRAME, perFrame);
function perFrame(event:Event):void{
time = 0.001 * getTimer();
lastMaster.graphics.copyFrom(master.graphics); //copy previous frame's graphics
UpdatePoints(); //update the path of the CustomWave
UpdateColor(); //update the color of the CustomWave
master.fireRenderCannon(); //redraw objects registered to master
}
This seems to work in theory, but as far as I can tell lastMaster ends up with no visible graphics content even though master renders as expected. I've tried several times to test whether this is the case, and am pretty convinced that that it is, but am newish to AS3 and am concerned I am overlooking something - the code looks like it should work. Does anyone have suggestions on how to test this properly? Are there obvious defects within this code that would cause lastMaster to be visually blank? Is there an better way of accomplishing my goal?
I think I'm in over my head on this... I would love any input. Thanks!
After you copied graphics, what do you try to do with it?
Method copyFrom works as clocks, without any problems. Isn't here logic bug in your code?
function perFrame(event:Event):void{
time = 0.001 * getTimer();
lastMaster.graphics.copyFrom(master.graphics); //Here
//master.graphics.copyFrom(lastMaster.graphics);
UpdatePoints();
UpdateColor();
master.fireRenderCannon();
}
Example of copyFrom, it works fine with any complexity of graphics:
var complex: Shape = new Shape();
adobeExample(complex.graphics);
var test2: Shape = new Shape();
test2.graphics.copyFrom(complex.graphics);
addChild(test2);
private function adobeExample(graphics: Graphics):void{
// define the line style
graphics.lineStyle(2,0x000000);
// define the fill
graphics.beginFill(0x666699);//set the color
// establish a new Vector object for the commands parameter
var star_commands:Vector.<int> = new Vector.<int>();
// use the Vector array push() method to add moveTo() and lineTo() values
// 1 moveTo command followed by 3 lineTo commands
star_commands.push(1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2);
// establish a new Vector object for the data parameter
var star_coord:Vector.<Number> = new Vector.<Number>();
// use the Vector array push() method to add a set of coordinate pairs
star_coord.push(0,0, 75,50, 100,0, 125,50, 200,0, 150,75, 200,100, 150,125, 200,200, 125,150, 100,200, 75,150, 0,200, 50,125, 0,100, 50,75, 0,0);
graphics.drawPath(star_commands, star_coord);
}
After the comments made by Bennet and Nicolas, it became obvious that my requirements were (nearly) impossible without a fair amount of redesign. The changes made are as follows:
Generators are no longer DisplayObjects. They are only used to calculate vectors containing the IGraphicsData objects necessary to draw the generated graphic with the drawGraphicsData method.
MasterContainer is now a shape subclass that retrieves the Vector.<IGraphicsData> from each registered generator in order to draw the output.
A bitmap subclass is used to render the contents of the MasterContainer, combining it with a color-dampened version of the previous frame.
An abridged version of the bitmap subclass:
private var constantSustain:Number;
private var linearSustain:Number;
private var sustain:ColorTransform;
private var lastFrame:BitmapData;
public function BitmapManipulator(constantSustain:Number = 0.998, linearSustain:Number = 0.98) {
this.constantSustain = Math.min(Math.max(constantSustain, 0), 1);
this.linearSustain = Math.min(Math.max(linearSustain, 0), 1);
this.UpdateSustain();
this.addEventListener(Event.ADDED_TO_STAGE, OnAddedToStage)
}
private function UpdateSustain():void {
var constantRelease:Number = 255 * (this.constantSustain - 1);
this.sustain = new ColorTransform(this.linearSustain, this.linearSustain, this.linearSustain, 1,
constantRelease, constantRelease, constantRelease, 0);
}
private function OnAddedToStage(event:Event) {
this.lastFrame = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0);
}
public function DrawFrame(container:MasterContainer):void {
this.lastFrame.draw(container);
this.bitmapData = lastFrame;
this.lastFrame = this.bitmapData
this.lastFrame.colorTransform(getBounds(this), this.sustain);
}
...and finally the results #60fps when using an indigo sine wave of shifting phase as the input for the CustomWave:
Currently I have an intro screen to my flash file which has two objects.
A button which will load an external flash file using:
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("flashgame.swf");
The second thing is a Numeric Stepper, which will be from 1 to 10. If the user selects a number e.g. 3 then the game speed I have set in the flashgame.swf should be changed
Such as:
var gameSpeed:uint = 10 * numericStepper.value;
But I think my problem is coming into place because the stepper and gamespeed are from different files.
Anyone got any idea please?
I have also tried creating a stepper in the game file and used this code:
var gameLevel:NumericStepper = new NumericStepper();
gameLevel.maximum = 10;
gameLevel.minimum = 1;
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
For some reason the stepper just flashes on the stage, no errors come up and the game doesn't work
When you execute you code, the stepper has no chance to wait for user input.
There is no time between theese two instructions.
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
You should wait for user input in your NumericStepper, and then, on user event, set the game speed.
Edit: Yeah I know it's kinda sad to type out all this code (especially since some people wouldn't even be grateful enough to say thanks) but I think this question is important enough to justify the code as it may be helpful to others in future also.
Hi,
You were close. In your game file you could have put a var _setgameSpeed and then from Intro you could adjust it by flashgame._setgameSpeed = gameSpeed; It's a bit more complicated though since you also have to setup a reference to flashgame in the first place. Let me explain...
Ideally you want to put all your code in one place (an .as file would be best but...) if you would rather use timeline then you should create a new empty layer called "actions" and put all your code in the first frame of that.
Also change your button to a movieClip type and remove any code within it since everything will be controlled by the code in "actions" layer. In the example I have that movieclip on the stage with instance name of "btn_load_SWF"
Intro.swf (Parent SWF file)
var my_Game_Swf:MovieClip; //reference name when accessing "flashgame.swf"
var _SWF_is_loaded:Boolean = false; //initial value
var set_gameSpeed:int; //temp value holder for speed
var swf_loader:Loader = new Loader();
btn_load_SWF.buttonMode = true; //instance name of movieclip used as "load" button
btn_load_SWF.addEventListener(MouseEvent.CLICK, load_Game_SWF);
function load_Game_SWF (event:MouseEvent) : void
{
//set_gameSpeed = 10 * numericStepper.value;
set_gameSpeed = 100; //manual set cos I dont have the above numericStepper
if ( _SWF_is_loaded == true)
{
stage.removeChild(swf_loader);
swf_loader.load ( new URLRequest ("flashgame.swf") );
}
else
{ swf_loader.load ( new URLRequest ("flashgame.swf") ); }
swf_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, Game_SWF_ready);
}
function Game_SWF_ready (evt:Event) : void
{
swf_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, Game_SWF_ready);
//Treat the Loader contents (flashgame.swf) as a MovieClip named "my_Game_Swf"
my_Game_Swf = swf_loader.content as MovieClip;
my_Game_Swf.gameSpeed = set_gameSpeed; //update gameSpeed variable in flashgame.swf
//also adjust SWF placement (.x and .y positions etc) here if necessary
stage.addChild(my_Game_Swf);
_SWF_is_loaded = true;
}
Now in you flashgame file make sure the there's also an actions layers and put in code like this below then compile it first before debugging the Intro/Parent file. When your Intro loads the flashgame.swf it should load an swf that already has the code below compiled.
flashgame.swf
var gameSpeed:int;
gameSpeed = 0; //initial value & will be changed by parent
addEventListener(Event.ADDED_TO_STAGE, onAdded_toStage);
function onAdded_toStage (e:Event):void
{
trace("trace gameSpeed is.." + String(gameSpeed)); //confirm speed in Debugger
//*** Example usage ***
var my_shape:Shape = new Shape();
my_shape.graphics.lineStyle(5, 0xFF0000, 5);
my_shape.graphics.moveTo(10, 50);
my_shape.graphics.lineTo(gameSpeed * 10, 50); //this line length is affected by gameSpeed as set in parent SWF
addChild(my_shape);
}
The key line in intro.swf is this: my_Game_Swf.gameSpeed = set_gameSpeed; as it updates a variable in flashgame.swf (referred as my_Game_Swf) with an amount that is taken from a variable in the Parent SWF.
This is just one way you can access information between two separate SWF files. Hope it helps out.
I have a class assignment where I have to create a photo gallery and one of the stipulations is that the images need to be loaded from an external source. The reference code from our assignment was:
var myRequest:URLRequest = new URLRequest("bw1.jpg");
myLoader.load(myRequest);
addChild(myLoader);
My specific needs requires me to have up to 2 copies of the images on the screen at once, one as a thumbnail and a second as a fullsized image. I want it so that when a user clicks a thumbnail a new instance of the picture is created scaled to fullsize with 0 alpha and the current selected picture decreases in alpha as the new pic increases in alpha. Once the old pic is no longer visible it is removed from the stage.
I am having trouble figuring out how to create a copy of the image in actionscript and also my for loop seems to not be executing properly as it only ever goes through one iteration even when I have no error messages.
Here is a link to my code via pastebin: http://pastebin.com/iadgKgsk but to save you from having to switch back and forth between I will also past it here
import flash.display.Bitmap;
//creates a loader for each picture to be loaded, I know I could have an empty array
that I add to but created a full array to test.
var loaders:Array = [new Loader(),new Loader(), new Loader(), new Loader(), new
Loader(), new Loader(), new Loader(), new Loader(), new Loader(), new Loader()];
//stores the url request for each image to be loaded
var Requests:Array =[new URLRequest("pic1.jpg"),new URLRequest("pic2.jpg"),new
URLRequest("pic3.jpg"),
new URLRequest("pic4.jpg"),new URLRequest("pic5.jpg"),new URLRequest("pic6.jpg"), new
URLRequest("pic7.jpg"),
new URLRequest("pic8.jpg"), new URLRequest("pic9.jpg"),new URLRequest("pic10.jpg")];
//creates 2 empty arrays one to store the thumbnail sized pics the other fullsized.
Ideally I want one Array holding the bitmap data and the other holding the thumbnail
instances since I only need 2
// fullsized images at a time I can just create a new one and erase the old one in a
single function.
var pics:Array = new Array();
var pics2:Array = new Array();
//defines an empty bitMap variable as a placeholder for which to copy from redefined in
every iteration of the loop
var test:Bitmap;
//loops through every loader
for (var i in loaders);
{
// loads the loader and url request and creates a picture
loaders[i].load(Requests[i]);
//waits for the pic to load
loaders[i].contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
//after loader is loaded create pic from the data
function loadComplete(evt:Event):void
{
var i = "Test";
trace(i);
test= evt.target.content as Bitmap;
pics2[i] = test;
pics[i] =new Bitmap(test.bitmapData);
pics2[i] =new Bitmap(test.bitmapData);
//creates an image on the stage at runtime to help debug
var pic1 = new Bitmap(test.bitmapData);
addChild(pics[i])
pic1.scaleX = 0.138427734375;
pic1.scaleY = 0.1384114583333333;
pic1.x = 204;
pic1.y = 20.6;
pic1.alpha = .25;
var pic2:Bitmap = new Bitmap(test.bitmapData);
pic2.x =100;
pic2.y =100;
pic2.scaleX =.33;
pic2.scaleY=.33;
addChild(pic2);
loaders[i].contentLoaderInfo.removeEventListener(Event.COMPLETE,
loadComplete)
}
}
Your for loop is setup in a way that it would attempt to iterate for each property of the loaders instance which isn't what you want. You may want to investigate other AS3 bulk loader options too there are already some scripts out there to help take care of this.
Your loop should look like
for(var i=0; i<loaders.length; i++)
{
var curLoader = loaders[i].load(Requests[i]);
You can also see an example I put together that loads a bunch of images flipbook style animation (images generated with blender):
http://www.shaunhusain.com/DrawTextRandomly/
http://www.shaunhusain.com/DrawTextRandomly/srcview/
look in the utils.imageLoader package, I made two classes there that deal with loading the images, since they were output from Blender with sequential file names I just used some loops to load the images based on a numeric counter, in your case you could switch it to use a source array of images to load.
In the BatchImageLoader class I have a variable for how many loaders to allow it to make, I wanted to see the difference in performance in terms of memory vs load time (will depend on runtime environment too but I wanted to get a general idea, ended with leaving it at using 90 loaders at most).
Ok so i'm trying to display multiple instance of an object square(movie clip) on different location on screen.
var k1=0,k=0,p=0;
for (k1=0;k1<5;k1++)
{
drawrect(k,p);
k=k+101;
}
This above code is for number of times i want to display the object om screen horizontally in line.
import flash.display.MovieClip;
function drawrect(x1:Number,y1:Number){
// statements here
trace("Hello world!");
var MC_squre:MovieClip= new MovieClip();
MC_squre.x=x1;
MC_squre.y=y1;
addChild(MC_squre);
};
this Function is trying to declare instance of movieclip SQUARE and place it at given parameter in function.i might want to make it and array of the instance later too.i tried this code with just
var square:Sprite = new Sprite();
addChild(square);
square.graphics.lineStyle(3,0x000000);
square.graphics.beginFill(0x0000FF);
square.graphics.drawRect(0,0,100,100);
square.graphics.endFill();
and it worked but i want to now use it by library object not just on drawn shapes.
What you have to do is to make your object in the library accessible by actionscript.
To do that, go into the properties of that Clip, click on "Advanced", and check the box "Export for Actionscript".
When pressing "Ok", you will get a warning that such a class does not exist and it will be automatically generated. That is ok.
Whatever you put as a classname in the Properties, you then have to use to instanciate your objects. If it is for example MySquare, use that.
So your above code would look like this:
function drawrect(x1:Number,y1:Number){
// statements here
trace("Hello world!");
var MC_squre:MovieClip= new MySquare();
MC_squre.x=x1;
MC_squre.y=y1;
addChild(MC_squre);
};
I am trying to build a portfolio application similar to the used by Whitevoid. I am using Flex 4 and Papervision3D 2. I have everything working except for one issue. When I try to load an external SWF as a material on one of the planes, I can see any native Flex or Flash components in their correct positions, but the papervision objects are not being rendered properly. It looks like the viewport is not being set in the nested swf. I have posted my code for loading the swf below.
private function loadMovie(path:String=""):void
{
loader = new Loader();
request = new URLRequest(path);
loader.contentLoaderInfo.addEventListener(Event.INIT, addMaterial);
loader.load(request);
}
private function addMaterial(e:Event):void
{
movie = new MovieClip();
movie.addChild(e.target.content);
var width:Number = 0;
var height:Number = 0;
width = loader.contentLoaderInfo.width;
height = loader.contentLoaderInfo.height;
//calculate the aspect ratio of the swf
var matAR:Number = width/height;
if (matAR > aspectRatio)
{
plane.scaleY = aspectRatio / matAR;
}
else if (matAR < aspectRatio)
{
plane.scaleX = matAR / aspectRatio;
}
var mat:MovieMaterial = new MovieMaterial(movie, false, true, false, new Rectangle(0, 0, width, height));
mat.interactive = true;
mat.smooth = true;
plane.material = mat;
}
Below I have posted two pictures. The first is a shot of the application running by itself. The second is the application as a MovieMaterial on a Plane. You can see how the button created as a spark object in the mxml stays in the correct position, but papervision sphere (which is rotating) is in the wrong location. Is there something I am missing here?
Man. I haven't seen that site in a while. Still one of the cooler PV projects...
What do you mean by:
I cannot properly see the scene rendered in Papervision
You say you can see the components in their appropriate positions, as in: you have a plane with what looks like the intended file loading up? But I'm guessing that you can't interact with it.
As far as I know, and I've spent a reasonable amount of time trying to make something similar work, the MovieMaterial (which I assume you're using) draws a Bitmap of whatever contents exist in your MovieClip, and if you set it to animated=true, then it will render out a series of bitmaps - equating animation. What it's not doing, is displaying an actual MovieClip (or SWF) on the plane. So you may see your components, but this is how:
MovieMaterial.as line 137
// ______________________________________________________________________ CREATE BITMAP
/**
*
* #param asset
* #return
*/
protected function createBitmapFromSprite( asset:DisplayObject ):BitmapData
{
// Set the new movie reference
movie = asset;
// initialize the bitmap since it's new
initBitmap( movie );
// Draw
drawBitmap();
// Call super.createBitmap to centralize the bitmap specific code.
// Here only MovieClip specific code, all bitmap code (maxUVs, AUTO_MIP_MAP, correctBitmap) in BitmapMaterial.
bitmap = super.createBitmap( bitmap );
return bitmap;
}
Note in the WhiteVoid you never actually interact with a movie until it "lands" = he's very likely swapping in a Movie on top of the bitmap textured plane.
The part that you are interacting with is probably another plane that holds the "button" that simply becomes visible on mouseover.
I think PV1.0 had access to real swfs as a material but this changed in 2.0. Sadly. Hopefully Molehill will.
cheers