• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

Drag and Drop in NSTableView

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Hi,

Das folgende ist eigentlich relativ trivial. Ich habe einen NSTableView der Daten aus einem NSMutableArray darstellt.
Nun soll Drag and Drop der Listenelemente ermoeglicht werden. Also habe ich mir die Dokumentation geschnappt und die "Anleitung" unter "Using Drag and Drop in Tables" befolgt.

Bis jetzt hatte ich keine Probleme nur den Drop zu akzeptieren macht mir Kopfweh. In der Anleitung steht.
Code:
// Move the specified row to its new location...
Und genau da scheitere ich. ;)

Ich krieg zwar das Objekt dazu das neue Objekt an der neuen Stelle hinzuschieben, aber von der alten Stelle zu entfernen da steigt mein Hirn irgendwie aus.
Wie macht man das?

Danke
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Hey danke fuer die flotte Antwort. Ich habe nur ein Problem. Das was du da hattest hatte ich auch schon probiert. Nur das Problem war, dass die Objekte dann doppelt in der Liste stehen.

Hier mal ein wenig Code aus dem acceptDrop:

Code:
NSPasteboard *pboard = [info draggingPasteboard];
NSData *data = [pboard dataForType:MyDragType];
NSIndexSet *indexSet = [NSKeyedUnarchiver unarchiveObjectWithData:data];
int dragRow = [indexSet firstIndex];

[contentArray insertObject:[contentArray objectAtIndex:dragRow] atIndex:row];
[contentArray removeObjectAtIndex:dragRow];

[tableView reloadData];
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Hier mein Code aus dem Projekt:

// Zeile greifen
-(BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard {

NSArrayController *theArrayController = [[tv infoForBinding:NSContentBinding] objectForKey:NSObservedObjectKey];

// Zeile zum Pasteboard schieben
NSData *theData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pboard declareTypes:[NSArray arrayWithObject:[myPreferences prefTuneInstructorDraggedType]] owner:theArrayController];
[pboard setData:theData forType:[myPreferences prefTuneInstructorDraggedType]];

// Ja, darf verschieben
return YES;

}


// Element ist am Cursor
-(NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation {

NSDragOperation theDragOperation = NSDragOperationMove;

// Nur neben den Zeilen Drop erlauben
[tv setDropRow:row dropOperation:theDragOperation];

// Alles erlauben
return theDragOperation;

}


// Element wird losgelssen
-(BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)to dropOperation:(NSTableViewDropOperation)operation {

NSArrayController *theArrayController = [[aTableView infoForBinding:NSContentBinding] objectForKey:NSObservedObjectKey];

// Drag-Info holen
NSPasteboard *thePasteboard = [info draggingPasteboard];
NSData *theData = [thePasteboard dataForType:[myPreferences prefTuneInstructorDraggedType]];

// Position der alten Zeilen
NSIndexSet* theRowIndexSet = [NSKeyedUnarchiver unarchiveObjectWithData:theData];
NSMutableIndexSet *theRowIndexSetTmp = [[[NSMutableIndexSet alloc] initWithIndexSet:theRowIndexSet] autorelease];

NSInteger theCounter = 0;
NSInteger theIndexNo = 0;
NSInteger theToTmp = 0;

while ([theRowIndexSetTmp count] > 0) {

theIndexNo = [theRowIndexSetTmp firstIndex];
[theRowIndexSetTmp removeIndex:theIndexNo];

// Vom ArrayController die ursprüngleche Zeile von der alten Position auslesen
NSMutableDictionary *theRow;

if(theIndexNo > to) { // Eintrag wird von Unten nach Oben geschoben

theRow = [[theArrayController arrangedObjects] objectAtIndex:theIndexNo];
[theArrayController insertObject:theRow atArrangedObjectIndex:to + theToTmp];
[theArrayController removeObjectAtArrangedObjectIndex:theIndexNo + 1];
theToTmp++;

} else { // Eintrag wird von Oben nach Unten geschoben

theRow = [[theArrayController arrangedObjects] objectAtIndex:theIndexNo - theCounter];
[theArrayController insertObject:theRow atArrangedObjectIndex:to];
[theArrayController removeObjectAtArrangedObjectIndex:theIndexNo - theCounter];
theCounter++;

}

}

return YES;

}
Der funktioniert tadellos.
Funktioniert auch, wenn Du zwischen den markierten Zeilen etwas einfügst.
Also die richtige Folge.


Viele Grüße
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Gut, dasss Du mich erinnerst.
Der Code ist plöht, schreibe ich neu.

Ich schreibe ein Testprojekt.
Lade es dann hier hoch.

Viele Grüße
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Ich schaffe es jetzt leider zeitlich nicht das Teil jetzt neu zu schreiben, aber ich habe Dir ein Beispiel erstellt.
Bitte schreibe doch noch den Code beim Loslassen neu.

Viele Grüße
 

Anhänge

  • TableTest.zip
    57,1 KB · Aufrufe: 104
  • Like
Reaktionen: Zettt

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Hey ich danke dir fuer das Beispielprojekt. Das hat mir extrem viel weiter geholfen.
Ich habs erstmal so gemacht wie du. Bin dann drauf gekommen, dass es vielleicht auch einfacher gehen koennte. (Da du, glaub ich, das Objekt was verschoben werden soll erst nochmal in ein tmpArray einliest, aber das Objekt befindet sich ja schon im Pasteboard.)

Herausgekommen ist das hier:

Code:
- (BOOL)tableView:(NSTableView *)aTableView 
	   acceptDrop:(id <NSDraggingInfo>)info 
			  row:(NSInteger)destinationRow 
	dropOperation:(NSTableViewDropOperation)operation {
	//NSLog(@"%@", NSStringFromSelector(_cmd));
	
	NSPasteboard *pboard = [info draggingPasteboard];
	NSData *data = [pboard dataForType:MyDragType];
	NSIndexSet *indexSet = [NSKeyedUnarchiver unarchiveObjectWithData:data];
	int sourceRow = [indexSet firstIndex];
	
	if (destinationRow < sourceRow) { //drag nach oben
		NSLog(@"Nach Oben");
		
		[contentArray insertObject:[contentArray objectAtIndex:sourceRow] atIndex:destinationRow];
		[contentArray removeObjectAtIndex:sourceRow + 1];
		
	} else if ( destinationRow > sourceRow) { //drag nach unten
		
		[contentArray insertObject:[contentArray objectAtIndex:sourceRow] atIndex:destinationRow];
		[contentArray removeObjectAtIndex:sourceRow];
	}
	[tableView reloadData];
	
	return YES;
}

In validateDrop arbeite ich auch ein wenig anders, allerdings kann ich nicht sagen ob das so stimmt. Ich moechte auch nicht, dass man Objekte "aufeinander" ziehen kann also:

Code:
- (NSDragOperation)tableView:(NSTableView *)aTableView 
				validateDrop:(id < NSDraggingInfo >)info 
				 proposedRow:(NSInteger)row 
	   proposedDropOperation:(NSTableViewDropOperation)operation {

	if (operation == 0) {
		return NSDragOperationNone;
	}
	return NSDragOperationEvery;
}

Merci und herzlichsten Dank!
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Da du, glaub ich, das Objekt was verschoben werden soll erst nochmal in ein tmpArray einliest, aber das Objekt befindet sich ja schon im Pasteboard.
Ja, weil ich (in meinem richtigen Projekt) noch ein paar andere Dinge damit umsetzen muss.
Deshalb dieser Weg.

Schön, dass es Dir geholfen hat.

Viele Grüße
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Verstehe. Ok. Nein hat mir sehr geholfen. Danke.
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Eine Frage noch. Wo fuehre ich denn die Drag'n'Drop Dinge die hier besprochen wurden in einer CoreData Applikation aus?
Ist das am besten im Delegate aufgehoben oder kreiere ich dafuer lieber eine Subklasse von NSObject und rede darin mit dem eigentlich CoreData Zeugs?
Steh grad mal wieder voll auf dem Schlauch.
 

Thaddäus

Golden Noble
Registriert
27.03.08
Beiträge
18.392
Hier mein Code aus dem Projekt:

Der funktioniert tadellos.
Funktioniert auch, wenn Du zwischen den markierten Zeilen etwas einfügst.
Also die richtige Folge.


Viele Grüße

Hi...

Wäre super, wenn du nächstes Mal Codetags verwenden würdest, das verhindert, dass überall Smilies angezeigt werden... ;)
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Wird er sicher noch machen. Hat mich jetzt aber auch nicht gestoert. Man weiss ja, was da eigentlich stehen soll.
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Das mit "wohin soll's" war ne doofe Frage. Natuerlich gehoert's in Controller. Da stand ich kurzzeitig auf der extrem langen Leitung. :p
 

Amin Negm-Awad

Süsser Pfaffenapfel
Registriert
01.03.07
Beiträge
665
Hi...

Wäre super, wenn du nächstes Mal Codetags verwenden würdest, das verhindert, dass überall Smilies angezeigt werden... ;)
Bei little_pixel bin ich mir ziemlich sicher, dass es ein versehen war. Er gehört nämlich zu den hilfsbreitesten und qualifiziertesten Nutzern hier.
 

Zettt

Doppelter Melonenapfel
Registriert
16.10.05
Beiträge
3.374
Es ist bereits äußerst begrüßenswert, dass du zu den Leuten gehörst, die diese Frage stellen.

Danke, Amin. Was man so aus Jux und Dallerei nicht alles macht.

Seh grade, dass du dieses Jahr auch wieder auf der Macoun bist. Da sehen wir uns ja. Kommst du Freitag schon? (Oder Samstag kurz vor Schluss – so wie dein Vortrag. Was fuer einen Slot du da erwischt hast!)