I have a very simple Flex 4 app, the mxml of which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="400" minHeight="300">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
public function Execute(foo:Object):void {
Alert.show("Hello World");
}
]]>
</fx:Script>
</s:Application>
I am compiling this using flex/bin/mxmlc file.mxml.
In another Flex app, I am attempting to load the app above using an SWFLoader, and to run the Execute function. It's code looks similar to:
var swfLoader:SWFLoader = ...;
// on load, run the below
var loadedSM:SystemManager = SystemManager(swfLoader.content);
var loadedApp:Object = loadedSM.application;
loadedApp.Execute(this);
The outer app is loaded just fine by the browser, but when the SWFLoader loads the inner app, the outer app crashes / unloads: the browser window goes white.
In the debug log from Flash Player, this is what I see:
VerifyError: Error #1053: Illegal override of getElementNearestScrollPosition in spark.layouts.HorizontalLayout.
ReferenceError: Error #1065: Variable ImageSkin__embed_mxml_Assets_swf___brokenImage_818059060 is not defined.
ReferenceError: Error #1065: Variable _0c91adc980e321d1cb58dff2b8f06798859d4954576f5b2afe24ac0f6c486f60_flash_display_Sprite is not defined.
Any pointers at all?
Within an application, you use the spark:ModuleLoader to load spark modules or applications (spark:Module or spark:Application). This takes care of the dependencies, as well as, the loading process.
Related
I am attempting to prototype a modular application architecture utilizing the Apache Flex SDK 4.12.1 using Flex Modules. I have the following project structure.
CommonLib flex library. This project contains a single file, IPlugin.as as shown below.
{
import mx.core.IVisualElement;
public interface IPlugIn
{
function get MyPlugin():IVisualElement;
}
}
ModuleProject flex application. This project contains two files. PluginModule.mxml which is the module I want to load and DemoForm.mxml which is the component I want to add to the main application.
// PluginModule.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:local="*"
implements="Interfaces.IPlugIn">
<fx:Script>
<![CDATA[
import mx.core.IVisualElement;
private var _myPlugin:DemoForm = new DemoForm();
protected function button1_clickHandler(event:MouseEvent):void
{
container.addElement(new DemoForm());
}
public function get MyPlugin():IVisualElement
{
if (_myPlugin == null)
_myPlugin = new DemoForm();
return _myPlugin;
}
]]>
</fx:Script>
<s:HGroup>
<s:Button id="btn" label="Add DemoForm" click="button1_clickHandler(event)"/>
<s:VGroup id="container"/>
</s:HGroup>
</s:Module>
// Demoform.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400">
<s:layout>
<s:TileLayout/>
</s:layout>
<s:Button label="Button 1"/>
<s:TextInput/>
</s:Group>
FlexProject flex application project. This contains a single file with the intention of loading the PluginModule and DemoForm.mxml into it's BorderContainer.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.core.IVisualElement;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;
import Interfaces.IPlugIn;
private var moduleInfo:IModuleInfo;
protected function button1_clickHandler(event:MouseEvent):void
{
moduleInfo = ModuleManager.getModule("PluginModule.swf");
moduleInfo.addEventListener(ModuleEvent.READY, renderModule);
moduleInfo.load(null, null, null, this.moduleFactory);
}
private function renderModule(event:ModuleEvent):void
{
var module:Object = moduleInfo.factory.create();
var plugin:IPlugIn = module as IPlugIn;
container.addElement(plugin as IVisualElement); // <-- Works!
container.addElement(plugin.MyPlugin); // <-- Error: Skin cannot be found
}
]]>
</fx:Script>
<mx:VBox>
<s:Button click="button1_clickHandler(event)" label="Add Plugin"/>
<s:BorderContainer id="container">
<s:layout>
<s:VerticalLayout gap="10"/>
</s:layout>
</s:BorderContainer>
</mx:VBox>
</s:Application>
I can add the module directly to the application's container and everything seems to work. The application container will then display the 1 button implemented by PluginModule.mxml. However, when I try to add the Demoform to the application's container via the plugin.MyPlugin method I receive the following error.
Error: Skin for
FlexProject.ApplicationSkin2.containerGrp.contentGroup.VBox5.container.BorderContainerSkin10.Group11.DemoForm13.RadioButton16
cannot be found.
I have tried this with numerous different controls including TextArea, TextInput, and RadioButtons. These all fail with similar errors. It appears that the main application cannot find the skins for these components!
Interestingly, if I instead allow PluginModule.mxml to add the DemoForm.mxml to it's own container it works fine. Though, this is not the behavior that I desire.
Any suggestions as to what might be occurring and how I can address it?
I think your module is omitting required classes and these are not available in the main application either.
If you want the unused classes to be included, using an import on those classes should be sufficient. Make sure you include the import in a class that is being used.
Add the compiler flag "link-report filename" generates a report to see what classes are included.
A colleague found the answer. In the project which will be loading the modules you need to add -keep-all-type-selectors to the compiler options. According to the adobe docs...
-keep-all-type-selectors
Instructs the compiler to keep a style sheet’s type selector in a SWF
file, even if that type (the class) is not used in the application.
This is useful when you have a modular application that loads other
applications. For example, the loading SWF file might define a type
selector for a type used in the loaded (or, target) SWF file. If you
set this option to true when compiling the loading SWF file, then the
target SWF file will have access to that type selector when it is
loaded. If you set this option to false, the compiler will not include
that type selector in the loading SWF file at compile time. As a
result, the styles will not be available to the target SWF file.
This is an advanced option.
I have this App.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Button id="bt" label="click me"/>
</s:Application>
And this test case:
package flexUnitTests
{
import flexunit.framework.Assert;
public class AppTest
{
[Test]
public function testApp():void
{
var app:App = new App();
Assert.assertNotNull(app.bt);
}
}
}
But app.bt is null. I want to access the button :(
Short Answer:
The life cycle methods have not run on app; so no createChildren() method was executed in order to create the child component of bt.
Longer Answer:
Things get slightly more complicated with the main application file, as it there is no higher level Flex component in the display hierarchy. I'm unclear on all specifics, but..
I think the Flex Compiler does some magic to set up this component--and the Flex Framework--that help makes the whole app work. You are, in essence, bypassing that work by creating your own instance of the component.
i'm looking for a possibility to log messages in my flex 4.5 Project. This should cover errormessages in remoteClasses, errorHandler or messages typing by hand.
After reading a lot of webpages, the solution from parslay looks good. i want to switch to this framework anyway.
the benefit is the possibility to configure the logging behavior at runtime. but i don't understand the documentation. perhaps because I'm brandnew in parsley. Also google has no fitting result.
Do you have already did this and it is possible for you to give me a few code snippets.
Thanks a lot
Frank
EDIT:
Because of J_A_X justified criticism, i add my code, because i have partially succeeded.
First we need a config file, because i want to configure the logging behavior in runtime. This is a simple xml-file in the project root.
<?xml version="1.0" encoding="UTF-8"?>
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:log="http://www.spicefactory.org/parsley/flex/logging"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.3/parsley-core.xsd
http://www.spicefactory.org/parsley/flex/logging
http://www.spicefactory.org/parsley/schema/2.3/parsley-logging-flex.xsd"
>
<log:target level="info" type="components.SocketTarget">
</log:target>
</objects>
This is my Application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600"
initialize="onAppInitiallize(event)"
xmlns:parsley="http://www.spicefactory.org/parsley"
>
<fx:Script>
<![CDATA[
import mx.controls.Label;
import mx.events.FlexEvent;
import mx.logging.Log;
import org.spicefactory.lib.logging.LogContext;
import org.spicefactory.parsley.flex.logging.FlexLoggingXmlSupport;
protected function onAppInitiallize(event:FlexEvent):void
{
FlexLoggingXmlSupport.initialize();
LogContext.getLogger(this);
//Log.getLogger("myCat").info("MyInfo");
}
protected function button1_clickHandler():void
{
Log.getLogger(this.toString()).info("myMessage");
Log.getLogger(this.toString()).fatal("myMessage");
}
]]>
</fx:Script>
<fx:Declarations>
<parsley:ContextBuilder>
<parsley:XmlConfig file="config.xml"/>
</parsley:ContextBuilder>
</fx:Declarations>
<s:Button click="button1_clickHandler()" label="SendLogToParsley" />
</s:Application>
At this point, the logging will work in the console of the flex builder, because parsley uses by default the TraceTarget. Now, i want to send my Logfiles to a socket. I wrote a litte rough SocketTarget.
package de.axurit.components
{
import flash.net.Socket;
import mx.logging.AbstractTarget;
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;
public class SocketTarget extends AbstractTarget
{
private var _host:String;
private var _port:int;
private var _socket:Socket;
public function SocketTarget(host:String = "localhost",port:int=8085)
{
_host = host;
_port = port;
_socket = new Socket (host,port);
super();
}
override public function logEvent (event:LogEvent):void
{
trace ("logevent" + event.message);
_socket.writeUTF(event.message + String.fromCharCode(13));
_socket.flush();
}
}
}
In the parsley documentation i can see the comment
The default target type created by this tag is a TraceTarget. You can
explicitly declare other target types:
If i add the type-attribute, i receive a Errormessage "One or more errors in BootstrapProcessor". The same as i received after a typo.
Can you give me some hints, how i can send my logs to a socket destination?
You're creating the socket, but never actually connect it. Plus, if you're going to make a log target, make your class extend trace target and override the log function.
I'm trying to communicate between a flex 4.1 application to a flash action script 2 application using LocalConnection.
flash application
contains a button called btn01 and the following code:
var a:LocalConnection = new LocalConnection();
btn01.onPress = function() {
trace("button clicked");
a.send("abcde","test");
}
you can see here that it sends a test command to the connection named 'abcde'.
flex application
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function init():void {
var a:LocalConnection = new LocalConnection();
a.client=this;
a.connect("abcde");
}
public function test():void {
Alert.show("test");
}
]]>
</fx:Script>
<mx:SWFLoader source="/location/as2-flash-file.swf" />
as you can see, in the flex application i connect to LocalConnection named 'abcde' and i set the client to 'this' which means that all the public functions can be executed from the LocalConnection.
the SWFLoader element loads the as2 flash file.
whenever i click the button i do see the trace message but the function test does not get executed on the flex application. any ideas?
update
both applications sit on the same domain, on the localhost actually so no need for allowDomain usage and both applications are web based.
Documentation says AS2 and AS3 LocalConnections should communicate no problems.
Do you need to look into the allowDomain method? Do you need to put a crossdomain.xml file in place? If you do have swfs on two different domains, pay special attention to the send method documentation, because you you have to add additional info to the send method's connection name.
Are they both browser based applications? I not, look into AIR
I created the LocalConnection variable within the init() scope, so when the function ended the localconnection was destroyed. the solution is just to declare the variable outside of the init function.
public var a:LocalConnection;
private function init():void {
a = new LocalConnection();
a.client=this;
a.connect("abcde");
}
I have imported a swf (not created with Flex, i.e. non-framework) into a Flex application. Once loaded, I would like to access movieclips within that imported swf. Looking at Adobe's docs (http://livedocs.adobe.com/flex/3/html/help.html?content=controls_15.html), it seems straightforward; however, their examples are between a Flex app and an imported swf (created with Flex).
Like their example, I'm trying to use the SystemManager to access the imported swf's content; however, I receive the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::MovieClip#58ca241 to mx.managers.SystemManager.
Is this error occurring because I'm importing a non-framework swf into a framework swf? Thanks in advance for any assistance.
Code:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:SWFLoader source="assets/test.swf" id="loader" creationComplete="swfLoaded()" />
<mx:Script>
<![CDATA[
import mx.managers.SystemManager;
[Bindable]
public var loadedSM:SystemManager;
private function swfLoaded():void
{
loadedSM = SystemManager(loader.content);
}
]]>
</mx:Script>
</mx:Application>
Was test.swf created with an earlier AS version? According to this swfs published for AS 1.0/2.0 runs in a different AS virtual machine than AS 3.
The parent AVM2 SWF file will not have
access to the properties, methods, or
objects of the loaded AVM1Movie
object.
You can access them directly, using their instance names.
private function swfLoaded():void {
var clip1:MovieClip = MovieClip(loader.content.myClip1);
var clip2:MovieClip = MovieClip(loader.content.myClip2);
// ...
}