Hi Leute,
Der Grund: Es gibt zumindest zwei Wege, einen Button einfacher zu machen, als Du ihn beschreibst:
Darüber kann man streiten ;-)
Here we go... :-) Nein, im Ernst, an alle zu posten, dass ich gleich zwei einfachere Lösungen wüsste, und dann auch noch Chris Seite umzubenennen, war ein wenig großspurig von mir. Ich hätte mich natürlich vorher mit ihm darüber abstimmen müssen, sorry, soll nicht mehr vorkommen.
Ich denke, die Diskussion wirft aber eine wichtige Frage auf:
An wen richten sich unsere Tutorials? Haben wir eine Hauptzielgruppe? Chris hat eher Smalltalk-Entwickler im Sinn, die eine gute open-source Entwicklungsumgebung suchen, ich dachte eher an Kinder/Eltern/Lehrer oder "Omniuser" (was war da gleich die beste deutsche Übersetzung?)
Vielleicht sollten wir da mehrere Zweige aufmachen und in der Überschrift klar machen, für wen das Tutorial gedacht ist.
Zum einen via E-Toys, das habe ich zunächst mal erklärt (Bilder lade ich up, sobald ich das Upload-Kennwort wieder weiß), zum zweiten, wenn Du es "textprogrammatisch" machen möchtest, brauchst Du "nur" die handlesMouseDown: und handlesMouseOver: in Morph zu überschreiben und kommst dann ganz ohne when:... aus.
Schon, schon, aber die Frage ob #handlesMouseDown: einfacher ist als "on:send:to:" ist schwierig zu beantworten.
Das Tutorial für den E-Toy Button nebst Screenshots und Filmaufnahme ist mir wichtiger, als die Antwort auf die Frage, welche der Smalltalk-Lösungen tatsächlich einfacher ist oder nicht. Trotzdem die längere Antwort zum anderen Teil:
Es gibt zumindest zwei Probleme damit: Zum einen muss man sich an fünfhundert verschiedene #handlesFooBar: Methoden erinnern, und wenn man eine vergisst passiert rein gar nix (und solche Sachen sind wirklich schwer zu finden).
Stimmt, ein Problem was ich hatte, war, dass ich erstmal #handlesMouseEnter: anstatt #handlesMouseOver: überschrieben hatte, da tat sich auch erst mal nicht viel. Wenn man mittels leerer Templatemethoden a la Morph >> #fooBar die #handlesFooBar ganz loswürde, wäre das noch besser. Aber die Schwierigkeiten, Morph zu vereinfachen, sind genug diskutiert worden, vielleicht gibt es ja da demnächst was besseres...
Demzufolge ist das "explizite Setup" mittels #on:send:to: u.U. einfacher zu merken - es hat weniger Constraints (die Methode kann irgendwie heissen)
Könnte man in mouseDown: umleiten...
und man muss sich nur ein Konzept merken. Zudem ist das Setup zentralisiert, was bedeutet das wenn jemand rausfinden möchte "was dieses Ding macht" kann er in die Initialisierung reinschauen und muss nicht wild durch die Klasse browsen.
Das Argument kommt mir schon vom Visitior-Pattern bekannt vor, ich mag es nicht so gern, weil wir ja sonst bei OO immer der Verteilung das Wort reden, bin wohl eher der wilde Typ :-) ...solange die Methodennamen sprechend genug sind, aber das ist vielleicht Mentalitätssache.
Vielleicht finde ich es auch einfach schwieriger, den richtigen Event-Namen zu finden, als die Methode, die ich überschreiben muss.
Wir sind uns einig, dass der E-Toy-Weg da der eleganteste ist.
Zum anderen, ist die Implementation von #mouseDown: o.ä. Methoden eigentlich eine Modifikation des Frameworks, was bedeutet, man muss zwangsläufig die "super" Methoden verwenden, was für mich eine (unnötige) Verkomplizierung des Tutorials darstellt. Du bist Dir übrigens bewusst, dass Dein Beispiel buggy ist, oder?! ;-) Weder #mouseEnter:, noch #mouseLeave:, noch #mouseUp: verwenden die "super" Implementationen, was sie eigentlich müssten (nicht so in Chris' Beispiel).
Ich verstehe aber nicht, warum ich super rufen muss. Ich muss es dann rufen, wenn ich event-handling, wie Ihr es vorschlagt, benütze. Will ich ja nicht, alles was der Morph nach click tun soll, definiere ich in mouseDown: Oder was übersehe ich? YAGN.
Folgendes Snippet zeigt, dass der Prozentsatz von "super-rufern" in 3.4 eher gering ist:
#(#mouseDown: #mouseEnter: #mouseLeave:) collect: [:aSymbol | someMethods := Morph allSubclasses select: [:e | e methodDict includesKey: aSymbol]. someSuperCallers := someMethods select: [:e | (e methodDict at: aSymbol) sendsToSuper and: [(e superclass lookupSelector: aSymbol) = (Morph compiledMethodAt: aSymbol)]]. someSuperCallers size / someMethods size]
#((11/71) (1/21) (1/18))
Wenn es denn falsch ist, bin ich zumindest nicht alleine... ;-) Ist das dann was für die MorphCleaningGroup?
Der einzige echte "Nachteil" der Verwendung von #on:send:to: ist, dass der Eventtrigger "zu weit entfernt" von der Methode ist, die darauf reagiert (und die Syntax ist auch nicht unbedingt trivial). Hier sind die eToys weit überlegen. Selbiges übrigens für #triggerEvent: etc.
Ob es aber "einfacher" ist, eine korrekte Implementation der Eventhandler zu schreiben oder #on:send:to: zu benutzen kann man also bezweifeln.
Ciao,
- Andreas
Viele Grüße,
Markus