Actionscript components events - actionscript

I have a project where I am trying to use multiple components in an ActionScript. I have a numeric stepper and text input and a couple buttons. The trouble is the events they dispatch in these components are similar (eg the "click" event), and I am getting a mishmash of scope problems trying to handle this. What I did was create a function in my .as file that had a switch statement to catch multiple "click" events, but for some reason the numeric stepper still is not playing well with the others and keeps setting the instance value to "undefined", probably because there is a scope issue.
Anyway here is a portion of the code that I think is where there is trouble.
(vars: plus_Btn and minus_Btn are button objects, they increment/decrement a private variable by adding or subtracting the value on the numeric stepper which is called stepSize_NS.)
stepSize_NS.addEventListener("click", this);
plus_Btn.addEventListener("click", this);
minus_Btn.addEventListener("click", this);
function click(evt:Object):Void{
switch (evt.target){
case minus_Btn:
command -= stepSize_NS.value;
break;
case plus_Btn:
command += stepSize_NS.value;
break;
case stepSize_NS:
trace("Step Size changed to " + stepSize_NS.value);
//eventually this will do something else whenever the stepper chngs
break;
default:
break;
}//end switch
}//end function

Related

How to get te text of a textfield from inside a function?

I want to make an app that has 2 textfields, 4 buttons and a Text view. 1 button that clears the content of the first textfield and another button that inputs the current time rounded to the nearest 4 and the Text view to display the total time in minutes. Same with the other textfield. It's an app to calculate the total time spent on something in minutes.
I also want to limit the amount of possible insertable characters to 5 as a time has a maximum of 5 characters as in "15:00". I have been able to make an observable object:
class TextFieldManager: ObservableObject {
let characterLimit = 5
#Published var userInput = "" {
didSet {
// Limit the max length of the field
if userInput.count > characterLimit {
userInput = String(userInput.prefix(characterLimit))
} else if userInput.count >= 4 {
// call the setTotalTime func or something to set totalTime
}
}
}
}
which works really well.
I am also able to clear the textfield and set the current time rounded to the nearest 5, but i am unable to limit the characters to 5 AND have the buttons do something at the same time.
So right now it's either being able to:
- Limit characters to a maximum of 5
OR being able to:
clear textfield with a button
input time now rounded to nearest 5 into textfield with a button.
If i go with the observable object method, when i have this above the body block of my ContentView:
#ObservedObject var startTimeManager = TextFieldManager()
#ObservedObject var endTimeManager = TextFieldManager()
and this inside the body for the textfields:
TextField("hh:mm", text: $startTimeManager.userInput)
TextField("hh:mm", text: $endTimeManager.userInput)
and the TextFieldManager class as shown above, than now i don't know how to get the value of the Textfield anymore.
If inside the input the current time button i try to set the time by doing
$startTimeManager.userInput = "whatever the current time is"
i get an error saying that i can't change the value of a binding<String> type something something. Likewise i also can't clear the textfield in the same way.
Also i would like to call a function inside this part:
} else if userInput.count >= characterLimit {
// call the setTotalTime func or something to set totalTime
}
I have a Functions.swift file where both the TextFieldManager class is and my function that i want to call, but if i try to call a function inside here, it says that the function doesn't exist? And inside the function i again would like to have access to the textfield values at the time of the call, but i don't know how to read the value of the textfields from inside the function.
I hope i am making sense and that someone is able to help me, or point me in the right direction. I made the same app for android (android studio), windows (python3) and Mac (python3), but this iphone and Xcode thing really doesn't want to work. I have watched a bunch of tutorial videos and guides, but none are trying to do what i am trying to do. Like i said i can get either to work, but never together and in both cases i am unable to somehow access the textfield values inside the function. I feel like i should be so close, but something is not coming together for me in my head.
Also while i'm at it, in Python 3 to catch all errors and let them pass silently i can do:
Try:
break_my_stuff = int("Break my stuff)"
ignore_some_more_stuff = int("ignore some more stuff)"
etc.
etc.
except Exception:
# catch silently and do nothing
pass
Is there something similar in swift, because
do {
breakMyStuff = whatever might make something break in swift
ignoreSomeMoreStuff = whatever might make something break in swift
etc.
etc.
} catch {
// do nothing and pass silently
}
doesn't work because it needs something to try and i wasn't able to try a complete section like i can with Python.
If inside the input the current time button i try to set the time by doing
$startTimeManager.userInput = "whatever the current time is"
you don't need binding in this case, just assign property in regular way
self.startTimeManager.userInput = "whatever the current time is"

Increment +1 cells with True value

I'm trying to take a set of names with check boxes next to them and make a system so that you can check some of the names (mark them as "True") and click a button. It would then increment +1 the value next to the names of the people marked true.
Here is a link to a sample sheet:
https://docs.google.com/spreadsheets/d/1gf-BrXXR0cAYCn7bMkvvK65R290NXbP9D6aA68c06C8/edit?usp=sharing
If column A, row 2 (Tim's row) is marked true, I want to increment the value in column C, row 2 by one, so Tim would have a running total of tardies next to his name.
I hope this is do-able. Thanks!
(Now I know what you're trying to get)
In order to increment a value via the press of a button, as far as I know you have to use scripts (Tools -> Script Editor). Here's something I threw together:
// editCell takes the cell to edit and it's new value
function editCell(cellName, value) {
SpreadsheetApp.getActiveSheet().getRange(cellName).setValue(value);
}
// getCell takes the cell's value and returns it
function getCell(cellName) {
return SpreadsheetApp.getActiveSheet().getRange(cellName).getValue();
}
// plusOne adds one to the field supplied. It's linked to the button in the sheet
function plusOne() {
editCell("C2",getCell("C2")+1);
}
In order to make it work, you may need to change the targeted Cell (currently C2). You'll also need to create a drawing (Insert -> Drawing) which will act as the button you'll be able to press. Once inserted, click on the three dots on it and click on Link Script. Type in plusOne. When executing it the first time, it'll ask you to authenticate the use of scripts.
That should do the trick. I hope you have some understanding of Java Script though (to modify the code to your needs optimally).
Edit - Expandable version
So, to make every number behind a ticked field increase by one, you can use this version of the code:
// Adds one to every field within "AddArea" that has a tick in front of it. It's linked to the button in the sheet.
function plusOne() {
var ss = SpreadsheetApp.getActiveSheet();
var range = ss.getRange("AddArea");
var values = range.getValues();
var newValues = [];
for (var i = 0; i < range.getNumRows(); ++i) {
var row = values[i];
if(row[0]) {
newValues.push([true, row[1]+1]);
}
else {
newValues.push([false, row[1]]);
}
}
range.setValues(newValues);
}
You need to define a custom named area, named "AddArea" (Data -> Labeled Areas [or similar]), link the script to a button and allow the script to be run. This was hard but very fun to figure out.
Example Sheet for reference (updated)
Can be achieved with just, for example for C2:
=A2+C2
but you would need to turn on iterative calculation (File > Spreadsheet settings... > Calculation [Max. 1 is adequate]) and I would not really recommend that over a trigger with Google Apps Script.

Setting Button action from XML

I have buttons who's action function changes based on a certain configuration XML. I'm looking to change the button action based on the XML.
Example, I will parse this XML node and finally should be able to set the target as doLoginSecure for the button loginButton. The doLoginSecure method action be already defined in the iOS code.
<button name="loginButton" target="doLoginSecure">
How do I do this ?
[someButton addTarget:self action:NSSelectorFromString(#"yourMethod") forControlEvents:UIControlEventTouchUpInside];
replace yourMethod string with XML value
I would suggest,
Instead of assigning target to button as per xml why not you write one function which will be assigned to that button and in that use switch case which will be execute as per the xml response.
Let say, you have loginbutton, so from xml you will be getting two function like fun1 or fun2.
Assign fun fucntion at start to loginbutton.
While parsing xml response set sone variable as 1 or 2 depending on the fucntion
say if fucntionname it fun1 then it is 1 and if it is fun2 then 2.
Now in fun,
-(void)fun:(int)icheck
{
switch(iCheck)
{
case 1:fun1();
break;
case 2:fun2();
break;
//......and like this
}
}

Simulating mouse events in Actionscript 3

Given stage coordinates (x,y), I want to make my flash app behave just as if the user clicked at position (x,y). That is, something like
function simulateClick(x:Number, y:Number):void{
var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, x, y)
stage.dispatchEvent(e);
}
I've found a bunch of pages talking about this kind of thing, and they all give solutions similar to the above. However, this isn't equivalent to the user clicking at (x,y). There are two problems:
The first is that e.stageX and e.stageY are both 0. I can't set them directly. The documentation says they are calculated when e.localX and e.localY are set, but this isn't happening when I set e.localX before dispatchEvent, nor in the event listener.
I could rewrite all of my event listeners with something like this:
var p:Point = e.target.localToGlobal(new Point(e.localX, e.localY));
Is this the only option?
The second problem is that my event listeners are registered with children of stage, not stage itself. So I need to find out what target to call dispatchEvent on. Clearly Flash is capable of determining what the target should be, ie which object owns the topmost pixel visible at position (x,y), because it does so when the user actually clicks. Is there an easy way to get at this information, or should I just write my own recursive function to do the same thing? I'm using DisplayObjectContainer.getObjectsUnderPoint at the moment, but it's not quite right.
I'm writing in FlashDevelop, if that makes any difference.
e.stageX/Y is populated correctly for me... also getObjectsUnderPoint() seems to work fine. I'm assuming that the x/y values passed to simulateClick are global coordinates?
edit: as pointed out in the comments, the mouse event must be dispatched on InteractiveObject instances... modified the code accordingly.
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
public function simulateClick(x:Number, y:Number):void
{
var objects:Array = stage.getObjectsUnderPoint(new Point(x, y));
var target:DisplayObject;
while(target = objects.pop())
{
if(target is InteractiveObject)
{
break;
}
}
if(target !== null)
{
var local:Point = target.globalToLocal(new Point(x, y));
var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, local.x, local.y);
target.dispatchEvent(e);
}
}
public function addedToStage():void
{
var parent:Sprite = new Sprite();
stage.addChild(parent);
var child:Sprite = new Sprite();
child.name = 'child 1';
child.graphics.beginFill(0xff0000, 1);
child.graphics.drawRect(0, 0, 200, 200);
child.graphics.endFill();
var child2:Sprite = new Sprite();
child2.name = 'child 2';
child2.graphics.beginFill(0xff00ff, 1);
child2.graphics.drawRect(0, 0, 100, 100);
child2.graphics.endFill();
child2.x = 150;
child2.y = 150;
var bmpData:BitmapData = new BitmapData(80, 80, false, 0x00ff00);
var bmp:Bitmap = new Bitmap(bmpData);
bmp.name = 'bitmap';
child2.addChild(bmp);
parent.addChild(child);
parent.addChild(child2);
child2.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void
{
trace('target: ' + e.target.name);
trace('localX: ' + e.localX);
trace('localY: ' + e.localY);
trace('stageX: ' + e.stageX);
trace('stageY: ' + e.stageY);
});
simulateClick(190, 190);
}
Output:
target: child 2
localX: 40
localY: 40
stageX: 190
stageY: 190
For question 1: After you create the MouseEvent (assigning it a local x,y) you should be able to directly reference e.stageX and set it to what you want prior to dispatching the event. It's just a property of the MouseEvent instance.
For #2, currentTarget is always the thing that is topmost under the mouse, while target is the thing that is dispatching the event -- assuming the event is genuinely being dispatched by mouse interaction. In your case, you can set the target to be whatever object you have dispatching the event, and set the currentTarget arbitrarily. The question really is whether this is the most efficient way to deal with what's under the mouse right now; and the answer is, probably not. You'd be a lot better off using a MOUSE_OVER event to keep tabs on what the mouse is over right now, store that as a variable you can use when you want to call this, and don't try to iterate the whole display chain all the time (because Flash natively does that much faster than you can do it in a loop). If you put a mouseOver on the stage, and just check the currentTarget, you'll be getting whatever the topmost item is under the mouse on every frame where it changes.
You should be aware that (to prevent some obvious nasty scripts), certain actions cannot be triggered by mouse events that are generated dynamically by actionscript. These include opening a file reference and going fullscreen.
I have faced this issue too, gave me a bit of a headache.
In my situation I was creating the event, performing a bit of complex computations, but I couldn't retrieve global coordinates even though I had already set local coordinates.
Actually the solution was quite obvious in my case...
Global coordinates are populated only AFTER the event is dispatched, otherwise how can the event know how to translate local to global?
This is another pitfall, on top of not checking for the object used to dispatch event being an InteractiveObject.
I post this because someone else may face this issue due to both pitfalls. A quick answer easy to read.

Bullets Go Only Once forward Action Script 3.0

I am new to Adobe Flash Action Script 3.0 but learning.
Geweer = the guy you are and kogel = bullet
I am having this code:
var geweer; .
stage.addEventListener(KeyboardEvent.KEY_DOWN,beweeg);
function beweeg(event:KeyboardEvent)
{
switch(event.keyCode)
{
case 38:
geweer.y = geweer.y -10;
kogel.y = kogel.y -10;
break;
case 40:
geweer.y = geweer.y +10;
kogel.y = kogel.y +10;
break;
case 32:
kogel.x = kogel.x +20;
break;
}
}
As you see. Case 32. When launched. The bullet will move from position only once(unless I press it multiple times). How can i make it to repeat(Without pressing multiple times)? And do it multiple times, to shoot multiple bullets.
You will have to write a game loop which handles all your logic at a regular time interval. A basic way to do this in actionscript is by subscribing to the ENTER_FRAME event.
Since your programming skills seem limited I suggest you first try to follow several tutorials on the subject you are attempting to program before asking such specific questions here.
A quick search seems to be able to help you. Check out 'PART 2 - Advanced detection' on this page.

Resources