Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Entwickler>Cocoa NSTextView / NSWindow delegates

Cocoa NSTextView / NSWindow delegates

Slartibartfast21.03.1118:55
Bin dabei ein C++ (Qt for Mac) Projekt nach Cocoa/Objective-C umzusetzen. Während mir damals der Einstieg in Qt sehr leicht gefallen ist, habe ich mit Cocoa mit ernsthaften Problemen zu kämpfen und brauche jetzt echt mal die Hilfe der Gemeinde

1. Problem: Ich habe einen TextView (nur PlainText) und möchte - sobald der User den Inhalt verändert - am Fenster die entsprechende Markierung setzen "[window setDocumentEdited:TRUE]". Dazu nutze ich momentan die delegate Funktion per "- (void)textDidChange:(NSNotification *)pNotification". Funktioniert auch prima, allerdings habe ich den Nebeneffekt, daß sobald ich den Font bzw. Fontgröße ändere, diese Notification auch getriggert wird. Gibt es eine Möglichkeit dies zu verhindern? Die Notification an sich gibt mir keine Auskunft darüber, ob der Text oder der Textfont geändert wurde.

2. Problem: Sobald der User das Fenster schließt, soll eine Sicherheitsabfrage kommen, ob dies wirklich erwünscht ist. Dazu habe ich mir "- (BOOL)windowShouldClose:(id)sender" rausgesucht. Als Abfrage soll ein NSAlert als Sheet dienen. Mir ist nur überhaupt nicht klar, wie so etwas zu implementieren ist, da nach Anzeige des Sheets der Programmfluß ja weitergeht und ich am Ende der "windowShouldClose" Routine ja TRUE oder FALSE zurückgeben muß (das Ende der Routine aber erreicht ist, bevor der User auf den NSAlert reagiert).

Alles andere (Load/Save, eigene Suchfunktion etc.) funktioniert schon.
Danke schon mal im voraus.
0

Kommentare

ExMacRabbitPro21.03.1119:54
Slartibartfast


1. Problem: Ich habe einen TextView (nur PlainText) und möchte - sobald der User den Inhalt verändert - am Fenster die entsprechende Markierung setzen "[window setDocumentEdited:TRUE]". Dazu nutze ich momentan die delegate Funktion per "- (void)textDidChange:(NSNotification *)pNotification". Funktioniert auch prima, allerdings habe ich den Nebeneffekt, daß sobald ich den Font bzw. Fontgröße ändere, diese Notification auch getriggert wird. Gibt es eine Möglichkeit dies zu verhindern? Die Notification an sich gibt mir keine Auskunft darüber, ob der Text oder der Textfont geändert wurde.

Nun, Du weißt aber doch im Programm, dass du gerade den Font am verändern bist. Dann verhindere doch, dass dann in textDidChange setDocumentEdited aufgerufen wird.

Beispiel:

im Header: 
BOOL internalEdit = NO;

dann dort wo der Font geändert wird: 
internalEdit = YES;
... modifiziere Font...
internalEdit = NO;

und in textDidChange:
if (!internalEdit)
{
     [window setDocumentEdited:TRUE]
}
Slartibartfast

2. Problem: Sobald der User das Fenster schließt, soll eine Sicherheitsabfrage kommen, ob dies wirklich erwünscht ist. Dazu habe ich mir "- (BOOL)windowShouldClose:(id)sender" rausgesucht. Als Abfrage soll ein NSAlert als Sheet dienen. Mir ist nur überhaupt nicht klar, wie so etwas zu implementieren ist, da nach Anzeige des Sheets der Programmfluß ja weitergeht und ich am Ende der "windowShouldClose" Routine ja TRUE oder FALSE zurückgeben muß (das Ende der Routine aber erreicht ist, bevor der User auf den NSAlert reagiert).

Geht eigentlich nach dem gleichen Konzept wie oben. Es wird windowShouldClose aufgerufen. Du stellst fest dass eigentlich gespeichert werden muss. Du präsentierst das Sheet und fragst den User und lässt windowShouldClose 'NO' zurück geben.
Dann im Handler des Sheets reagierst Du auf die Auswahl des Users:
1. Option
Bricht er ab, machst Du einfach das Sheet zu.
2. Option
Will er speichern machst Du das und schließt dann das sheet. Danach schließt Du intern selbst das Window und merkst Dir aber, dass die Aktion von intern kommt. Mit dem Merker verhinderst Du dann, dass sich in windowShouldClose das Sheet noch mal öffnet und gibst 'YES' zurück.
3. Option
Will er ohne speichern schließen, schließt du das sheet. Dann schließt Du intern selbst das Window und merkst Dir aber, dass die Aktion von intern kommt. Mit dem Merker verhinderst Du dann, dass sich in windowShouldClose das Sheet noch mal öffnet und gibst 'YES' zurück. (Gleiche Vorgehensweise wie oben - nur ohne zu speichern)
0
lasergans21.03.1119:55
1. Ich sehe nur den nicht sonderlich eleganten weg über eine Variable, in der der Inhalt gespeichert wird, und mit „isEqualToString:“ überprüft wird.
- (void)controlTextDidChange
{
if [oldContent == nil] {
//alloc and init oldContent string with new content
//do some thing
} else {
     if ([[textField stringValue] isEqualtoString:oldContent]){
     //do sth
     [oldContent release];
     //alloc and init oldContent string with new content
     }
}
}
oder so ähnlich, ist nur so hingeschmiert.
Aber warum sollte denn der geänderte Font nicht bemerkt/gespeichert werden? Ist doch eigentlich auch eine evtl wichtige Eigenschaft.
Edit: Ok, die Methode von ExMac... ist vieeeel eleganter.

2. Solange NSRunAlertPanel() noch offen ist, sollte eigentlich nichts weiter laufen (im gleichen Thread)
0
Slartibartfast22.03.1102:46
Erst einmal vielen Dank für die Tips. Während ich Objective-C als Sprache gleich ins Herz geschlossen habe, finde ich Cocoa wesentlich schwieriger als Qt.

lasergans
zu 1: Da ich nur Plaintext und nicht RTF verwende, will ich Font u. Fontgröße im Prefs File speichern, die eigentliche Datei soll nur Blowfish verschlüsselten Text enthalten, ohne irgendwelche Formatierungen. An einen Stringvergleich hatte ich auch gedacht, es aber als total uncool wieder verworfen. Nichts für ungut
zu 2: Der Tip mit NSRunAlertPanel() könnte mir aber u.U. helfen, hatte es bisher nur mit Aufrufen wie "[alert beginSheetModalForWindow: ... usw" versucht.

ExMacRabbitPro
zu 1: Bisher nutze ich ja den "eingebauten" FontDialog ohne eigenen Code. Müßte ich den Font Manager dann "subclassen"? (<- gibts da kein vernünftiges Wort für?) Muß ja an der Stelle, an der im TextView der Font gesetzt wird, eingreifen. Wenn Du mir da noch einen Tip geben könntest?
0
ExMacRabbitPro22.03.1111:54
Slartibartfast

Das Problem ist, dass der TextView auch eine Font-Änderung als reguläre Textänderung behandelt.
D.h. alle Delegate Messages werden auch bei einer Font Änderung genau so aufgerufen wie bei einer Text Änderung.
Die Schwierigkeit ist, herauszufiltern ob sich nur der Font geändert hat und nicht der Text.

Aber ganz Ehrlich - so ganz verstehe ich deine Applikations-Logik nicht. Ich versuche es mal zu beschreiben:

Der User hat einen Dialog mit TextView. Tippt er hinein, soll angezeigt werden dass sich der Text geändert hat (setDocumentEdited:TRUE) und beim schließen soll auch nach dem Speichern gefragt werden.

Ändert ein User nur den Font, dann soll KEINE Änderung angezeigt werden und beim schließen auch NICHT gefragt nach Speichern gefragt werden? Warum? Ja, und wann wird denn die Änderung am Font gespeichert? Implizit immer?

Irgendwie verstehe ich nicht, warum Du da aus Sicht des Users einen Unterschied machen willst. Finde ich verwirrend für den User und inkonsistent gegenüber anderen Anwendungen mit Text Editor. Überlege Dir doch noch einmal, ob Du das wirklich so haben willst.
0
Slartibartfast22.03.1113:18
ExMacRabbitPro

Die Logik ist ganz einfach. Der TextView enthält nur Plaintext (mit einheitlicher Formatierung, ein Font, eine Fontgröße). Diese Einstellung, die der User macht, gilt für alle Texte und wird deshalb im Prefs File automatisch beim Programmende gespeichert.

In meiner jetzigen Qt Implementierung enthält ein File nur den Header, einen Hash und den mit Blowfish verschlüsselten Text (zusätzlich Ascii85 codiert) aus dem TextView. So möchte ich das auch wieder umsetzen, schon aus Kompatibilitätsgründen.

Ich habe das Menü und ToolbarItem soweit geändert, daß ich auf eine Routine in meinem AppDelegate verweise (IBAction) und dort den FontDialog aufrufe (funktioniert schon). Nun muß ich den Font nur noch in den TextView kriegen
d.h. ich muß rausfinden, was passiert, wenn im Dialog Font oder Größe geändert werden.

0
ExMacRabbitPro22.03.1114:10
Slartibartfast

Ah ok - man kann immer nur den GESAMTEN Font ändern. Ja, dann würde ich auch nicht das eingebaute FontPanel des TextViews nehmen sondern - wie Du es nun machst - selbst ein FontPanel öffnen und bei Auswahl den Font des TextViews "von außen" setzen. Dann klappt auch die von mir oben beschriebene Vorgehensweise. ;-
0
Slartibartfast23.03.1114:29
Also, ich habs geschafft. Übrigens, bei Verwendung eines eigenen FontDialogs wird beim Ändern des Fonts die Notification nicht getriggert, d.h. ich komme ohne irgendwelche Klimmzüge aus:

- (IBAction)showFontPanel:(id)sender {
[[NSFontPanel sharedFontPanel] orderFront:nil];
[[NSFontManager sharedFontManager] setTarget:self];
if ([NSFontPanel sharedFontPanelExists] == NO) return;
[[NSFontPanel sharedFontPanel] setPanelFont: [textView font] isMultiple: NO];}

- (void)changeFont:(id)sender {
NSFont *newFont;
newFont = [sender convertFont: [textView font]];
[textView setFont:newFont];
[textView setNeedsDisplay: TRUE];
}

- (void)textDidBeginEditing:(NSNotification *)pNotification {
if(! [window isDocumentEdited]) [window setDocumentEdited:TRUE];
}
0

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.