My question is straightforward.
I have some ClickListeners added to an Actor. I want to execute a click event on them programmatically.
Something like myActor.performClick();
You can also use:
InputEvent event1 = new InputEvent();
event1.setType(InputEvent.Type.touchDown);
button.fire(event1);
InputEvent event2 = new InputEvent();
event2.setType(InputEvent.Type.touchUp);
button.fire(event2);
This will also show any pressed image change which can be helpful.
I figured out a solution :
public static void performClick(Actor actor) {
Array<EventListener> listeners = actor.getListeners();
for(int i=0;i<listeners.size;i++)
{
if(listeners.get(i) instanceof ClickListener){
((ClickListener)listeners.get(i)).clicked(null, 0, 0);
}
}
}
This method can be called passing the actor on whom click needs to be performed
I do it like this (seems nicer to me):
public void triggerButtonClicked(Button button) {
InputEvent inputEvent = Pools.obtain(InputEvent.class);
inputEvent.reset();
inputEvent.setButton(0);
inputEvent.setRelatedActor(button);
try {
inputEvent.setType(InputEvent.Type.touchDown);
button.fire(inputEvent);
inputEvent.setType(InputEvent.Type.touchUp);
button.fire(inputEvent);
} finally {
Pools.free(inputEvent);
}
}
Related
Let's say I have this very simple function:
function pressingDown(e:TouchEvent):void
{
trace(e.pressure);
}
As you can see, it will trace the pressure of the user's touch, but how do I keep this updated?
For example, the user doesn't move their finger at all and my program needs to detect the pressure of their touch all the time. What Touch Event should I use for this? Does it exist? If it doesn't, what can I do to achieve what I'm asking for, or can I achieve it at all without a 3rd party library/ANE?
I have never used e.pressure before, though I don't know this would work.
But might as well throw out some idea, in case it helps.
Try Event.ENTER_FRAME
package {
public class TouchApp extends MovieClip {
var _currentTouchEvent:TouchEvent;
public function TouchApp()
{
this.addEventListener(TouchEvent.TOUCH_BEGIN, pressingDown);
}
function pressingDown(e:TouchEvent):void
{
_currentTouchEvent = e;
//When touch is down, do this function every frame.
this.addEventListener(Event.ENTER_FRAME, whileBeingTouched);
//Add EventListener to catch "touchEnd" event.
this.stage.addEventListener(TouchEvent.TOUCH_END, onTouchEndHandler);
}
function whileBeingTouched(evt:Event):void
{
//Action to do every frame.
trace(_currentTouchEvent.pressure);
}
function onTouchEndHandler(e:TouchEvent):void
{
if (_currentTouchEvent) _currentTouchEvent = null;
this.removeEventListener(Event.ENTER_FRAME, whileBeingTouched);
this.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEndHandler);
}
}
}
I have this situation where I declare inside my main class a function that looks like this:
public class Main extends MovieClip
{
public static var instance:Main;
public function Main()
{
// constructor code
welcomeScreen();
instance = this;
}
public final function welcomeScreen():void
{
//some code in here
}
public final function startLevelOne():void
{
//some other code here
}
}
In some other class I use this statement to fire a reset:
restart.addEventListener('click', function() {
Main.instance.welcomeScreen();
});
Somehow in another class I try to use the same statement for 'startLevelOne' but it seems it is not working and gives the fallowing error:
1195: Attempted access of inaccessible method startLevelOne through a reference with static type Main.
Any ideas?
UPDATE #1
The class where I try to access the function is in full this one:
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
}
UPDATE #2
I have pasted the full code of the main definition here http://pastebin.com/s6hGv7sT
Also the other class could be found here http://pastebin.com/s6h3Pwbp
UPDATE #3
Even though the problem was solved with a workaround, I still cannot understand where was the problem.
I would recommend to leave the static instance (singleton), and work event-based. Now you make all functions public, which is not desirable. It's not that hard to use custom events. See this is how your Main class could look:
public class Main extends MovieClip
{
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
}
public function handleAddedToStage(event:Event)
{
this.removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
this.showWelcomeScreen();
stage.addEventListener(ScreenEvent.SHOW_WELCOME_SCREEN, handleScreenEvent);
stage.addEventListener(ScreenEvent.SHOW_LEVEL, handleScreenEvent);
}
private function handleScreenEvent(event:ScreenEvent):void
{
switch (event.type)
{
case ScreenEvent.SHOW_WELCOME_SCREEN:
{
this.showWelcomeScreen()
break;
}
case ScreenEvent.SHOW_LEVEL:
{
// event.data contains level number
this.startLevel(event.data);
break;
}
default:
{
trace("Main.handleScreenEvent :: Cannot find event.type '" + event.type + "'.");
break;
}
}
}
private function showWelcomeScreen():void
{
trace("show WelcomeScreen")
//some private code in here
}
private function startLevel(level:int):void
{
trace("start level: " + level)
//some other private code here
}
}
This is how the custom event class should look (ScreenEvent.as). Note it has an optional parameter called data. You can pass any value (objects, numbers, strings etc) into this. To the example as clear as possible, I used one event-class for both actions, you can also choose to make more specific custom events for other actions with more detailed parameters, you would have names like ScreenEvent, LevelEvent, PlayerEvent, GameEvent etc etc..
At the top of the class the (static constant) types are defined. An event should only have getters.
package
{
import flash.events.Event;
public class ScreenEvent extends Event
{
public static const SHOW_WELCOME_SCREEN:String = "ScreenEvent.showWelcomeScreen";
// event.data contains level number
public static const SHOW_LEVEL:String = "ScreenEvent.showLevel";
private var _data:String;
public function ScreenEvent(type:String, data:String):void
{
super(type);
this._data = data;
}
public function get data():String
{
return this._data;
}
override public function clone():Event
{
return new ScreenEvent(this.type, this._data);
}
}
}
.. Anywhere in your code you can dispatch the event to the stage.
// dispatch event to Main (stage). Should show welcome screen in our case
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_WELCOME_SCREEN));
// show level 2
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_LEVEL, 2));
I know, its a bit more code, it looks more difficult at first but if the project grows, it will help a lot. The difference with events is 'this could happen, and when it happens, do this' instead of 'do this here, do that over there'
The advantage is that if you remove the event listener in the Main class, nothing will break (loosely coupled). This makes it easier to maintain, it saves a singleton, and you have the ability to extend the Main class if you want to.
I think you wrote
Main.startLevelOne();
instead of
Main.instance.startLevelOne();
Hmm. Given your code, there is only one serious question - what is PerwollGame? You have there public static var instance:PerwollGame; and you assign it an object of type Main. Perhaps that PerwollGame has a startLevelOne() function with a different signature, that obscures your function in the Main class. Also, the other people who answered you are right as well, you should never use nested functions in your code, really put that listener of yours out from inline declaration.
Judging from your coding style and the error reported, I would assume you did this.
public static function startLevelOne():void
There is a fine line between static methods and instantiated objects.
Also never use nested functions
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', onMyClick )
}
public functiononMyClick (e:Event) {
Main.instance.startLevelOne();
});
}
}
I assume that when you register the listener Main.instance is not already assigned.
Did you try to trace Main instance here?
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
trace(Main.instance); // I assume Main.instance is null
}
what about if you add the listener in another method in LevelBrief like :
public function registerListeners():void{
trace("Main.instance == null? -> " + (Main.instance == null)); //not null here if called later.
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
I'm building a panel of buttons, that are enclosed in Canvas container. For this purpose I created a MyButton class, which is a subclass of UIComponent. MyButton class has 2 other subclasses: MyRadioButton and MyMenuButton, which have another behavior on MouseEvent.MOUSE_DOWN. MyMenuButtoncreates and shows a menu, that I build from XML and it builds ok.
I add listeners in the superclass like this:
this.addEventListener(MouseEvent.CLICK, handleClick);
this.addEventListener(MouseEvent.MOUSE_DOWN, handleMouse);
this.addEventListener(MouseEvent.MOUSE_UP, handleMouse);
It's done at the creation stage.
In my subclasses I override handleMouse handler.
override protected handleMouse(event:MouseEvent) : void
{
// subclass specific handling
}
These button objects are added to canvas container as following:
in class MyButtonsContainer.as:
this.rowChildren.addChild(button);
These buttons draw perfectly and in place. The problem is the behavior:
The event doesn't come to handleClick handler of superclass. And that's the question actually - why can it be?
Thanks in advance
EDIT: It appears that MOUSE_DOWN & MOUSE_UP interfere with CLICK event. When I remove listeners to them I get to click handler.How to cause them live together?
I managed to catch CLICK event as timing difference between MOUSE_DOWN & MOUSE_UP.
EDIT: A short/long explanation: For some reason my listeners for MOUSE_DOWN/MOUSE_UP events were interfering with MouseEvent.CLICK. I was suggested by somebody to give up on listening to MouseEvent.CLICK and instead start a timer in MouseEvent.MOUSE_DOWN and check again the timer in MouseEvent.MOUSE_UP. If the difference less than 0.1 (you can put there another threshold) then it was a click actually.
Now some sample code:
public class MyButton extends UIComponent
{
...
private var _clickTime : Number = 0.;
public function void MyButton()
{
super();
addEventListener(MouseEvent.MOUSE_DOWN, handleMouse);
addEventListener(MouseEvent.MOUSE_UP, handleMouse);
}
protected function checkForClick(event:MouseEvent) : Boolean
{
var down : Boolean = event.type == MouseEvent.MOUSE_DOWN;
if (down)
_clickTime = getTimer();
else {
var diff : Number = getTimer() - _clickTime;
if (diff/1000. < 1.) {
handleClick();
return true;
}
}
return false;
}
protected function handleClick(event:MouseEvent) : void
{
// handle the click here
}
protected function handleMouse(event:MouseEvent) : void
{
checkForClick(event);
...
// take care of your button graphic state
}
DISCLAIMER: This code works for me and good for me and my application needs. If you disagree with this way or have a better way to suggest, please do it in comments. Since this answer answers my own question and this EDIT was added only because I was asked to do so, please don't downvote it if you don't agree with it.
call the superclass method like so
override protected handleMouse(event:MouseEvent) : void
{
super.handleMouse(event);
// subclass specific handling
}
If I'm understanding you correctly, you just need to make sure that in your overriden handlers you end each one with a call to super -
override protected handleMouse(event:MouseEvent):void {
// my logic here for the subclass
trace("blah blah blah");
//now redispatch up to the superclass.
super.handleMouse(event);
}
I'm not 100% sure what you're asking, but I'd override click actions like this..
Base class:
public class MyButton extends UIComponent
{
/**
* Constructor
*/
public function MyButton()
{
// listeners
addEventListener(MouseEvent.CLICK, _click);
// ...other listeners
}
/**
* Called on dispatch of MouseEvent.CLICK
*/
private function _click(e:MouseEvent):void
{
doClick();
}
/**
* Override this method and fill with actions to
* do when this is clicked
*/
protected function doClick():void
{
trace("base class was clicked");
}
}
And the extending class:
public class MyOtherButton extends MyButton
{
/**
* Override doClick
*/
override protected function doClick():void
{
super.doClick();
trace("extending class was clicked");
}
}
After closely inspecting your code:
You've added two different listeners to one function for one, shouldn't these have seperate functions as they are called by contrasting events?
this.addEventListener(MouseEvent.MOUSE_DOWN, handleMouse);
this.addEventListener(MouseEvent.MOUSE_UP, handleMouse);
Also, it seems like you're expecting handleMouse to be fired by a click event judging by the below code, which isn't the case.
override protected handleMouse(event:MouseEvent) : void
{
// subclass specific handling
}
Either that, or you're forgetting to override handleClick as well - which is the method that you're running on a click event. You possibly need to add this code:
override protected handleClick(event:MouseEvent) : void
{
// subclass specific handling for a click
}
I have a JList with an array of strings. Basically it displays a restaurant menu.
right next to the JList i have another JList which is empty. Whenever a user double clicks on a string in the first JList (where the menu is displayed) I want it to show up on the next JList which is right next to it.
how do i do that?
You can try
final JList list = new JList(dataModel);
MouseListener mouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
String selectedItem = (String) list.getSelectedValue();
// add selectedItem to your second list.
DefaultListModel model = (DefaultListModel) list2.getModel();
if(model == null)
{
model = new DefaultListModel();
list2.setModel(model);
}
model.addElement(selectedItem);
}
}
};
list.addMouseListener(mouseListener);
You may also want to do it with the Enter key pressed by adding a KeyListener:
jlist.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if (e.getKeyCode() == KeyEvent.VK_ENTER){
//do what you want to do
}
}
});
I know that this is not for a double click but some people want to do it with the Enter button instead as I wanted to do.
I have done it already in your code in the other question?
[link] I want to add an action listener from one JList to another JList and how can a JList appear with out any text inside?
The only think you must do there is to put it into the #Bala R's if statement doing the check of number of clicks:
if (e.getClickCount() == 2) {
//your code
}
Actually you would be better to use addElement(selectedItem); method, as in the #Bala R's code instead of
add(orderList.getModel().getSize(), selectedItem); in my code. Both add the item to the end but addElement looks nicer and you do not need to retrieve the model's size.
Oi, Boro.
public void addActionListener(final ActionListener al) {
jList.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
al.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "ENTER"));
}
}
});
jList().addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
al.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "ENTER"));
}
}
});
}
I'm looking for a way to add an EventListener which will automatically removes itself after the first time it fires, but I can't figure a way of doing this the way I want to.
I found this function (here) :
public class EventUtil
{
public static function addOnceEventListener(dispatcher:IEventDispatcher,eventType:String,listener:Function):void
{
var f:Function = function(e:Event):void
{
dispatcher.removeEventListener(eventType,f);
listener(e);
}
dispatcher.addEventListener(eventType,f);
}
}
But instead of having to write :
EventUtil.addOnceEventListener( dispatcher, eventType, listener );
I would like to use it the usual way :
dispatcher.addOnceEventListener( eventType, listener );
Has anybody got an idea of how this could be done?
Any help would be greatly apprecitated.
(I know that Robert Penner's Signals can do this, but I can't use them since it would mean a lot of code rewriting that I can't afford for my current project)
I find the cleanest way without using statics or messing up your code with noise is to defining a global function (in a file called removeListenerWhenFired.as) like so:
package your.package
{
import flash.events.Event;
import flash.events.IEventDispatcher;
public function removeListenerWhenFired(callback:Function, useCapture:Boolean = false):Function
{
return function (event:Event):void
{
var eventDispatcher:IEventDispatcher = IEventDispatcher(event.target)
eventDispatcher.removeEventListener(event.type, arguments.callee, useCapture)
callback(event)
}
}
}
Then you can listen for events like so:
import your.package.removeListenerWhenFired
// ... class definition
sprite.addEventListener(MouseEvent.CLICKED,
removeListenerWhenFired(
function (event:MouseEvent):void {
... do something
}
)
)
I've not tried it, but you could just turn the EventUtil static method into a standard method and extend the class in your object.
public class OnceEventDispatcher
{
public function addOnceEventListener(eventType:String,listener:Function):void
{
var f:Function = function(e:Event):void
{
this.removeEventListener(eventType,f);
listener(e);
}
this.addEventListener(eventType,f);
}
}
public class Example extends OnceEventDispatcher
{
}
var ex:Example = new Example();
ex.addOnceEventListener(type, func);
functionadd.addEventListener(COMPLETE,functionremove);
functionremove()
{
runevent();
functionadd.removeEventListener(COMPLETE,functionremove);
}
function runevent()
{
trace('Hello');
}