IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

Comment rendre 'disabled' un menu Toplevel


Sujet :

Tkinter Python

  1. #1
    Membre régulier Avatar de Pierrot92320
    Homme Profil pro
    Ingénieur en retraite (électronique)
    Inscrit en
    Avril 2009
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur en retraite (électronique)
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2009
    Messages : 159
    Points : 119
    Points
    119
    Par défaut Comment rendre 'disabled' un menu Toplevel
    Bonjour

    J'essaie de reconstruire le menu présenté ici, mais en plaçant le menu comme un esclave de la fenêtre, et non comme un esclave d'un widget MenuButton. Pour cela j'ai repris l'architecture que m'a fait découvrir wiztricks :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    from tkinter import *
    showinfo =  messagebox.showinfo
     
    def activerClients():
        pass
     
    app = Tk()
     
    # Mise en place d'une barre de menu dans la fenêtre
    menuBar = Menu(app)
    app['menu'] = menuBar
     
    # Rubrique <Fichier>
    fic = Menu(menuBar)
    menuBar.add_cascade(label='Fichier', menu=fic, underline=0)
    fic.add_command(label='Effacer', underline=0,
                      command=lambda: showinfo('Effacer'))
    fic.add_command(label='Quitter', underline=0, command=app.quit)
     
    # Rubrique <Clients>
    cli = Menu(menuBar)
    menuBar.add_cascade(label='Client', menu=cli, underline=0)
    cli.add_command(label="Animaux", underline=0,
                      command=lambda: showinfo("Animaux"))
    cli.add_command(label="Maitres", underline=0,
                      command=lambda: showinfo('Maitres'))
     
    # Rubrique <Options>
    actCli = IntVar()       # booléen indiquant la valeur DISABLED ou NORMAL 
                            # du paramètre 'state' du menu <clients>
    opt = Menu(menuBar)
    menuBar.add_cascade(label='Options', menu=opt, underline=0)
    opt.add_checkbutton(label='activer/désactiver Clients',
                        command=activerClients, variable=actCli)
     
    app.mainloop()
    app.destroy()
    (ce programme permet d'utiliser les raccourcis clavier en appuyant sur la touche tab)
    Mon problème est que je n'arrive pas à faire fonctionner la rubrique <Options> du menu pour activer/désactiver la rubrique <Clients>. Auriez-vous une idée ?

    Merci pour votre aide.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Salut,

    C'est possible avec .entryconfigure.
    Il faut lire la documentation Tk native pour le mettre en œuvre.
    Le piège est dans la gestion des "index".
    Et je n'ai pas le temps d'essayer de vous rendre la chose plus digeste, pour l'instant.

    - W

  3. #3
    Membre régulier Avatar de Pierrot92320
    Homme Profil pro
    Ingénieur en retraite (électronique)
    Inscrit en
    Avril 2009
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur en retraite (électronique)
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2009
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Merci wiztricks. Grâce à cette info, et avec beaucoup de tâtonnements je suis arrivé au code suivant (je n'ai modifié que la fonction activerClients) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    from tkinter import *
    showinfo =  messagebox.showinfo
     
    def activerClients():
        p = actCli.get()
        menuBar.entryconfigure(2, state= p and DISABLED or NORMAL)
     
    app = Tk()
     
    # Mise en place d'une barre de menu dans la fenêtre
    menuBar = Menu(app)
    app['menu'] = menuBar
     
    # Rubrique <Fichier>
    fic = Menu(menuBar)
    menuBar.add_cascade(label='Fichier', menu=fic, underline=0)
    fic.add_command(label='Effacer', underline=0,
                      command=lambda: showinfo('Effacer'))
    fic.add_command(label='Quitter', underline=0, command=app.quit)
     
    # Rubrique <Clients>
    cli = Menu(menuBar)
    menuBar.add_cascade(label='Client', menu=cli, underline=0)
    cli.add_command(label="Animaux", underline=0,
                      command=lambda: showinfo("Animaux"))
    cli.add_command(label="Maitres", underline=0,
                      command=lambda: showinfo('Maitres'))
     
    # Rubrique <Options>
    actCli = IntVar()       # booléen indiquant la valeur DISABLED ou NORMAL 
                            # du paramètre 'state' du menu <clients>
    opt = Menu(menuBar)
    menuBar.add_cascade(label='Options', menu=opt, underline=0)
    opt.add_checkbutton(label='activer/désactiver Clients',
                        command=activerClients, variable=actCli)
     
    app.mainloop()
    app.destroy()
    J'ai l'impression que les index commencent à 1. Pourtant la valeur 0 est acceptée mais ça n'a aucun effet sur le fonctionnement du menu.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Salut,

    More clever:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    #! -*- coding:utf-8 -*-
     
    import tkinter as tk
    from tkinter.constants import *
    from tkinter import messagebox
     
    showinfo =  messagebox.showinfo
     
    STATES = [ DISABLED, NORMAL ]
     
    def do_toggle(entry):
     
        menu = entry.master
        name = str(entry)
     
        last = menu.index('last')
        if last is None:
            return 
     
        for ix in range(last):
            if menu.type(ix) == 'cascade':
                nm = menu.entrycget(ix, 'menu')
                if nm == name:
                    state = menu.entrycget(ix, 'state')
                    assert state in STATES, 'unexpected state: %s' % state
                    iy = (STATES.index(state) + 1) % len(STATES)
                    ns =  STATES[iy]
                    menu.entryconfigure(ix, state=ns)
     
     
    def create_menu(app):
     
        menu = tk.Menu(app)
        app['menu'] = menu
     
        # Rubrique <Fichier>
        mm = tk.Menu(menu)
        menu.add_cascade(label='Fichier', menu=mm, underline=0)
        mm.add_command(label='Effacer', underline=0,
                          command=lambda: showinfo('Effacer'))
        mm.add_command(label='Quitter', underline=0, command=app.quit)
     
        # Rubrique <Clients>
        clients = mm = tk.Menu(menu)
        menu.add_cascade(label='Client', menu=mm, underline=0)
        mm.add_command(label="Animaux", underline=0,
                          command=lambda: showinfo("Animaux"))
        mm.add_command(label="Maitres", underline=0,
                          command=lambda: showinfo('Maitres'))
     
        menu.add_command(label='Toggle',
                         command=lambda entry=clients: do_toggle(entry))
     
    if __name__ == '__main__': 
        app = tk.Tk()
        create_menu(app)
        app.mainloop()
    Pour retrouver l'index du s/menu "clients" dans "menu", je poole les index via menu.index(ix):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        ix = 1
        while ix == menu.index(ix):
              ... boulot ...
              ix += 1
    Le boulot est de récupérer le nom: nm = menu.entrycget(ix, 'menu'), un "path" - avec des "." dedans -.
    name = str(entry) avait récupéré le "path" de l'entry.
    Lorsque nm == name, le bon index est dans ix.

    - W
    edit: j'ai retravaille le code pour supprimer l'IntVar.
    Comme on va avoir autre chose que des add_cascade, il faut tester le menu.type.
    edit2: j'ai retravaille le pool en récupérant le nombre d’entrées via menu.index('last')

  5. #5
    Membre régulier Avatar de Pierrot92320
    Homme Profil pro
    Ingénieur en retraite (électronique)
    Inscrit en
    Avril 2009
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur en retraite (électronique)
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2009
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Merci beaucoup wiztricks pour cette mine de renseignements.

    Si ce n'est pas abuser, pourrais-tu m'éclairer sur la méthode Menu.index() ? J'ai vu dans la doc que si on met un label en argument ça renvoie l'index du sous_menu correspondant. Par exemple menu.index('Client') en ligne 51 renvoie 2 et menu.index('Toggle') renvoie 3.

    Mais à quoi cela sert-il de mettre un entier en argument, juste à faire des tests ? La valeur 0 est acceptée, que représente-t-elle ?

    Merci pour ton aide.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Salut,

    Citation Envoyé par Pierrot92320 Voir le message
    Si ce n'est pas abuser, pourrais-tu m'éclairer sur la méthode Menu.index() ? J'ai vu dans la doc que si on met un label en argument ça renvoie l'index du sous_menu correspondant. Par exemple menu.index('Client') en ligne 51 renvoie 2 et menu.index('Toggle') renvoie 3.
    Dans quelle documentation avez vous trouve ça?

    Ça fonctionne parce que ça passe par une interface tk::MenuFindName.
    Elle est utilisée dans les tests de Tk mais elle n'est pas (a ma connaissance) supportée.

    Code tcl : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    # ::tk::MenuFindName --
    # Given a menu and a text string, return the index of the menu entry
    # that displays the string as its label.  If there is no such entry,
    # return an empty string.  This procedure is tricky because some names
    # like "active" have a special meaning in menu commands, so we can't
    # always use the "index" widget command.
    #
    # Arguments:
    # menu -		Name of the menu widget.
    # s -			String to look for.
     
    proc ::tk::MenuFindName {menu s} {
        set i ""
        if {![regexp {^active$|^last$|^none$|^[0-9]|^@} $s]} {
    	catch {set i [$menu index $s]}
    	return $i
        }
        set last [$menu index last]
        if {$last eq "none"} {
    	return
        }
        for {set i 0} {$i <= $last} {incr i} {
    	if {![catch {$menu entrycget $i -label} label]} {
    	    if {$label eq $s} {
    		return $i
    	    }
    	}
        }
        return ""
    }


    Mais à quoi cela sert-il de mettre un entier en argument, juste à faire des tests ? La valeur 0 est acceptée, que représente-t-elle ?
    Les nombres entiers sont l'interface documentée.
    Le 0 correspond au "tearoff" qui est "on", par défaut.
    J'ai corrige mon code. De toute façons, je filtre les entrées "cascade".

    - W

  7. #7
    Membre régulier Avatar de Pierrot92320
    Homme Profil pro
    Ingénieur en retraite (électronique)
    Inscrit en
    Avril 2009
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur en retraite (électronique)
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2009
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Dans quelle documentation avez vous trouve ça?
    Je l'ai trouvé ici.

    Mais si cette utilisation n'est pas permise, quelle est l'utilité de la méthode index ? Elle ne sert qu'à tester l'étendue des valeurs de l'index (comme vous l'avez fait dans cet exemple) ?

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Citation Envoyé par Pierrot92320 Voir le message
    Mais si cette utilisation n'est pas permise, quelle est l'utilité de la méthode index ? Elle ne sert qu'à tester l'étendue des valeurs de l'index (comme vous l'avez fait dans cet exemple) ?
    C'est parce que RTFM

    Option and the args determine the exact behavior of the command.

    Many of the widget commands for a menu take as one argument an indicator of which entry of the menu to operate on. These indicators are called indexes and may be specified in any of the following forms:

    number
    Specifies the entry numerically, where 0 corresponds to the top-most entry of the menu, 1 to the entry below it, and so on.

    ...

    pattern
    If the index does not satisfy one of the above forms then this form is used. Pattern is pattern-matched against the label of each entry in the menu, in order from the top down, until a matching entry is found. The rules of Tcl_StringMatch are used.
    Et oui, parfois je lis aussi la doc. avec les pieds.

    - W

  9. #9
    Membre régulier Avatar de Pierrot92320
    Homme Profil pro
    Ingénieur en retraite (électronique)
    Inscrit en
    Avril 2009
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Ingénieur en retraite (électronique)
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2009
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Aurais-je réussi à te prendre en défaut J'avoue que ça me réconforte ! Bien que ce soit un pur coup de chance ...

    J'ai relu ce passage que tu cites dans la doc. J'avoue qu'il faut être balèze pour comprendre ... chapeau.

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 313
    Points : 36 819
    Points
    36 819
    Par défaut
    Citation Envoyé par Pierrot92320 Voir le message
    J'ai relu ce passage que tu cites dans la doc. J'avoue qu'il faut être balèze pour comprendre ... chapeau.
    En fait, j'ai lu les sources. Je me suis plante dans ma première lecture. Il fallait descendre dans le module C jusqu’à la fonction TkGetMenuIndex qui est déroulée derrière.
    Après la question était de comprendre pourquoi ce machin la n’était pas plus "lisible" dans la documentation.
    Quand on y croit, on le trouve et c'est clair . Sinon on peut lire ça 10 fois sans comprendre.

    Aurais-je réussi à te prendre en défaut. J'avoue que ça me réconforte ! Bien que ce soit un pur coup de chance ...
    Yup. j'avoue! Ma première lecture des sources de Tk fut un peu trop superficielle je me suis fait avoir par le découpage entre la partie scripte et le code C.

    Finalement, le code devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #! -*- coding:utf-8 -*-
     
    import tkinter as tk
    from tkinter.constants import *
    from tkinter import messagebox
     
    showinfo =  messagebox.showinfo
    STATES = [ DISABLED, NORMAL ]
    TclError = tk._tkinter.TclError
     
    def do_toggle(menu, label):
     
        try:
            ix = menu.index(label)
        except TclError:
            return
     
        state = menu.entrycget(ix, 'state')
        assert state in STATES, 'unexpected state: %s' % state
        iy = (STATES.index(state) + 1) % len(STATES)
        ns =  STATES[iy]
        menu.entryconfigure(ix, state=ns)
     
     
     
    def create_menu(app):
     
        menu = tk.Menu(app)
        app['menu'] = menu
     
        # Rubrique <Fichier>
        mm = tk.Menu(menu)
        menu.add_cascade(label='Fichier', menu=mm, underline=0)
        mm.add_command(label='Effacer', underline=0,
                          command=lambda: showinfo('Effacer'))
        mm.add_command(label='Quitter', underline=0, command=app.quit)
     
        # Rubrique <Clients>
        mm = tk.Menu(menu)
        menu.add_cascade(label='Client', menu=mm, underline=0)
        mm.add_command(label="Animaux", underline=0,
                          command=lambda: showinfo("Animaux"))
        mm.add_command(label="Maitres", underline=0,
                          command=lambda: showinfo('Maitres'))
     
        menu.add_command(label='Toggle',
             command=lambda menu=menu, label='Client': do_toggle(menu, label))
     
    if __name__ == '__main__': 
        app = tk.Tk()
        create_menu(app)
        app.mainloop()
    - W

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment rendre mon menu sup flottant ?
    Par adn505 dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 25/02/2010, 14h59
  2. [Joomla!] comment rendre un menu visible mais non cliquable dans joomla
    Par tcone dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 5
    Dernier message: 08/02/2007, 23h25
  3. [VB.Net] Comment rendre les élements du menu shared
    Par Pedro Varela dans le forum Windows Forms
    Réponses: 2
    Dernier message: 12/10/2006, 15h13
  4. Comment rendre un menu transparent?
    Par casho dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 22/09/2006, 15h27
  5. Comment rendre flottant un menu.
    Par fmoriet dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 07/10/2004, 11h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo