NSOutlineView avec plusieurs menus contextuels

Bonjour,

Je cherche à afficher un menu contextuel différent en fonction de l'élément d'un NSOutlineView sur lequel un clic droit est effectué.
J'utilise un NSTreeController dans lequel j'ai bien référencé children et leaf
Si leaf = false c'est un dossier, si leaf = true c'est "autre chose"
Si il s'agit d'un dossier je voudrais afficher un menu contextuel, si c'est "autre chose" afficher un autre menu contextuel
J'ai créé les 2 menus dans le Storyboard
Mais comme grand débutant je n'ai pas trouvé comme faire.

Merci par avance

Réponses

  • yannSyannS Membre

    J'ai un peu avancé.
    J'ai compris qu'il fallait sous-classer NSOutlineView et surcharger menu(for:)
    Ce que j'ai fait :

    import Cocoa
    @objc(Profils)
    class Profils: NSOutlineView {
    
    
        override func draw(_ dirtyRect: NSRect) {
            super.draw(dirtyRect)
    
            // Drawing code here.
        }
    
    
    
        override func menu(for event: NSEvent) -> NSMenu? {
            let point = self.convert(event.locationInWindow, from: nil)
            let row = self.row(at: point)
            let item = (self.item(atRow: row) as! NSTreeNode).representedObject as! Arborescence
    
            if item.leaf == true{
                return nil
            }
            else {
                return nil
            }
        }
    
    
    
    }
    

    Actuellement aucun menu n'est affiché
    Les menus sont dans le storyboard et les outlets dans le ViewController
    Comment faire pour y accéder et les retourner depuis cette classe ?

  • yannSyannS Membre

    J'ai trouvé une solution que voici, il y a peut-être mieux

    override func menu(for event: NSEvent) -> NSMenu? {
            let point = self.convert(event.locationInWindow, from: nil)
            let row = self.row(at: point)
            let item = (self.item(atRow: row) as! NSTreeNode).representedObject as! Arborescence
    
            let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
            let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "VC1")) as! ViewController
    
            if item.leaf == true{
                return viewController.menuContextProfil
            }
            else {
                return viewController.menuContextDossier
            }
        }
    
  • yannSyannS Membre

    ça semble pas terrible comme solution, car le viewController déclaré ne permet pas de "pointer" sur celui de l'application.
    Pour forcer la sélection dans le NSTreeController, j'ai ajouté

    import Cocoa
    @objc(Profils)
    class Profils: NSOutlineView {
    
        var treeController = NSTreeController()   //<-
    

    Dans le viewController je passe le NSTreeController

    override func viewDidLoad() {
            super.viewDidLoad()
    
            // Do any additional setup after loading the view.
    
            let racine = Arborescence(id: "65535", pid: "", nomProfil: "", text: "Racine")
            profilsTreeController.addObject(racine)
            profilsOutlineView.treeController = profilsTreeController
    
        }
    

    Alors j'arrive dès que l'on fait un clic droit à sélectionner le node et à afficher le bon menu

    override func menu(for event: NSEvent) -> NSMenu? {
            let point = self.convert(event.locationInWindow, from: nil)
            let row = self.row(at: point)
            let node = self.item(atRow: row) as! NSTreeNode
            let item = node.representedObject as! Arborescence
    
            let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
            let ctrl = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "VC1")) as! ViewController
    
            //Permet la sélection de l'item dans le NSTreeController quand le clic-droit est effectué
            treeController.setSelectionIndexPath(node.indexPath)
    
            if item.leaf == true{
                return ctrl.menuContextProfil
            }
            else {
                return ctrl.menuContextDossier
            }
    
        }
    

    Mais au autre défaut est apparu.

    Les items de mes menus sont attachés à des actions qui sont dans le viewcontroller
    Pou l'exemple : récupération de la sélection et affichage du text

    @IBAction func creerSousDossier(_ sender: NSMenuItem) {
    
    
            if self.profilsTreeController.selectedNodes.count>0{
                let node = self.profilsTreeController.selectedObjects[0] as! Arborescence
                print(node.text)
            }
    
        }
    

    Problème quand le code est exécuté il n'y a pas de sélection, il semble bien que le NSTreecontroller ne soit pas celui du viewcontroller de l'appli (je m'exprime certainement très mal)

    Je dois certainement mal m'y prendre, si quelqu'un à une idée...

  • yannSyannS Membre
    25 févr. modifié #5

    Une solution, j'ai simplement appliqué celle déjà utilisée pour le NSTreeController

        import Cocoa
        @objc(ProfilsClass)
        class ProfilsClass: NSOutlineView  {
    
            var treeController = NSTreeController()
            var menuContextProfil = NSMenu()
            var menuContextDossier = NSMenu()
    .....
    
        override func menu(for event: NSEvent) -> NSMenu? {
                let point = self.convert(event.locationInWindow, from: nil)
                let row = self.row(at: point)
                let node = self.item(atRow: row) as! NSTreeNode
                let item = node.representedObject as! Arborescence
    
    
                //Permet la sélection de l'item dans le NSTreeController quand le clic-droit est effectué
                treeController.setSelectionIndexPath(node.indexPath)
    
                if item.leaf == true{
                    return menuContextProfil
                }
                else {
                    return menuContextDossier
                }
    
            }
    

    coté viewcontroller

    class ViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
    
        @IBOutlet weak var profilsTreeController: NSTreeController!
        @IBOutlet weak var profilsOutlineView: ProfilsClass!
        @IBOutlet weak var menuContextProfil: NSMenu!
        @IBOutlet weak var menuContextDossier: NSMenu!
    
    .....
    
    
        override func viewDidLoad() {
                super.viewDidLoad()
    
                // Do any additional setup after loading the view.
    
                let racine = Arborescence(id: "65535", pid: "", nomProfil: "", text: "Racine")
                profilsTreeController.addObject(racine)
                profilsOutlineView.treeController = profilsTreeController
                profilsOutlineView.menuContextProfil = menuContextProfil
                profilsOutlineView.menuContextDossier = menuContextDossier
    
            }
    
Connectez-vous ou Inscrivez-vous pour répondre.