Différer l'ouverture d'un PopUpMenu

Bonjour,


 


J'expérimente le même problème que celui rencontré (en 2005) ici:


http://lists.apple.com/archives/cocoa-dev/2005/Nov/msg02088.html


 


Il n'a malheureusement pas reçu de réponse en huit ans. En deux mots:


 


Quand vous placez un NSPopUpButtonCell dans une NSTableView, le popUp s'ouvre AVANT que la sélection dans la tableView ait changé.


 


Si vous faites dépendre le contenu du popUp de la sélection de la ligne dans la tableView, vous vous retrouvez avec un temps de retard.


 


Solution 1: différer l'ouverture du popUp avec un block qui appelle [super] quelques nanosecondes plus tard. Mais là  je sèche parce que je ne sais pas quelle méthode surcharger.


 


Solution 2: farcir le popUp avec d'autres bindings que ceux que j'utilise actuellement (le popUp contient le NSSet de l'entité sélectionnée dans la table, je passe donc par un contrôleur différent de celui de la table et je branche son content set à  myTable.selection.theSet.


 


Voyez-vous autre chose à  faire?


 


Réponses

  • devulderdevulder Membre
    décembre 2013 modifié #2

    Bonjour,


     


    Je ne vois pas le souci, que la ligne soit déjà  sélectionner ou pas il faudra remplir le popupmenu avec les données en conséquence !


     


    Une alternative serait que quand l'utilisateur clique sur le popupmenu alors qu'il n'est pas sélectionner alors tu la sélectionnes et tu annule l'apparition du menu ?


  • berfisberfis Membre
    décembre 2013 modifié #3

    devulder,


     


    Le fait est que lorsque l'utilisateur clique sur le pop menu de la ligne " mettons, 3 " alors que la ligne 2 est sélectionnée, le pop menu affiche le contenu propre à  la deux, puis la ligne 3 est sélectionnée. Si je reclique au même endroit, le contenu du pop up sera correct.


     


    Le problème est que le menu est bindé sur la sélection de la table. Or cette sélection n'a pas encore été mise à  jour (probablement que le pop menu intercepte l'event et réagit immédiatement, puis rend la main et la tableView change alors la sélection).


     


    Pour répondre à  ta question, c'est partiellement ça, sauf que je ne veux pas annuler l'apparition du menu mais la différer (disons la reporter jusqu'à  la fin de la boucle d'événement en cours). ça je sais faire, mais je ne vois pas quelle méthode différer au juste, ni même si c'est possible...


  • vu sur le net, cette méthode pour afficher ton propre menu et t'affranchir des bindings


     


    une possible piste ?



    - (void) mouseDown:(NSEvent *)theEvent
    {
    NSPopUpButtonCell *cell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
    NSMenu *tempMenu = [[[NSMenu alloc] init] autorelease];

    [tempMenu addItemWithTitle:@first item action:NULL keyEquivalent:@""];
    [tempMenu addItemWithTitle:@second item action:NULL keyEquivalent:@""];
    [tempMenu addItemWithTitle:@third item action:NULL keyEquivalent:@""];

    NSRect viewBounds = [self bounds];

    [cell setMenu:tempMenu];
    [cell performClickWithFrame:viewBounds inView:self];
    [cell release];
    }
  • On doit pouvoir faire la même chose dans la méthode déléguée:


     


    - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)col row:(NSInteger)rowIndex

  • yoannyoann Membre
    décembre 2013 modifié #6

    Les valeurs de bind de la tableView ne sont pas selection (qui représente la selection) mais arrangedObjects qui représente les lignes.


     


    Relis la doc de binding sur les tableView.


     


    Sors nous un sample code si tu n'y arrive pas.


  • berfisberfis Membre
    décembre 2013 modifié #7

    Bon je reprends.


     


    @mpergand et devulder:


    Je pense qu'on peut s'en tirer sans la datasource


     


    @yoann:


    Ce n'est pas le contrôleur de la NSTableView que je bonde à  .selection, mais le contrôleur du popMenu. Si je binde la colonne à  myTable.arrangedObjects.entitesB, j'obtiens une bouillie (un NSSet brut) qui n'entre pas dans un popUpMenuCell... ou du moins, je n'arrive pas à  l'y faire tenir. Je définis donc un contrôleur séparé, dont je binde le contentSet à  l'entité A sélectionnée, puis je binde le popUp à  ce contrôleur.


     


    Alors, où est-ce que je me goure?


  • Il ne faut pas travailler avec NSSet sur les binding, ce n'est pas fait pour.


     


    Tiens, voilà  un exemple fonctionnel si j'ai bien compris ce que tu cherche à  faire.


     


  • Merci yoann d'avoir pris le temps de rédiger ce petit exemple !


     


    (Un bémol pour le "fonctionnel", j'obtiens



    2013-12-17 01:13:53.289 Demo[11132:303] An uncaught exception was raised
    2013-12-17 01:13:53.290 Demo[11132:303] Error setting value for key path selectedIndex of object {
    authorizedValues = (
    "Valeur 2-1",
    "Valeur 2-2",
    "Valeur 2-3"
    );
    name = "Ligne 2";
    selectedIndex = 1;
    } (from bound object <NSTableColumn: 0x610000092840> identifier: (null)): [<__NSDictionaryI 0x60800006ef00> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key selectedIndex.


    quand je touche au popup, mais bon...)


     



     


    Il ne faut pas travailler avec NSSet sur les binding, ce n'est pas fait pour.



     


    Oui et non... Après tout, il y a bien un "content set" possible dans les bindings d'un contrôleur. Le seul souci, c'est que le NSSet est désordonné, mais il a d'autres avantages, comme l'unicité des contenus. L'ordre ne m'intéresse pas dans ce cas particulier, et si jamais il doit y avoir un NSOrderedSet (jamais essayé).


     


    Une précision: mon code produit exactement le résultat attendu, il n'y a que cette histoire de popup qui doit bénéficier d'une priorité de premier ordre pour passer devant tout le monde comme ça. Probablement voulu par Apple pour garantir la réactivité de l'interface...




  • Merci yoann d'avoir pris le temps de rédiger ce petit exemple !


     


    (Un bémol pour le "fonctionnel", j'obtiens



    2013-12-17 01:13:53.289 Demo[11132:303] An uncaught exception was raised
    2013-12-17 01:13:53.290 Demo[11132:303] Error setting value for key path selectedIndex of object {
    authorizedValues = (
    "Valeur 2-1",
    "Valeur 2-2",
    "Valeur 2-3"
    );
    name = "Ligne 2";
    selectedIndex = 1;
    } (from bound object <NSTableColumn: 0x610000092840> identifier: (null)): [<__NSDictionaryI 0x60800006ef00> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key selectedIndex.


    quand je touche au popup, mais bon...)




     


     


    Petit erreur du fait de l'utilisation de la nouvelle syntaxe des dictionnaires. Les item représentant les lignes n'étaient pas mutable. Corrige de cette manière :



    for (int i = 0; i < 5; i++) {
    [data addObject:[@{
    @name: [NSString stringWithFormat:@Ligne %d, i],
    @selectedIndex: @1,
    @authorizedValues: @[;
    [NSString stringWithFormat:@Valeur %d-1, i],
    [NSString stringWithFormat:@Valeur %d-2, i],
    [NSString stringWithFormat:@Valeur %d-3, i],
    ],
    } mutableCopy]];
    }


     


     




    Oui et non... Après tout, il y a bien un "content set" possible dans les bindings d'un contrôleur. Le seul souci, c'est que le NSSet est désordonné, mais il a d'autres avantages, comme l'unicité des contenus. L'ordre ne m'intéresse pas dans ce cas particulier, et si jamais il doit y avoir un NSOrderedSet (jamais essayé).


     


    Une précision: mon code produit exactement le résultat attendu, il n'y a que cette histoire de popup qui doit bénéficier d'une priorité de premier ordre pour passer devant tout le monde comme ça. Probablement voulu par Apple pour garantir la réactivité de l'interface...




     


    Oui mais non. Je te parle d'expérience ici. Les binding s'arrange assez mal des NSSet. Et l'ordonnancement de ces données est obligatoire pour l'affichage.


     


    Si tu tiens absolument à  garder un NSSet en source il faut le convertir avec un valueTransformer en array pour les binding et faire particulièrement attention à  la gestion de l'item sélectionné.


     


    Ton code produit exactement le résultat attendu sauf quand il ne le fait pas, donc il ne marche pas. Le problème est que tu t'y prend mal pour faire marcher la chose, c'est tout.


     


    Fait les choses comme je te le conseil et tu verra que ça marchera.



  • Le problème est que tu t'y prend mal pour faire marcher la chose, c'est tout.




     


    Ah ça... Je n'aurais pas ouvert ce sujet sinon ;)


     


    Je vais reprendre tout ça à  tête reposée en adaptant ton exemple (le tien travaille avec un array unique, moi j'en ai deux à  gérer).


     


    P.S. Mon popUp ne fait qu'indiquer la liste des entités B auxquelles appartient l'entité A sélectionnée, et non d'en sélectionner une (de toute façon c'est une relation plusieurs-à -plusieurs).


     


    Mais il me vient à  l'esprit en relisant tout ça qu'en fait il serait peut-être plus conforme, HIG parlant, d'utiliser un popOver (le problème c'est que je devrais le mettre à  la bonne taille moi-même pour afficher la liste). Sans compter que je n'aurais plus à  me battre avec cette fichue popUpMenuCell...


     


    Affaire à  suivre.

Connectez-vous ou Inscrivez-vous pour répondre.