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 :

widget text: récupérer le texte associé à un tag. [Python 2.X]


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2016
    Messages : 13
    Par défaut widget text: récupérer le texte associé à un tag.
    Bonjour,

    Je travail sur une modeste interface graphique qui doit lire un fichier texte. Fichier dans lequel se trouve des URL auxquelles j'applique un style et une commande webbrowser pour m'ouvrir la page. Cela fonctionne mais mon interface ne retiens que la dernière adresse. Pour tenter de corriger ce problème j'ai mis chaque url dans une liste pour que webbrowser m'ouvre les liens les uns après les autres mais ça fonctionne encore moins puisqu'il me dresse un IndexError : list out of range

    Voilà le code :
    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
    58
    59
    60
    61
     
    import webbrowser
    import Tkinter as tk
    from Tkinter import *
    from ScrolledText import *
     
    def Liens():
    	links = []
     
    	for line in news : 
    		if "http" in line :
    			links.append(line)
     
    	return links
     
     
    #Ouverture du fichier à consulter
    newsletter = open("logs/NewsletterLog.txt", "r") 
    news=newsletter.readlines()
     
    link=Liens()
     
    #création de la fenêtre de visualisation de la newsletter TOTEM
    fenetre = tk.Tk()
    fenetre.title("TOTEM")
     
    contenu = tk.Label (fenetre, text="Semaine Test")
    contenu.pack()
     
    #Création de la zone Texte 
     
    texte = ScrolledText(fenetre, width = 150, height = 35, font = "Arial 10", relief = "groove") 
    i=0
     
    for line in news : 
    	if "http" in line :
    		texte.insert(tk.END, line , 1)
    		texte.tag_config(1, foreground="blue", underline=1)
    		texte.tag_bind(1, '<Button-1>', lambda e: webbrowser.open(link[i], new=0, autoraise=True))
    		texte.pack()
    		i+=1
     
    	else : 
    		texte.insert(tk.END, line)
    		texte.pack()
     
    #texte.pack() 
     
    #Ecriture des données
    texte.config(state = NORMAL)    #Permettre l'écriture 
    texte.insert("1.0", line)       #Gestion de l'insertin des lignes  #1 = 1ere ligne  0 = 1er caractere de la ligne 
    texte.config(state = DISABLED)  #Interdire les modifications 
     
     
    #bouton de sortie
    tk.Button(fenetre, text="Quitter", command=fenetre.destroy).pack()
     
    fenetre.mainloop()
     
    #fermeture du fichier
    newsletter.close()
    Bon je suis sûr que c'est sans doute assez bête comme erreur mais je ne vois pas comment la corriger.

    Merci

  2. #2
    Membre éclairé
    Homme Profil pro
    Amateur
    Inscrit en
    Juin 2015
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Amateur
    Secteur : Transports

    Informations forums :
    Inscription : Juin 2015
    Messages : 52
    Par défaut
    Bonjour,

    Le problème vient du fait que ta fonction lambda​ en ligne 39 fait appel à la variable locale i. Cependant Python ne va évaluer la valeur de cette variable que lorsque la fonction sera appelée, et non à la définition. Donc la boucle sera terminée depuis longtemps et i aura comme valeur le dernier élément sur lequel tu as itéré.

    Afin de palier à ce problème, tu peux forcer la valeur lors de la définition en passant un keyword argument additionnel à la lambda.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    texte.tag_bind(1, '<Button-1>', lambda e, i=i: webbrowser.open(link[i], new=0, autoraise=True))
    Hormis ce problème, ton code pourrait être amélioré de plusieurs manières:
    • L'ouverture du fichier devrait se faire au début du code et ensuite le fermer. Il est inutile de le laisser ouvert alors qu'on a lu ce qu'il contenait. On préférera aussi l'utilisation d'un context manager
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      with open("logs/NewsletterLog.txt", "r") as newsletter:
          news = newsletter.readlines()
      # Plus besoin d'appeler newsletter.close() c'est fait d'office à la sortie du with
    • La lecture des lignes avec readlines() a comme désagrément que les retours à la ligne (\n) restent à la fin des chaînes de caractères. On préfère lire tout le fichier d'un coup et ensuite utiliser splitlines():
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      with open("logs/NewsletterLog.txt", "r") as newsletter:
          news = newsletter.read()
          news = news.splitlines()
    • Ta fonction Liens() a besoin de la liste des lignes contenue dans ton fichier. Pourquoi ne pas lui passer en argument, plutôt qu'accéder à cette liste car elle est dans l'espace globale. Ca rendra cette fonction ré-utilisable.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      def liens(lines):    
          links = []
          for line in lines: 
              if line.startswith("http"):
                  links.append(line)
       
          return links
       
       
      # Ou bien
       
       
      def liens(lines):
          return [line for line in lines if line.startswith("http")]
      Note que j'ai renommé la fonction avec une minuscule, comme le préconise la PEP8. J'ai aussi utilisé la méthode startswith() des chaînes de caractère, car j'imagine que ça doit commencer par http et non se trouver n'importe où dans la ligne. J'ai mis en option une autre définition de cette fonction en utilisant les listes en intention.

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Salut,

    Citation Envoyé par SidereusNuncius Voir le message
    Cela fonctionne mais mon interface ne retiens que la dernière adresse. Pour tenter de corriger ce problème j'ai mis chaque url dans une liste pour que webbrowser m'ouvre les liens les uns après les autres mais ça fonctionne encore moins puisqu'il me dresse un IndexError : list out of range
    En lisant votre code, je ne comprends pas pourquoi "IndexError" mais c'est "cosmétique" car votre truc ne marchera jamais.
    Le widget Text est un des widgets des plus compliqués, bien plus compliqué que Canvas (et c'est pas la faute de Tk, c'est comme çà depuis son invention dans les années 80s).
    La notion de "tag" paraît simple: vous créez une étiquette à laquelle vous associez des propriétés et tous les morceaux de texte auxquels aura été associé ce tag auront les propriétés associées. Cela dit, relisons votre code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    		texte.insert(tk.END, line , 1)
    		texte.tag_config(1, foreground="blue", underline=1)
    		texte.tag_bind(1, '<Button-1>', lambda e: webbrowser.open(link[i], new=0, autoraise=True))
    Votre tag s'appelle "1". Vous lui associez des propriétés, puis l'action sur B-1 déclenchera un callback.
    Itération suivante, au cas ou Tk serait sourd, vous associez les mêmes propriétés mais l'action B-1 est associée à un autre callback...
    Au bout du bout, l'action sur B-1 déclenchera le dernier callback<period>.

    => On fait les .tag_XXX une seule fois et on se contente de "taguer" le texte correspondant.
    Je comprends que cela ne vous arrange pas car vous souhaiteriez récupérer l'URL sur laquelle on vient de cliquer.
    En fait, il faut récupérer la position à partir de le texte avec le tag qui englobe cette position, puis... mais c'est beaucoup plus sportif.

    Un truc "crade" qui devrait marcher vite fait est de remplacer "1" par "i":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    		texte.insert(tk.END, line , i)
    		texte.tag_config(i, foreground="blue", underline=1)
    		texte.tag_bind(i, '<Button-1>', lambda e: webbrowser.open(link[i], new=0, autoraise=True))
    autant de tags que de lignes qui contiennent "http" et donc autant de callbacks différents.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2016
    Messages : 13
    Par défaut
    Merci wiztricks,

    Même si c'est un peu "sale" ça fonctionne bien donc je vais m'en contenter.

    J'avais posté un autre message où je remerciai Dan mais un titre "malheureux" dans la newsletter que j'avais donné en exemple pour la mise en forme a fait que ça a atterris dans la case censure mais merci quand même Dan.

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Citation Envoyé par SidereusNuncius Voir le message
    Merci wiztricks,

    Même si c'est un peu "sale" ça fonctionne bien donc je vais m'en contenter.
    Normalement, quand vous vous lancez à coder des choses exotiques, il est bon de faire un petit exemple pour voir comment vous allez bien pouvoir le faire fonctionner(*). En quelques lignes (que je n'ai pas eu le temps de coder plus tot):

    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
    import tkinter as tk
     
    text = tk.Text()
    for x in range(10):
        text.insert('end', 'aaa * ', '', 'bbb-%d' % x, 'mytag', ' * aaa\n', '')
    text.pack()
     
    def on_click(e):
        text_range = text.tag_prevrange('mytag', "@%d,%d"%(e.x,e.y))
        print ('/', text.get(*text_range), '/')
     
    text.tag_config('mytag', foreground="blue", underline=1)
    text.tag_bind('mytag', '<Button-1>', on_click)
     
    tk.mainloop()
    Il suffit de le faire tourner pour comprendre ce que çà fait.
    (*) Comprendre comment faire fonctionner le widget texte sur un exemple simple plutôt que s'accrocher au texte que vous voulez traiter rend la question plus claire (et les réponses plus faciles à utiliser pour tout le monde) et pas besoin de savoir ce que contient votre texte (ce qui évite aussi la censure).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

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

Discussions similaires

  1. [XL-2010] Remplacer une partie des liens hypertextes
    Par GADENSEB dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 21/05/2014, 15h24
  2. [XL-2007] Connexion à un fichier pour alimenter une BD en liens hypertextes
    Par MouM38 dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 05/10/2010, 22h36
  3. [E-07] Comment créer une liste de liens hypertextes ?
    Par xtremlimit dans le forum Excel
    Réponses: 3
    Dernier message: 11/01/2009, 21h09
  4. Réponses: 2
    Dernier message: 28/04/2008, 23h58
  5. [Excel] Insérer une série de liens hypertextes
    Par PedroBD dans le forum Excel
    Réponses: 2
    Dernier message: 15/11/2006, 09h38

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