Flash nervt (Teil II): Verschachtelte Event Handler

Je länger ich mit Flash arbeite, desto mehr füllt sich die Liste der nervigen Schwachstellen der immerhin mehrere hundert Euro teuren Software. Arbeiten mit Flash ist wie modernes Fernsehen - immer, wenn es interessant wird, hört der Spaß plötzlich auf. Im Fernsehen ist es Werbung, die alles ruiniert, bei Flash sind es Unzulänglichkeiten, die einen ambitionierten Programmierer vor den Kopf stoßen. Wer aber schon länger mit Flash arbeitet, wird sich auch bereits daran gewöhnt haben, sich ständig Umwege ausdenken zu müssen, wie diese Hürden, die uns FlashentwicklerInnen von Herrn und Frau Macromedia-Adobe aufgebürdet worden sind, doch noch zu überwinden sind; so genannte workarounds sind an der Tagesordnung.

Das Flashfeature, eigene Kontextmenüs zu erstellen, wird ja dadurch versaut, dass sie nun gerade nicht in Standalone-Anwendungen funktionieren, aber darüber habe ich mich ja schon an anderer Stelle aufgeregt.

Worum geht es?
Ein anderes Thema, das noch mehr Leute angeht, da es häufiger nachgefragt wird als die Manipulation irgendwelcher Kontextmenüs, ist das Verschachteln von event handlers. Zur Veranschaulichung folgender Screenshot:

<img src=”../img/freel_contact_beta_shot.gif” alt=”" width=”450″ height=”147″ />
Abb. 1: Einsatzgebiet für verschachtelte event handler aus der Praxis

Es handelt sich um eine Kontaktverwaltungsapplikation (unvollendet). Interessant ist hier hauptsächlich der Bereich, wo einzelne Kontakte angezeigt werden. Jeder Kontakteintrag besteht im Wesentlichen aus einem breiten, rechteckigen Block, in dem ein Foto und einige Textinformationen untergebracht sind. Ferner gibt es noch eine kleine Checkbox. Alles zusammen steckt in einem Movieclip, der über seinen Exportnamen aus der Library auf die Bühne gebracht wird. Das Foto und die Checkbox stellen jeweils eigene Movieclips innerhalb des vorgenannten Movieclips dar.

Das Ansprechen oder Referenzieren dieser ineinander verschachtelten Movieclips ist ja kein Problem. Spannend wird es erst, wenn ich folgenden Plan in die Tat umsetzen will:

  • Bei Überrollen des Blocks soll die Meldung “Block überrollt” ausgegeben werden.
  • Bei Klick auf das Foto soll die Meldung “Foto geklickt” ausgegeben werden.
Versuch 1:
block.onRollOver = function () {
trace(”Block überrollt”);
}
block.foto.onRelease = function () {
trace(”Foto geklickt”);
}

Ergebnis von ActionScript-Versuch 1:
Der event handler onRollOver wird wie gewünscht ausgeführt, die Meldung erscheint. Auf das Foto kann allerdings geklickt werden, bis die Maustaste ihren Geist aufgibt - nichts passiert, keine Meldung erscheint im Ausgabefenster. Das liegt daran, dass es in Flash (noch?) nicht ohne Weiteres möglich ist, event handler auf diese Weise zu verschachteln. Das Skript für den Eltern-Movieclip “block” überdeckt das Skript für den Kind-Movieclip “foto”.

ActionScript-Versuch 2:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
};

Ergebnis von ActionScript-Versuch 2:
Der event handler onRollOver wird ausgeführt, onRelease ebenfalls.

Wird also das überdeckende Skript nach dem ersten Inkrafttreten entfernt (per delete), erhält das zunächst überdeckte Skript eine Chance, seinen Dienst zu verrichten.

Wird jetzt allerdings erneut der Block überrollt, passiert nichts weiter, denn sein Skript ist ja entfernt worden. Das ist natürlich ungünstig, da BenutzerInnen natürlich ruhig so oft mit dem Mauszeiger über den Block rollen können sollen, wie sie wollen, ohne Funktionalitätseinbußen in Kauf nehmen zu müssen.

Irgendwie muss ich also das ursprüngliche Verhalten des Blocks wieder herstellen.

ActionScript-Versuch 3:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
};

Ergebnis von ActionScript-Versuch 3:
Teilerfolg! Der event handler onRollOver wird aktiv, onRelease ebenfalls. Leider befindet sich der Mauszeiger noch über dem Block (eigentlich über dem Foto, aber damit auch über dem Block), während sein Skript restauriert wird, so dass es sofort wieder ausgelöst - und gelöscht - wird.

Wenn ich die Wiederherstellung des Block-Skripts nicht mit onRollOver des Blocks koppele, sondern mit dessen onRollOut, …

ActionScript-Versuch 4:
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
_root.block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
delete this.onRollOut;
};
};
};

Ergebnis von ActionScript-Versuch 4:
…komme ich der Lösung zwar ein Stückchen näher und das ursprüngliche Überroll-Verhalten des Blocks wird wieder hergestellt, aber nur(!), wenn vorher das Foto angeklickt worden ist. Wenn BenutzerInnen aber den Block überrollen, das Foto keines Blickes/Klicks würdigen und wieder aus dem Block herausrollen, habe ich immer noch dasselbe Problem: Der Block bleibt deaktiviert und regungslos zurück wie ein kurzgeschlossener Toaster. Füge ich statt dessen einen onRollOut event handler vor allem anderen ein, lande ich wieder in derselben Falle wie ganz am Anfang:

ActionScript-Versuch 5:
block.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
};
block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;};
block.foto.onRelease = function() {
trace(”Foto geklickt”);
this._parent.onRollOut = function() {
trace(”Mauszeiger von Block weggerollt!”);
_root.block.onRollOver = function() {
trace(”Block überrollt!”);
delete this.onRollOver;
delete this.onRollOut;
};
};
};

Ergebnis von ActionScript-Versuch 5:
Das Foto-Skript wird wieder überdeckt, diesmal nicht vom onRollOver-, sondern vom onRollOut-Skript des Blocks.

Nicht nur, dass ich auf diese Weise offenbar nicht auf einen grünen Zweig komme; das Skript wird auch noch abartig unübersichtlich und unhandlich.

Anderer Ansatz - hitTest()
Kramt man etwas in Flashs Trickkiste, findet man eine Methode, die ich persönlich genauso halbherzig umgesetzt finde, wie so vieles andere in Flash: hitTest(). Sie soll FlashentwicklerInnen bei Kollisionsabfragen unterstützen, also Abfragen erlauben wie zum Beispiel “Überschneidet sich Movieclip A mit Movieclip B?” oder “Befindet sich der Mauszeiger über Movieclip X?”.

Der Gedanke bei dem folgenden Versuch ist einfach: Wenn man keine event handler verschachteln kann, die speziell mit Maus-Interaktion zusammen hängen, gelingt dann vielleicht die Verschachtelung aus so einem event handler und einer hitTest-Abfrage?

ActionScript-Versuch 6:
function over() {
trace(”Block überrollt!”);
};
block.onRollOver = over;block.foto.onEnterFrame = function() {
if (this.hitTest(_root._xmouse, _root._ymouse)) {
delete this._parent.onRollOver;
this.onRelease = function() {
trace(”Foto geklickt”);
};
} else {
this._parent.onRollOver = over;
}
};

Ergebnis von ActionScript-Versuch 6:
Das Skript ist nicht hübsch, aber es funktioniert. Dem Foto-Movieclip wird ein onEnterFrame event handler mit auf den Weg gegeben, der x mal pro Sekunde überprüft, ob sich der Mauszeiger über dem Foto befindet. Falls dies zutrifft, wird schnell ein geeigneter event handler für das Foto ins Leben gerufen und der event handler für den Block entfernt. Falls BenutzerInnen jedoch das Foto gar nicht im Visier haben, erhält der Block sein normales Verhalten (zurück, wenn das Foto berührt worden ist).

Eigentlich unlogisch
Im Grunde wundert mich, dass es auf diese Weise funktioniert, denn laut Flash-ActionScript Dictionary handelt es sich auch bei onEnterFrame um einen event handler, das heißt, wir haben es hier eigentlich wie bei den ganzen gescheiterten Versuchen oben auch mit sich überdeckenden event handlers zu tun. Nur dass es hier läuft… *seufz*

Hinterlasse eine Antwort