Double clic dans Flash
Par -Alexandre LEGOUT aka LAlex- le mardi, août 16 2005, 18:12 - Liens - Lien permanent
Le fait de pouvoir intercepter un évenement de type double clic a longtemps été demandé pour les boutons Flash. En attendant, je fais comme tout le monde, je me débrouille... et voici comment je fais dans le cadre d'une classe héritant de MovieClip.
class DblClickMovieClip extends MovieClip {
// Interval called if second click is too late
private var _itv:Number;
// Amount of succesive clicks
private var _click:Number = 0;
// onPress event
private function onPress() {
dblClick();
}
// Check if 2 clicks were made in the given timelapse
private function dblClick() {
if (++_click == 2) {
_click = 0;
onDblClick();
} else {
// Double click timelapse can be set here
_itv = setInterval(this, "clickTimeout", 250);
}
}
// Init clicks
private function clickTimeout() {
clearInterval(_itv);
_click = 0;
}
// Called if double click
private function onDblClick() {
trace("Double click");
}
}
Bien évidemment, cette méthode est adaptable si on ne veut pas que tout le clip soit clicable...
Je pensais d'ailleurs implémenter ca par la suite sous forme de décorateur d'un clip...
Il doit y avoir des centaines de méthodes pour arriver au même résultat, alors si quelqu'un en voit une meilleure, qu'il n'hésite pas!
Et pour finir, ne désespérons pas de l'avoir un jour en natif, il ne nous aura fallu que 4 versions pour avoir l'upload de fichiers ! ![]()
Commentaires
tu l'utilises comment après ? en mettant la class sur un symbole de la bibliothèque ?
moi j'ai eu le soucis de vouloir garder le onPress aussi
et en voulant calquer le comportement du double click windows, il ne faut pas que la souris se déplace aussi
neo> Avec le code que je donne oui, il faut lier la classe à un symbole de la bibliothèque... C'est d'ailleurs pour ca que je pense en faire un décorateur ensuite...
Avec un intervalle de 250ms, je trouve que ca se rapproche assez du double clic de Windows, et pour cliquer/déplacer la souris/recliquer en 250ms, il faut quand-même être doué à la souris...
++ ^^
moi j'ai mis 300, mais 250, c'est 1/4 de seconde, c'est pas si court que ca
je l'ai appliqué à une fenêtre, pour reproduire le maximize et tout
et en le testant, le problème du déplacement de souris est venu tout seul
mais c'est vrai que pour une icone, c'est tellement petit qu'on a pas besoin
Comme tu utilises un interval, tu n'as pas besoin de placer un compteur. En terme de logique, tu dois pouvoir utiliser un truc comme ci-dessous (non teste).
class DblClickMovieClip extends MovieClip {// Interval called if second click is too late
private var _itv:Number = -1;
// onPress event
private function onPress() {
dblClick();
}
// Check if 2 clicks were made in the given timelapse
private function dblClick() {
if (_itv != -1) {
killInterval();
onDblClick();
} else {
// Double click timelapse can be set here
_itv = setInterval(this, "doSingleClick", 250);
}
}
// Init clicks
private function killInterval() {
clearInterval(_itv);
_itv = -1;
}
private function doSingleClick() {
killInterval();
onSingleClick();
}
// Called if double click
private function onDblClick() {
trace("Double click");
}
// Called if single click
private function onSingleClick() {
trace("Single click");
}
}
Yop Lalex, les gens,
J'avais implémenter tantôt une classe statique plutôt partant du principe qu'il était peu probable qu'un utilisateur double-click a 2 endroits simultanéement et pour rendre vraiment indépendant la fonctionnalité de double-click.
J'ai pas les sources sur le portable mais ça donnais ça :
DblClickHandler.initialize();
DblClickHandler.setDelay(280); // délai en ms -> par défaut à 250
la méthode initialize lançais un Mouse.addEventListener(_global); s'occuper de créer le setinterval et basculer un flag booléen (DOUBLE_CLICKING) à true si on était dans l'interval d'un double click potentiel, etc en se basant sur onMouseDown.
Côté utilisation ça donnais :
import DblClickHandler;
mybtn.onPress=function(){
trace (DOUBLE_CLICKING ? "Double-click" : "Simple click");
}
Bon je suis pas convaincu que ce soit très OO spririt mais ça m'avais permis de m'en servir rapidement sur des projets en cours sans trop réfléchir...
Ce que je comprend de l'utilisation de ta classe, Lalex, c'est que tu es oblige de l'utiliser comme un composant qui va contenir chaque bouton qui devra implementer le double clic.
Perso, la version en as1 que j'utilise est code sur le meme principe que ce qu'explique Foxy.
L'avantage etait de n'avoir qu'une seul methode rajoute sur la classe Mouse.
Foxy, si tu retrouves tes sources en as2, ca m'interesse.
ah oui, en fait, c'est un double click général
c'est pas bete, j'vais réfléchir sur des cas où ca pourrait poser probleme
parce que bien sûr, il faut trouver un truc qui marche partout
Roikku, j'ai pas les sources sur mon portable, je suis en pseudo vacances, mais je l'ai refaite vite euf :
import mx.utils.Delegate;sur la scène un bouton et :class DblClickHandler{
// Static properties
private static var intervalDelay:Number=250; // Delay
private static var idInterval:Number; // Interval ID
private static var _DOUBLE_CLICKING:Boolean=false; // Flag Dbl-click
private static var _init:Boolean=false; // Init Flag
private static var oListen:Object; // Interval object handler
private static var nbClicks:Number=0; // Clicks
// Intialize
static public function initialize():Void{
if (!_init){
_init=true;
// Just a litle object to handle the interval callback
oListen=_global.__DblClickHandler__={};
oListen.onKillInterval=Delegate.create(DblClickHandler,onKillInterval);
// Mouse listener
Mouse.addListener(DblClickHandler);
}
}
// Change delay
public static function changeDelay(n:Number):Void{
intervalDelay=n>0 ? n : 250;
}
// Getter DOUBLE_CLICKING
static public function get DOUBLE_CLICKING():Boolean{
return _DOUBLE_CLICKING;
}
// OnMouseDown callback
static private function onMouseDown():Void{
// Set Flag
nbClicks++;
_DOUBLE_CLICKING=nbClicks>1;
// Start interval
clearInterval(idInterval);
idInterval=setInterval(oListen,"onKillInterval",intervalDelay);
}
// Interval elapsed
static private function onKillInterval():Void{
// Clear flag & interval & nbClicks
clearInterval(idInterval);
_DOUBLE_CLICKING=false;
nbClicks=0;
}
}
import DblClickHandler;DblClickHandler.initialize();
myButton.onPress=function(){
trace (DblClickHandler.DOUBLE_CLICKING);
}
Hello
et j'ai ajouté 2 événements via un AsBroadcaster onClick et on2Click pour garder un gestionnaire d'événement acceptable 
Foxy >> au dessus pouquoi tu utilises une variable en _global pour gérer le callback ?
Sinon en voyant ce que tu viens de faire je me permets d'adapter un peu ton code pour assurer tout d'abord que l'on est bien un double click et pas un triple ou + si affinité (au cas où l'on serait un peu nerveux sur la gachette)
/* ---------- DoubleClick
dans flash un petit exemple :Name : DoubleClick
Package : eka.src.movieclip
Version : 1.0.0.0
Date : 2005-08-19
Author : ekameleon
URL : <a href="http://www.ekameleon.net" rel="nofollow">http://www.ekameleon.net</a>
Mail : <a href="mailto:contact@ekameleon.net" rel="nofollow">contact@ekameleon.net</a>
THKS : Foxy and Lalex >> <a href="http://blog.lalex.com/comments/200508/280-double-clic-dans-flash.html#comments" rel="nofollow">http://blog.lalex.com/comments/200508/280-double-clic-dans-flash.html#comments</a>
PROPERTIES
DoubleClick.ISDOUBLE [Boolean]
DoubleClick.DELAY [Number] : default 250
METHODS
DoubleClick.INITIALIZE()
DoubleClick.RESET()
EVENTS
onClick : émis lorsque l'utilisateur clique sur le bouton gauche de la souris
on2Click : émis lorsque l'utilisateur doubleclick sur le bouton de la souris
---------- */
class eka.src.movieclip.DoubleClick {
// ----o Author Properties
public static var className:String = "DoubleClick" ;
public static var classPackage:String = "eka.src.movieclip";
public static var version:String = "1.0.0.0";
public static var author:String = "ekameleon";
public static var link:String = "<a href="http://www.ekameleon.net" rel="nofollow">http://www.ekameleon.net</a>" ;
// ----o Constructor
private function DoubleClick() {}
// ----o Static Properties
public static var ISDOUBLE:Boolean ;
static public var broadcastMessage:Function ;
static public var addListener:Function ;
static public var removeListener:Function ;
// ----o Static Methods
static public function INITIALIZE(Void):Void {
RESET() ;
Mouse.addListener(DoubleClick);
}
static private function RESET(Void):Void{
clearInterval(_CPT);
ISDOUBLE = false ;
_CPT = 0 ;
}
// ----o Static Virtual Properties
static public function get DELAY():Number{
return _DELAY ;
}
static public function set DELAY(n:Number):Void {
_DELAY = n > 0 ? n : 0 ;
}
// ----o Static Private Properties
private static var _DELAY:Number = 250 ;
private static var _IDITV:Number ;
private static var _CPT:Number ;
static private var __INITBROADCASTER = AsBroadcaster.initialize(DoubleClick) ;
// ----o Static Private Methods
static private function onMouseDown(Void):Void{
_CPT ++;
ISDOUBLE = _CPT == 2 ;
DoubleClick.broadcastMessage( (_CPT == 2) ? "on2Click" : "onClick" ) ;
clearInterval(_IDITV);
_IDITV = setInterval( RESET , _DELAY) ;
}
}
import eka.src.movieclip.* ;function onClick():Void {
trace ("-------> Simple click") ;
}
function on2Click():Void {
trace ("-------> Double click") ;
}
DoubleClick.INITIALIZE() ;
DoubleClick.addListener(this) ;
mc.onPress = function () {
trace ("## onPress >> " + DoubleClick.ISDOUBLE) ;
}
Merci en tout cas car j'avais pas eu le temps de me pencher sur la chose et voilà qui est fait
Yop eka,
- Le coup de l'objet c'est à cause du setInterval, j'ai pris l'habitude d'utiliser la syntaxe à 3 paramètres pour pas avoir de problème de scope (ou un truc dans ce goût, je m'en rappelle plus), mais là semble rouler.
- Le triple-click, oui, bien vu.
- La méthode RESET, oui mais avec clearInterval(_IDITV);
- Le gestionnaire asbroadcaster sert à quoi ? dans quel cas peux-tu avoir besoin d'intercepter un double-click dans le vent lié à aucune instance de quoique ce soit ?
- Pourquoi des majuscules partout ? C'est atroce à lire !
- Void en paramètre de fonction ça sert presque à rien, aucune erreur à la compilation sera déclenchée , c'est interprété comme un type de retour uniquement par le compilateur. Pour ma part j'utilise une classe _Void avec un constructeur privé vide et signe myFunc(v:_Void) les fonctions ne devant recevoir aucun paramètre.
L'idée de la classe statique me plait pas des masses, je suis sûr que y'a moyen de trouver une idée plus sympa qui dispatch du onDoubleClick sur des instances voulues.
Hello
- L'événement avec le AsBroadcaster peut servir si tu utilises un Controller qui doit gérer des actions lors d'un doubleclick .. pas besoin forcément de faire des doubles clicks sur un bouton ... peut servir pour certaines navigation etc. (exemple : applicatif de dessin avec double click pour désactiver le tracé d"une courbe)
- Les mauscules c'est pour notifier que l'on a à faire à des constantes, notation classique lorsque j'utilise le static en général
- Pour le Void c'est juste une question d'habitude
Disons que là je spécifie au lecteur qu'il ne faut rien envoyer en paramètre et c'est tout
Salut eka,
- Ok pour le broadcaster même si c'est un peu tiré par les cheveux, ça prête à confusion, on a tendance à penser que l'on va pouvoir utiliser DoubleClick.addListener(myButton) pour se servir de onClick et on2Click sur l'instance alors que ça ne sera pas possible. Dans le meilleur des cas, onClick sert pas à grand chose puisque c'est onMouseDown et on on2Click devrait s'appeller onMouseDoubleClick pour faire comprendre que c'est bien une action générale non liée à une instance.
- Ok pour la notation en majuscule concernant les constantes, mais tout ce qui est static n'est pas forcéement constant ( _CPT, _IDITV sont tout sauf constant). En cpp l'utilité des majuscules pour des constantes est surtout d'ordre esthétique car les constantes sont protégées (impossible de modifier leur valeur), en Flash on a pas de mot-clef nous permettant de protéger/instancier les constantes, c'est donc d'autant plus important de se rabattre sur une nomenclature stricte et de bien les différencier de tout ce qui n'est pas constant pour éviter de les modifier dans le code. En mettant absoluement tout en majuscules tu perd tous les avantages des majuscules pour les constantes et rend ton code (surtout dans le cadre de dév de classe statique) relativement imbuvable.
- L' interrêt de void en paramètres et de générer une erreur en cas de forçage à la compilation. Sois tu développes juste pour toi ou pour un exemple simple et niveau lisibilité ça suffira. Mais là t'as l'air de développer un paquetage bien soigné, alors va au bout des choses, et part du principe que les dévs qui utiliseront tes paquetages n'iront pas forcéement matter tes sources.
++
Excusez mon ignorance mais a quoi correspond gt dans la fonction
static public function set DELAY(n:Number):Void {
_DELAY = n > 0 ? n : 0 ;
}
Dans l'aide de flash il dise que c'est "greater than" et que cela a été remplacé dans flash 5 par >
je ne comprend pas, si quelqu'un peut m'éclairer.
Merci d'avance
Chô
tibo > Petit problème d'encodage du caractère > qui, en HTML s'écrit > ... Pareil pour < qui s'écrit <... Pas encore eu le temps de rectifier ca, il faut donc faire les rectifs si tu utilises un copier/coller...
++ ^^
Donc depuis ce matin j'essaye d'utiliser la classe DoubleClick de eka. J'ai crée une classe MainWindow, dans cette classe on a un objet DoubleClick, j'ai une fonction on2Click()
Je crée donc plusieurs fenetre fille de MAinWindow, le probleme c'est que le AsBroadcaster transmet le message a tous les heritier instancié de la classe. Donc si lorsque je double clic sur une fenetre fille elle doit se fermer; du coup elle se ferme toutes.
Si vous voyez une solution ....
(peut etre utilisé du eventdispatcher plutot que du asbroadcaster)
utilises simplement la propriété ISDOUBLE sur le onPress et dans ton cas n'utilise pas l'événement.
(regarde le code au dessus... :))
Récupère à chaque fois que tu fais un onPress sur une fenêtre si tu as fais un double-click ou pas
Comme je l'ai dit au dessus l'événement on2Click est surtout utilisable dans un contexte général.. style fermer plein de fenêtre en même temps ou lancer une action dans l'applicatif sans forcément être lié à une zone réactive précise
Bonjour à tous. Merci pour ces sources fortes utiles, mais elle ne font pas le boulot que je souhaite correctement :/
alors je propose une nouvelle version :
/**Et sur mon clip voici ce que je fais :* Class to intercept a onClick and onDblClick
* @author JR
* @version 0.1
*/
class mx.events.DoubleClick
{
// ----o Static Private Properties
private static var _DELAY:Number = 100;
private static var _OBJET:Object;
// to get delay from interceptor
static public function get DELAY():Number{
return _DELAY ;
}
// to set delay from interceptor
static public function set DELAY(n:Number):Void {
_DELAY = n>0 ? n : 0 ;
}
// Constructor
private function DoubleClick() {}
// intialise les option du double clic et le listener
static public function initialize(obj:Object):Void{
_OBJET = obj;
_OBJET.doubleclickDuration = _DELAY;
_OBJET.lastClick = 0;
_OBJET.pressed = false;
interceptor();
}
// intercept le double clic et renvoie un évènement
static public function interceptor():Void{
/* interceptor event "onEnterFrame" */
_OBJET.onEnterFrame = function(){
if (this.lastClick>0) {
if ((getTimer()- this.lastClick)>this.doubleclickDuration) {
this.lastClick = 0;
if (this.hitTest(_root._xmouse, _root._ymouse, true) && this.pressed)
this.onClick();
}
}
};
_OBJET.onMouseDown = function(){
if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
this.pressed = true;
if (this.lastClick == 0) {
this.lastClick = getTimer();
} else {
this.lastClick = 0;
this.onDblClick();
}
}
};
_OBJET.onMouseUp = function(){
this.pressed = false;
};
}
/* on double click */
public function onDblClick() : Void {}
/* on simple click */
public function onClick() : Void {}
}/**
* Class to intercept a onClick and onDblClick
* @author JR
* @version 0.1
*/
class mx.events.DoubleClick
{
// ----o Static Private Properties
private static var _DELAY:Number = 100;
private static var _OBJET:Object;
// to get delay from interceptor
static public function get DELAY():Number{
return _DELAY ;
}
// to set delay from interceptor
static public function set DELAY(n:Number):Void {
_DELAY = n>0 ? n : 0 ;
}
// Constructor
private function DoubleClick() {}
// intialise les option du double clic et le listener
static public function initialize(obj:Object):Void{
_OBJET = obj;
_OBJET.doubleclickDuration = _DELAY;
_OBJET.lastClick = 0;
_OBJET.pressed = false;
interceptor();
}
// intercept le double clic et renvoie un évènement
static public function interceptor():Void{
/* interceptor event "onEnterFrame" */
_OBJET.onEnterFrame = function(){
if (this.lastClick>0) {
if ((getTimer()- this.lastClick)>this.doubleclickDuration) {
this.lastClick = 0;
if (this.hitTest(_root._xmouse, _root._ymouse, true) && this.pressed)
this.onClick();
}
}
};
_OBJET.onMouseDown = function(){
if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
this.pressed = true;
if (this.lastClick == 0) {
this.lastClick = getTimer();
} else {
this.lastClick = 0;
this.onDblClick();
}
}
};
_OBJET.onMouseUp = function(){
this.pressed = false;
};
}
/* on double click */
public function onDblClick() : Void {}
/* on simple click */
public function onClick() : Void {}
}
private function designObject(temp, nom){temp.onDblClick = function(){
_root.design_mc.select(nom, this);
_root.design_mc.editText(this, nom);
}
temp.onClick = function(){
_root.design_mc.select(nom, this);
_root.design_mc.moveAll();
temp.onRelease = function() {
_root.design_mc.stopAll();
};
}
temp.onRelease = function() {
_root.design_mc.stopAll();
};
DoubleClick.initialize(temp);
}
Ainsi je peux instancier le double clic sur plusieurs sous clip d'un clip sans m'emeler les pinceaux, je n'envoie pas 2 messages pour le double clic (1 sur le simple, 1 sur le double), et enfin j'intercepte bien une sorte de onPress sur mon élément.
Si vous avez des remarques, des insultes, des idées d'amélioration, ne vous gênez pas !
Désolé pour 2 choses :
* avoir double copier coller ma classe
* avoir doublé mon onRelease
^o^
hello
des _root dans une classe (_root.design_mc) ??? étrange en général c'est pas propre ce genre d'utilisation du ciblage
J'en profite pour proposer ma version perso du doubleClick
http://live.burrrn.com/browser/projects/VEGAS/AS2/trunk/src/asgard/ui/DoubleClick.as
Utilisation :
import vegas.events.Delegate ;import asgard.events.MouseEvent ;
import asgard.events.MouseEventType ;
import asgard.ui.DoubleClick ;
var onDoubleClick = function (ev:MouseEvent):Void {
trace (this + " >> " + ev.type) ;
}
DoubleClick.addListener( Delegate.create(this, onDoubleClick) ) ;
// Test sur un événement onPress avec la propriété statique ISDOUBLE
bt.onPress = function () {
var isDouble:Boolean = DoubleClick.ISDOUBLE ;
if (isDouble) trace (this + " >> " + MouseEventType.DOUBLE_CLICK) ;
}
A mon avis tu devrais notifier l'événement avec un système événementiel de type ASBroacaster ou autre... ce serait + propre non ?
EKA+
tu as raison
par contre pour l'ASBroadcaster, j'ai du mal. Il me renvoie un clic sur tous mes éléments écoutés, et ce pour un clic n'importe où sur la scène. J'ai donc laissé tomber et fait une autre fonction à la va vite, pour ne pas en plus receptionner le premier clicK.
J'aimerais bien tester ta classe mais j'ai besoins de tes classes event.dispatcher et fastdispatcher.
merci d'avance
Retourne à la racine du projet sur le lien au dessus et tout est expliqué pour installer mes classes
Bonjour tout le monde j ai eu un probleme avec le double clic sous flash et j ai voulu le desactivé J ai trouvé cette solution >
Code sur le bouton que je ne veu plus pouvoir dboule cliquer
> on(release){_parent.monBouton.enabled= false}
on(press){_parent.monBouton.enabled= false}
Pensser a réactivez les boutons que vous avez besoin de réutiliser par la suite
Bonne chance a vous et bon Flash
Fil des commentaires de ce billet