• Wieder einmal haben uns unsere Apfeltalker tolle Fotos zur Abstimmung eingesandt. Welches ist Euer Favorit? Stimmt mit ab! Hier geht es zur Abstimmung --> Klick
  • Es ist bereits Apfeltalk-Tradition und wir möchten sie auch in diesem Jahr fortsetzen: Unser Apfeltalk-Weihnachtslogo-Wettbewerb hat begonnen! Gestaltet für uns das Weihnachtsbanner, das im Monat Dezember bis zum Weihnachtsfest unsere Webseite schmücken soll. Lasst Eurer Kreativität freien Lauf! Hier geht es zum Wettbewerb --> Klick

NSTableView auf Rechtsklick reagieren lassen

  • Ersteller Ersteller Mitglied 7974
  • Erstellt am Erstellt am

Mitglied 7974

Gast
Hallo, zusammen!

Ich schraub gerade an einem Cocoa-Programm herum, das eine NSTableView enthält. Diese wiederum soll auf Rechtsklicks reagieren können (ich will dann über dem ausgewählten Eintrag ein Kontext-Menü einblenden, dass Optionen anzeigt, was mit dem selktierten Eintrag angestellt werden soll).

Mein Problem ist jetzt, dass mir nicht klar ist, wie ich meine Tabelle nun auf Rechtsklicks reagieren lassen kann. Mein Ansatz wäre gewesen, die Methode rightMouseDown: (NSEvent *)theEvent zu überschreiben. Nachdem NSTableView von NSResponder abgeleitet ist, müsste ich dazu also wahrscheinlich lediglich eine neue Klasse erstellen, die von NSTabeleView abgeleitet ist, und darin besagte Methode überschreiben.

Das funktioniert aber nicht. Die so erstellte Ableitung von NSTableView wird nicht mal mehr richtig in meinem Cocoa-Fenster dargestellt und ist innerhalb des Programms gar nicht mehr ansprechbar. Das muss also wohl der falsche Ansatz gewesen sein.

Nachdem die Suchfunktion und Google mir darauf keine Antwort liefern konnten, wende ich mich nun an euch mit der allgemeinen Frage: Was muss ich tun, damit ich einen Rechtsklick auf eine NSTableView abfangen und darauf reagieren kann? (Und ja: Ich bin Cocoa-Newbie und scheine wohl das Event-System unter Cocoa noch nicht richtig verstanden zu haben.)

Danke!
 
Poste mal den Code... Ich kann aus deinen Ausführungen nicht herauslesen, was du falsch gemacht hast. Ein solches Vorhaben sollte eigentlich kein Problem sein.

Gruss ppocket

PS: Machst du einen Anhang, bitte den build-Ordner löschen!!
 
Erstmal danke für das Angebot. Aus welchen Gründen auch immer - jetzt funktioniert plötzlich alles. Ich kann's mir nicht erklären.

Nun gut, ich geh jetzt einfach mal davon aus, dass sich vorhin bei mir irgendwo eine Unaufmerksamkeit eingeschlichen hat und daher das Ableiten von NSTableView nicht korrekt funktioniert hat. Jetzt geht es.

Doch von der einen Lösung geht's gleich weiter zum nächsten Problem: Ich will ja Rechtsklicks abfangen. Ja, das kann ich jetzt auch, doch scheint ein Rechtsklick eben was anderes zu sein als ein Control-Klick. Ein normaler Rechtsklick bewirkt nämlich nicht, dass die Selektion in meiner Tabelle an die Stelle des Rechtsklicks springt. Sehr wohl aber bei einem Control-Klick.

Jetzt stellt sich mir also die Frage: Wie bringe ich es fertig, dass bei einem Rechtsklick (rightMouseDown) die Selektion der Tabelle genauso an die angeklickte Stelle springt, als ob man mit der linken Maustaste darauf geklickt hätte? Ich hab's schon mit dem Senden eines selbst erstellten Maus-Events an mouseDown probiert, aber da schmiert mir das Programm ab.
 
Ach ja, hier der Quellcode der Implementierung meiner eigenen NSTableView. Damit funktioniert die Selektion auch bei Rechtsklick, doch schmiert dann das Programm ab. Was ist also die korrekte Lösung?

Code:
@implementation MyTableView


- (void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent];
    
    if ([theEvent modifierFlags] == 262401) {
        // Kontextmenü einblenden
    }
}

- (void)rightMouseDown:(NSEvent *)theEvent {
    [super rightMouseDown:theEvent];
    
    NSEvent *newEvent = [NSEvent mouseEventWithType:NSLeftMouseDown
                                           location:[theEvent locationInWindow] 
                                      modifierFlags:262401 // Entspricht den modifierFlags bei Control-Klick
                                          timestamp:[theEvent timestamp] 
                                       windowNumber:[theEvent windowNumber] 
                                            context:[theEvent context] 
                                        eventNumber:[theEvent eventNumber] + 1 
                                         clickCount:1 
                                           pressure:1.0];
    [self mouseDown:newEvent];
}

@end
}
Im Anhang ist außerdem noch das zugehörige Xcode-Projekt angehängt. Im Großen und Ganzen handelt es sich dabei um ein Tool, das mir mehrere Bilder gleichzeitig auf eine bestimmte Größe skalieren soll. Wenn man die zu skalierenden Bilder ausgewählt hat, werden deren Namen links in der besagten Tabelle angezeigt. Bei einem Klick auf einen der Namen wird in der Rechten Bildschirmhälfte das ausgewählte Bild angezeigt.

Der Rechtsklick auf einen Bildernamen soll nun also bewirken, dass die Tabellenselektion zunächst an die betreffende Stelle springt und dann an ebendieser Stelle ein Kontextmenü eingeblendet wird.
 

Anhänge

Was mir als Erstes auffällt, ist, dass du zweimal ein mouseDown event an super bzw. self sendest, aber nie ein mouseUp. Ganz klar schmiert dein Programm ab, weil nicht mehr alle Klicks wieder losgelassen werden, zumindest lässt du das Programm dies glauben!

Also bei mir unter 10.6 passiert sowohl bei Rechtsklick als auch bei Ctrl-Klick keine Selektion, sondern nur so ein blauer, gerundeter Rand erscheint, aber auch nur, wenn ein Kontextmenu eingestellt ist. Sonst ist es dasselbe, wie bei dir.

Das kommt wahrscheinlich daher, dass wenn kein Kontextmenu existiert, ein Ctrl-Klick als Linksklick interpretiert wird, also ein völlig logischer Unterschied.

Schau dir mal die NSTableView-Methode menuForEvent: an!!

Gruss ppocket
 
Ah, danke, Poljpocket! Dann werde ich mir die Methode mal angucken. Vielleicht reicht das dann schon.

Dennoch: Wie müsste ich es denn machen, damit es mit dem Umleiten eines Rechtsklicks auf einen Control-Klick funktioniert? Vielleicht kann ich das ja irgendwann mal brauchen. Du meintest ja, ich müsse freilich auch noch ein MouseUp-Event schicken. Müsste das dann in etwa so aussehen?

Code:
- (void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent]; // MouseDown an super weiterleiten, um Standardverhalten nicht zu unterbinden
    
    NSEvent *controlMouseDownEvent = ...
    [self mouseDown:controlMouseDownEvent]; // MouseDown für Control-Klick simulieren

    NSEvent *rightMouseUpEvent = ...
    [self rightMouseUp:rightMouseUpEvent]; // MouseUp für rechte Maustaste

    NSEvent *controlMouseUpEvent = ...
    [self mouseUp:controlMouseUpEvent]; // MouseUp für Control-Klick simulieren
}

Ich kann's leider erst am Abend testen, aber wär das so in etwa richtig oder sieht das unter Cocoa grundsätzlich anders aus?
 
Ich kann dir das nicht genau sagen, habe mich nicht damit befasst. Ausprobieren hilft. Ganz klar ist, dass du das mouseUp-Event für diesen RightKlick selber handeln musst!! Wie gesagt, ich brauche sowas selber nicht, da es ja wirklich nicht nötig ist, weil dasselbe passiert, wenn ein Kontextmenu existiert und ein Linksklick interpretiert wird, wenn kein Kontextmenu existiert (bzw. Ctrl-Klick dann eben gar keine Funktion hat)!
 
NSView#menuForEvent funktioniert ganz wunderbar! Nochmal vielen Dank! Wenn man so wie ich von der Java-Programmierung kommt, wo man dann doch eine Menge Standard-Zeug immer wieder von neuem programmieren muss, ist Cocoa dann doch eine Umstellung. Ich muss mir wohl angewöhnen, die Library genauer zu durchsuchen, wenn ich Standardverhalten implementieren möchte. Wie es scheint, nimmt einem Apple da öfter mal die Arbeit ab. Ist auch schön! ;-)
 
Joa, Cocoa ist das Apple-Framework für die Objective-C Programmierung schlechthin. Die stellen jegliche auch von ihnen selbst für die OS X Programme verwendeten Interface-Elemente und sonstige Klassen, was zusammen eine gute Einheit für alle Programme schafft, einfach so zur Verfügung. Das schafft für den Benutzer enorm viel Transparenz und er trifft immer wieder dasselbe an. Finde ich ein Riesenvorteil gegenüber Windows, wo wirklich fast jedes Programm anders aussieht/funktioniert, nichtmal Mircosoft selber schafft es da einheitlich zu halten bei ihren Dingen (man sehe sich das scheussliche Office 07 / Office 10 an).

PS: Wenn du es richtig machst, nimmt dir Apple fast die ganze Arbeit ab (zB CoreData, CoreAnimation, ...). :P
 
CoreData und CoraAnimation kommen irgendwann auch noch mal bei mir dran. Jetzt aber erst mal den Ball flach halten und schauen, dass ich die Grundlagen in den Griff bekomme. Nachdem bei Cocoa gerne mal der Gaul von hinten aufgezogen wird (man sagt nicht der NSView, sie solle ein Bild zeichnen, sondern dem Bild, es solle sich in die NSView zeichnen!), muss ich zunächst mal umdenken lernen.

Ich muss dir aber bei MS Office widersprechen. Ich finde die Ribbonbar von Office 2007 absolut gelungen. Ich komme damit besser klar als mit den tausend verschachtelten Menüs und würde mir sowas auch für den Mac wünschen. Aber das ist freilich Geschmackssache und über Geschmack lässt sich ja nicht streiten. ;-)
 
Nachdem bei Cocoa gerne mal der Gaul von hinten aufgezogen wird (man sagt nicht der NSView, sie solle ein Bild zeichnen, sondern dem Bild, es solle sich in die NSView zeichnen!), muss ich zunächst mal umdenken lernen.

Das ist so nicht ganz richtig! Die NSView zeichnet sowieso auch nicht in sich selbst. Dafür gibt es einen sog. graphics context, in welchem definiert ist, in welchen Bereich des Bildschirms, auf welcher Ebene usw... gezeichnet wird. Also kannst du NSView und NSImage genau gleich behandeln, weil diese beide einfach in die graphics Oberfläche zeichnen. Das sind halt die Konzepte von Cocoa, manchmal gewöhnigsbedürftig, aber schon recht gut durchdacht und sicher auch nicht ohne Grund so, wie sie sind.

Gruss ppocket

PS: Ich spreche bei Office auch nicht von den einzelnen Elementen der Software, ich gebe dir recht, die Ribbon-Bar ist praktisch. Es ist nur so, dass die Programme nicht einheitlich sind. Also zum Beispiel hat Cocoa vordefinierte Befehl-Sheets für Speichern, Öffnen und sogar Drucken. Bist du unter Windows, musst du bei jedem einzelnen Druckbefehl die Dinge immer wieder suchen, weil die alle anders aufgebaut sind. Auf dem Mac sagt man als Programmierer, "Cocoa, druck mir das: ..." und dann geschieht alles automatisch und der Druckbefehl sieht immer gleich aus.