15 berichten aan het bekijken - 1 tot 15 (van in totaal 15)
  • Q:
    Bijdrager
    Undaunted

    [cocoa] – vraag over een delegate method

    Ik ben bezig cocoa te leren met behulp van het boek “cocoa programming for Mac OSX (3rd edition) door Aaron Hillegass, en stuit op een functie die niet lijkt te werken.

    Nou begin ik al aardig wegwijs te raken, en heb met behulp van bindings een tableView gemaakt die data op basis van een zelfgedefinieerde class invoegt, verwijderd, edit.. dat werkt allemaal prima.

    Nou wil Hillegass graag dat je ook leert om het op de “oude manier” te doen. Of te wel, de Interface builder met rust laten en met code het zelfde programma werkend te krijgen.

    Dat is me gelukt op 1 functie na: sorteren.

    Als ik de documentatie erop na sla schijn ik onderstaande methode te moeten gebruiken:
    [code:1:bbe72281ea]
    – (void)tableView:(NSTableView *)aTableView
    sortDescriptorsDidChange:(NSArray *)oldDescriptors
    {
    NSLog(@"Sort method wordt aangesproken");
    NSArray *newDescriptors = [aTableView sortDescriptors];
    [employees sortUsingDescriptors:newDescriptors];
    [tableView reloadData];
    }
    [/code:1:bbe72281ea]
    Mijn overige datasource methodes zien er vergelijkbaar uit, ik zie niet goed waarom deze genegeerd wordt. Er wordt niet gesorteerd wanneer ik op een header van de tableView klik, en de functie wordt niet aangeroepen.

    Nou heb ik als oplossing gewoon toch in Interface Building de “Sort Key” en de “Selector” ingevuld van de column die ik wil sorteren, en dat werkt prima natuurlijk. Maar – gewoon uit niewsgierigheid – waarom wordt mijn sort methode niet aangesproken. het is toch een datasource method? De overige datasource methods zoals onderstaande werken wel gewoon:
    [code:1:bbe72281ea]
    – (void)tableView:(NSTableView *)aTableView
    setObjectValue:(id)anObject
    forTableColumn:(NSTableColumn *)aTableColumn
    row:(int)rowIndex
    {
    NSString *identifier = [aTableColumn identifier];
    Person *person = [employees objectAtIndex:rowIndex];

    //Set the value for the attribute named identifier
    [person setValue:anObject forKey:identifier];
    }
    [/code:1:bbe72281ea]

    Alvast bedankt!

    Bijdrager
    mhrenes

    Ik begrijp dat die delegate (sortDescriptorsDidChange) niet aangeroepen wordt?

    Wat ik her en der lees is dat als de TableView geen selectie of reordering van de columns toestaat, een ‘click’ op de header niet doorgegeven wordt.

    Probeer (ergens in de initialisatie, bijv awakeFromNib) het volgende:
    [code:1:591aef80be][<tableview object> setAllowsColumnSelection:YES];[/code:1:591aef80be]

    Hoop dat het helpt.

    Bijdrager
    Undaunted

    Leek een goede oplossing maar helaas, dat maakt geen enkel verschil.

    Als ik op de header van het column druk zie ik wel dat de datasource methods worden getriggered, maar die sortDiscriptorsDidChange: worden toch genegeerd..

    Heb je nog een andere suggestie?

    Bijdrager
    mhrenes

    Inderdaad…

    Ik denk dat ik er nu wel achter ben:

    [code:1:b93df2a187]- (void)tableView:(NSTableView *)aTableView
    sortDescriptorsDidChange:(NSArray *)oldDescriptors[/code:1:b93df2a187]

    Is alleen een delegate die aangeroepen wordt als de sortdescriptors veranderd (zouden kunnen) zijn.

    Ik vermoed dat we die dus expliciet moeten triggeren.

    We willen de tabel sorteren op geleide van de column header dus we implementeren de delegate die een click op een header van een tabelkolom registreert:

    [code:1:b93df2a187]- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn[/code:1:b93df2a187]

    In deze delegate maken we een nieuwe sort descriptor voor onze tabel en maken dit de nieuwe sort descriptor van onze tabel. Middels tableColumn weten we welke header is aangeklikt.
    NSTableView heeft de volgende method om een nieuwe sort descriptor aan te geven:

    [code:1:b93df2a187]- (void)setSortDescriptors:(NSArray *)array[/code:1:b93df2a187]

    Als de key value coding magie werkt zou automatisch de delegate sortDescriptorsDidChange aangeroepen moeten worden, zo niet dan doe je het handmatig met

    [code:1:b93df2a187][<TableView object> sortDescriptorsDidChange:nil];[/code:1:b93df2a187]

    De oude sortdescriptors zijn voor dit voorbeeld toch niet van belang dus kunnen we nil teruggeven als oude SortDescriptor.
    Anders kun je in de didClickTableColumn delegate eerst de oude descriptor ophalen met

    [code:1:b93df2a187]NSArray *oldDescriptors = [<tableView Object> sortDescriptors];[/code:1:b93df2a187]

    En die later meegeven.
    In je tabel initialisatie moet je wel ergens de eerste keer een sortDescriptor instellen anders is de tabel pas gesorteerd als de gebruiker een eerste keer op een tabel header klikt.

    Overigens:
    [code:1:b93df2a187][<array> sortUsingDescriptors:(NSArray *)<NSSortDescriptor>];[/code:1:b93df2a187]
    werkt alleen met een NSMutableArray.

    Als je me de code PM’t kan ik er thuis ook zelf nog even naar kijken. Automatisch de boel laten sorteren met InterfaceBuilder is wel een stuk eenvoudiger :D

    Bijdrager
    Undaunted

    Fantastisch, hartelijk dank voor je uitgebreide antwoord! Ik ga er vanavond weer even lekker mee stoeien.

    ’t is inderdaad honderd keer makkelijker in de interface builder, maar het handwerk leert je het best hoe het in z’n werk gaat. Vergeet ik het ook minder snel weer.

    Nogmaals heel erg bedankt voor al je tijd en energie!

    Bijdrager
    mhrenes

    En, werkt het nu?

    Bijdrager
    Undaunted

    Sorry, het lijkt waarschijnlijk dat het werkt, maar ik heb het nog niet aan de praat. Ik puzzel nog even door, ik laat het je weten!

    Bijdrager
    Undaunted

    Ik krijg het nog niet werkend, maar ik moet ook bekennen dat ik niet goed snap wat er nu gebeurd.

    In de interface builder kun je een “selector” aangeven en een “Sort Key”. Met de selector geef je de actie aan (toch?) en dat kan dan bijvoorbeeld de methode compare: zijn, en bij de Sort Key geef ik aan welke attribute er gesorteerd moet worden. Hoe ik dat naar code vertaal is me niet goed duidelijk.

    Hieronder quote ik een passage uit het boek van Aaron Hillegass, hij legt het als volgt uit:
    “The information that you added to the columns of the table is packed into an array of NSSortDescriptor object. A sort descriptor includes the key, a selector, and an indicator of wheteher data should be sorted into ascending or descending order. If you have an NSMutableArray of objects, you can use the following method to sort it:
    [code:1:b6b076dae4] – (void)sortUsingDescriptors:(NSArray *)sortDescriptors[/code:1:b6b076dae4]

    An optional table view dataSource method is triggered when the user clicks the header of a column with a sort descriptor:
    [code:1:b6b076dae4]-(void)tableView:(NSTableView *)tableView
    sortDescriptorsDidChange:(NSArray *)oldDescriptors[/code:1:b6b076dae4]

    Thus, if you have a mutable array that holds the information for a table view, you can implement the method like this:

    [code:1:b6b076dae4]- (void)tableView:(NSTableView *)tableView
    sortDescriptorsDidChange:(NSArray *)oldDescriptors
    {
    NSArray *newDescriptors = [tableView sortDescriptors];
    [myArray sortUsingDescriptors:newDescriptors];
    [tableView reloadData];
    }
    [/code:1:b6b076dae4]

    =========
    Ik zie nergens een methode die de Sort Key en / of selector toewijst. Het lijkt of bovenstaande code helemaal geen verandering te weeg brengt.

    Volgens bovenstaande claim zou je “didClickTableColumn” zelfs kunnen weglaten, wanneer de “sortUsingDescriptors” methode is gebruikt. Ik kom er met de helpfile niet uit hoe ik die gebruik. Kun je me uitleggen hoe dat werkt?

    Bijdrager
    mhrenes

    In je eerste post geef je aan om het allemaal zonder interface builder te willen doen.

    Als je een NSTableView object maakt dan moet je (zonder Interface Builder) ook alle code schrijven die de TableView functionaliteit geven.

    NSTableView heeft een datasource (bijvoorbeeld zoals in het beschreven voorbeeld uit het boek) en een delegate (ook net als in het boek).

    Interface Builder kan automatisch een deel van de code voor zijn rekening nemen. Als je het zonder interface builder wilt doen moet je natuurlijk zelf alle code schrijven.

    1. Je wilt dat de tabel sorteert afhankelijk van de header die de gebruiker aanklikt. Dat doe je door de delegate – (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn te implementeren. Hierin maak je een nieuwe sortDescriptor afhankelijjk van welke column er aangeklikt is. Vervolgens sorteer je je NSMutableArray met die sortDescriptor. Daarna laat je de tableview de data opnieuw laden (reloadData) en als het goed is is het dan gesorteerd.

    De selectors e.d. in Interface Builder heb je dus niet nodig want je implementeert het allemaal in je eigen code. De geciteerde alinea gaat over sortDescriptors en hoe die gebruikt worden als je alles via Interface Builder doet.

    Als je me je je code emailt die je tot dusver hebt kan ik er ook naar kijken.

    Inactief
    Anoniem

    Ik zou die delegates and datasources gewoon schrappen en gelijk met bindings aan de gang gaan… 8)

    Bijdrager
    mhrenes

    Dat is eenvoudiger maar daar ging het TS niet om.

    Bijdrager
    Undaunted

    Hey mhrenes, ik heb je een PM gestuurd, mogelijk heb j’m gemist. Zou je daar op willen reageren?

    Alvast bedankt!

    Bijdrager
    mhrenes
    ”Undaunted”

    Hey mhrenes, ik heb je een PM gestuurd, mogelijk heb j’m gemist. Zou je daar op willen reageren?

    Alvast bedankt!

    Ik heb je een PM gestuurd.

    Bijdrager
    Undaunted

    Thanks, zie mail:)

    Bijdrager
    mhrenes

    You have mail….:)

15 berichten aan het bekijken - 1 tot 15 (van in totaal 15)

Je moet ingelogd zijn om een reactie op dit onderwerp te kunnen geven.