Can flash.display.Bitmap have events on themself? - actionscript

Is this possible or need I do it anyway else? The problem is that the event is not responding.
[Embed(source="pic1.jpg")]
private var Img1:Class;
var i1:Bitmap = new Img1();
// not working
i1.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) {
t.htmlText = "Click!";
});

As you can see Here, Bitmap is not descendant of InteractiveObject. Only interactive objects can be part of an input processes of Flash.
To do what you want encapsulate the Bitmap with Sprite:
[Embed(source="pic1.jpg")]
private var Img1:Class;
var i1:Bitmap = new Img1();
var s1:Sprite = new Sprite();
s1.addChild(i1);
s1.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) {
t.htmlText = "Click!";
});

Related

Jetpack Compose: UnsupportedOperationException when adding Entries to MPAndroidCharts dynamically

I try to display live data in an MPAndroidChart hosted in an AndroidView.
I get the graph but an UnsupportedOperationException happens when I call addEntry() to update the graph dynamically. Am I doing something wrong?
You find a demo repo in the comments.
#Composable
fun MyLineChart() {
val mainViewModel = viewModel()
val sensorData = mainViewModel.sensorFlow.collectAsState(SensorModel(0F,0F)).value
AndroidView(modifier = Modifier.fillMaxSize(),
factory = { context ->
val lineChart = LineChart(context)
var entries = listOf(Entry(1f,1f))
val dataSet = LineDataSet(entries, "Label").apply { color = Color.Red.toArgb() }
val lineData = LineData(dataSet)
lineChart.data = lineData
lineChart.invalidate()
lineChart
}){
try {
Log.d("TAG", "MyLineChart: Update --- Current thread id: ${Thread.currentThread()}")
it.data.dataSets[0].addEntry(Entry(sensorData.x, sensorData.y))
it.lineData.notifyDataChanged()
it.notifyDataSetChanged()
it.invalidate()
} catch(ex: Exception) {
Log.d("TAG", "MyLineChart: $ex")
}
}
}
The data is sent to the view via the following ViewModel:
#HiltViewModel
class MainViewModel #Inject constructor(#ApplicationContext var appContext: Context) : ViewModel() {
private var rand: Random = Random(1)
val sensorFlow: Flow<SensorModel> = flow<SensorModel> {
while (true) {
delay(1000L)
Log.d("TAG", "sensorFlow: Current thread id: ${Thread.currentThread()}")
emit(SensorModel(rand.nextFloat(), rand.nextFloat()))
}
}
}
You pass entries to LineDataSet, which is an immutable list.
This library seems to have a pretty bad API, because it doesn't ask for a modifiable list as a parameter, but at the same time it doesn't make it modifiable on its side. This causes you to try to modify the immutable list, which leads to an exception.
Replace
var entries = listOf(Entry(1f,1f))
with
val entries = mutableListOf(Entry(1f,1f))
p.s. I can't advise you another graph library as I haven't worked with any, but I would advise you to look for a library with a better API.
try this code:
// it.data.dataSets[0].addEntry(Entry(sensorData.x, sensorData.y))
val entryList = mutableListOf<Entry>()
entryList.add(Entry(sensorData.x, sensorData.y))
val dataSet = LineDataSet(entryList, "Label").apply {
color = Color.Red.toArgb()
}
it.data = LineData(dataSet)

How do I add an AudioWorkletProcessor to work with it in audioWorkletNode in Dart?

In pure JS I can do it:
const audioContext = new AudioContext();
const source = audioContext.createMediaElementSource(new Audio());
await audioContext.audioWorklet.addModule('./my-processor.js');
const processorNode = new AudioWorkletNode(audioContext, 'my-processor');
source.connect(processorNode);
processorNode.connect(audioContext.destination);
In Dart I can not do it:
var audioContext = AudioContext();
var source = audioContext.createMediaElementSource(AudioElement());
audioContext.audioWorklet // The getter 'audioWorklet' isn't defined for the class 'AudioContext'.
var processorNode = AudioWorkletNode(audioContext, 'my-processor');
source.connectNode(processorNode);
processorNode.connectNode(audioContext.destination);
I cannot find the audioWorklet property in the AudioContext class.
I tried unsuccessfully to find in the documentation where else an audioWorklet or addModule could be located.
How do I add an AudioWorkletProcessor to work with it in audioWorkletNode in Dart?
if there isn't a method or property in a JS interop object you can use the dart:js_util:
import 'package:js/js_util.dart' as jsu;
var worklet = jsu.getProperty(audioContext, 'audioWorklet'));
jsu.callMethod(worklet, 'addModule', ['./my-processor.js']));

Remove event listeners from movieclip from main timeline

So, i am adding movieclip objects on to the main timeline programatically.
With-in those movieclips im using a timer event so they will move once added to the stage.
so when my game ends, i want to remove the movieclip objects from the stage, i can do this, but its causing errors because the listeners of the objects are still there.
i cant access the code in the movieclip object timeline from the main timeline to remove the listeners and i dont know how to remove the listener from with-in the movieclip timeline when they are removed!
I hope this makes sense!
Help!
Your MovieClips can listen to Event.REMOVED_FROM_STAGE to programmatically remove all the event listeners you added earlier. Here is some sample code to show how it is done.
// add this code to an ActionScript class that extends Sprite
// call initClips() in the constructor
private var _clipA:MovieClip;
private var _clipB:MovieClip;
private var _clipACount:int;
private var _clipBCount:int;
private function initClips():void
{
// create 2 movieclips and add some common event listeners
_clipA = new MovieClip();
_clipA.addEventListener(Event.ADDED_TO_STAGE, onClipAddedToStage);
_clipA.addEventListener(Event.REMOVED_FROM_STAGE, onClipRemovedFromStage);
_clipA.addEventListener(Event.ENTER_FRAME, onEnterFrameClipA);
_clipB = new MovieClip();
_clipB.addEventListener(Event.ADDED_TO_STAGE, onClipAddedToStage);
_clipB.addEventListener(Event.REMOVED_FROM_STAGE, onClipRemovedFromStage);
_clipB.addEventListener(Event.ENTER_FRAME, onEnterFrameClipB);
_clipACount = 0;
_clipBCount = 0;
addChild(_clipA);
addChild(_clipB);
}
private function onClipAddedToStage(event:Event):void
{
var clip:MovieClip = event.currentTarget as MovieClip;
if(clip == _clipA)
{
// position movieclip to dummy values
clip.x = 40;
clip.y = 40;
}
else if(clip == _clipB)
{
clip.x = 200;
clip.y = 100;
}
}
private function onClipRemovedFromStage(event:Event):void
{
var clip:MovieClip = event.currentTarget as MovieClip;
// good habit to null check in case "as" casting fails
if(clip != null)
{
// remove event listeners for this movieclip instance
clip.removeEventListener(Event.ADDED_TO_STAGE, onClipAddedToStage);
clip.removeEventListener(Event.REMOVED_FROM_STAGE, onClipRemovedFromStage);
// there is no penalty for trying to remove event listeners that were not added to this object instance
clip.removeEventListener(Event.ENTER_FRAME, onEnterFrameClipA);
clip.removeEventListener(Event.ENTER_FRAME, onEnterFrameClipB);
}
}
private function onEnterFrameClipA(event:Event):void
{
_clipACount++;
trace("onEnterFrame for clipA " + _clipACount);
if(_clipACount > 10)
{
// for demonstration purposes
// remove self after a few frames pass
removeChild(_clipA);
}
}
private function onEnterFrameClipB(event:Event):void
{
_clipBCount++;
trace("onEnterFrame for clipB " + _clipBCount);
if(_clipBCount > 20)
{
removeChild(_clipB);
}
}
There are events to receive notification, when a DisplayObject is removed from stage. Just set up listeners for Event.ADDED, Event.ADDED_TO_STAGE, Event.REMOVED and Event.REMOVE_FROM_STAGE to implement a live cycle for the MovieClips. Start stuff when the MovieClips are added. Remove listeners, stop timers etc, when the MovieClips are removed.

Check if textboxes have the same content

I want to check if the textboxes created like this:
(function(arr) {
for (var i = 0; i < arr.length; i++) {
app.add(app.createLabel(arr[i] + " mail"));
app.add(app.createTextBox().setName(arr[i]));
}
})(["first", "second", "third"]);
have the same contents? I was looking for something like getElementByTagname or or getTextboxes, but there are no such functions.
So how to iterate thvrough them and show a label if they are all equal?
To access any widget values you need to add them as a callback element (or a parent panel) to the server handler that will process them. The values of each widget are populated on a parameter passed to the handler function and can be referenced by the widget name (that you already set).
You don't need to setId as suggested on another answer. Unless you want to do something with the widget itself (and not its value). e.g. change its text or hide it, etc.
var textBoxes = ["first", "second", "third"];
function example() {
var app = UiApp.createApplication().setTitle('Test');
var panel = app.createVerticalPanel();
textBoxes.forEach(function(name){
panel.add(app.createLabel(name + " mail"));
panel.add(app.createTextBox().setName(name));
});
panel.add(app.createLabel('Example Label').setId('label').setVisible(false));
var handler = app.createServerHandler('btnHandler').addCallbackElement(panel);
panel.add(app.createButton('Click').addClickHandler(handler));
SpreadsheetApp.getActive().show(app.add(panel));
}
function btnHandler(e) {
var app = UiApp.getActiveApplication(),
allEqual = true;
for( var i = 1; i < textBoxes.length; ++i )
if( e.parameter[textBoxes[i-1]] !== e.parameter[textBoxes[i]] ) {
allEqual = false; break;
}
app.getElementById('label').setVisible(allEqual);
return app;
}
Notice that ServerHandlers do not run instantly, so it may take a few seconds for the label to show or hide after you click the button.
When you create the textboxes, assign each one an id using setId(id).
When you want to obtain their reference later, you can then use getElementById(id).
Here is an example:
function doGet() {
var app = UiApp.createApplication();
app.add(app.createTextBox().setId("tb1").setText("the original text"));
app.add(app.createButton().setText("Change textbox").addClickHandler(app.createServerHandler("myHandler")));
return app;
}
function myHandler() {
var app = UiApp.getActiveApplication();
app.getElementById("tb1").setText("new text: in handler");
return app;
}

Away3D 4.0 Loading dynamic textures for primitives from arrays

I have several arrays storing the attributes needed to build primitives. One array stores the widths, another stores the heights, another the depths, x, y, z etc. I have one more that stores the remote filename for the texture to be applied. After I get my response from the server I attempt to apply the textures to the primitives. When I move the camera to look at the primitive, I am not able to see it. My view seems to freeze up (the view will not update). Once the camera has moved past the primitive, it can see again. Any ideas?
private var loadedBuildingTextures:Object = new Object();
private var map_building_count:Number = 0;
private var loadedBuildings:Number = 0;
public var map_building_widths:Array;
public var map_building_heights:Array;
public var map_building_depths:Array;
public var map_building_xs:Array;
public var map_building_ys:Array;
public var map_building_zs:Array;
public var map_building_textures:Array;
// I POPULATE THE ARRAYS BUT LEFT THAT CODE OUT FOR SIMPLICITY
public function placeBuildings():void {
trace('FUNCTION: placeBuildings() fired');
var buildingsPlaced:Number = 0;
for (var a:Number = 0; a < map_building_count; a++ ) {
loadedBuildingTextures['texture_' + a.toString()] = new BitmapFileMaterial(map_building_textures[a]); // ASSIGNS THE BitmapFileMaterials TO AN OBJECT FOR REFERENCING LATER
loadedBuildingTextures['texture_' + a.toString()].loader.contentLoaderInfo.addEventListener(Event.COMPLETE, postBuildingLoad);
buildingsPlaced++;
}
trace('placed ' + buildingsPlaced.toString() + ' of ' + map_building_count.toString() + ' buildings.'); // OUTPUT = "placed 4 of 4 buildings."
trace('FUNCTION: placeBuildings() completed');
}
public function postBuildingLoad(event : Event):void {
loadedBuildings++;
if (int(loadedBuildings) == int(map_building_count)) {
placeBuildingsStep2();
}
}
public function placeBuildingsStep2():void {
trace('RECEIVED ALL RESPONSES FROM SERVER FOR TEXTURES');
for (var a:Number = 0; a < map_building_count; a++ ) {
cube = new Cube(
loadedBuildingTextures['texture_' + a], // <----- THIS SEEMS TO BE THE PROBLEM
map_building_widths[a], // WIDTH
map_building_heights[a], // HEIGHT
map_building_depths[a], // DEPTH
1, // WIDTH UNITS
1, // HEIGHT UNITS
1, // DEPTH UNITS
true);
cube.x = map_building_xs[a];
cube.y = map_building_ys[a];
cube.z = map_building_zs[a];
view.scene.addChild(cube);
}
}
Although this post is old, it does highlight an important issue. BitmapFileMaterial is more a shortcut to test than a production ready scheme.
I would highly recommend using a loading queue for external assets (like LoaderMax or the new AssetLibrary in 4.0) and then instantiate materials as needed.

Resources