banniere.png

Exercice 07 - Tkinter, recherche d'un texte dans des fichiers en tâche de fond

#!/usr/bin/python
# -*- coding: ISO-8859-15 -*-
from os import walk
from re import compile, findall
from threading import Thread

from Tkinter import *
from Tkconstants import *

DEFAULT_BUFSIZE = 8*1024

#
# Thread de recherche
#
class Recherche(Thread):
    """ Thread de recherche de texte
    """
    def __init__(self, chemin, texte, pourcent, retour):
        Thread.__init__(self)
        self.chemin = chemin
        self.texte = texte
        self.pourcent = pourcent
        self.retour = retour
        self.tampon = DEFAULT_BUFSIZE
        self.running = False

    def stop(self):
        """ arrête le thread """
        if self.running:
            self.running = False
            self.join()

    def run(self):
        """ méthode lancée par start() """
        chemin = self.chemin
        texte = self.texte
        trouve = 0
        self.running = True
        for racine, reps, fichiers in walk(chemin):
            if not self.running:
                break
            i = 1
            for fichier in fichiers:
                if not self.running:
                    break
                self.pourcent('Recherche: %s/%s : %d/%d' \
                            % (racine, fichier, i, len(fichiers)))
                nom_complet = '%s/%s' %(racine, fichier)
                if self.texte_present(nom_complet, texte):
                    self.retour('%s' % nom_complet)
                    trouve += 1
                i += 1
        if trouve == 0:
            self.retour('Aucun fichier')
        self.pourcent('%d fichier(s) trouvé(s)' % trouve)

    def texte_present(self, fichier, texte):
        """ renvoie vrai si le fichier contient le texte """
        c_cherche = compile(texte)
        try:
            curseur = open(fichier, 'r', buffering=self.tampon)
        except IOError?:     # en cas de pb d'accès (droits, etc.)
            return False
        try:
            line = None
            while line != '':
                if not self.running:
                    return False
                line = curseur.readline(self.tampon)
                res = findall(c_cherche, line)
                if res != []?:
                    return True
            return False
        finally:
            curseur.close()

#
# Frames
#
class FrameChemin?(Frame):
    def __init__(self, racine):
        Frame.__init__(self)
        label = Label(self, text="Chemin de recherche")
        label.pack(fill=X, expand=1)
        self.chemin = Entry(self, name="chemin")
        self.chemin.pack(fill=BOTH)
        self.chemin.insert(0, '/')
        self.chemin.select_range(0, END)

class FrameTexte?(Frame):
    def __init__(self, racine):
        Frame.__init__(self)
        self.label = Label(self, text="Texte à rechercher")
        self.label.pack(fill=X, expand=1)
        self.texte = Entry(self, name="texte")
        self.texte.pack(fill=BOTH)
        self.texte.insert(0, '')
        self.texte.select_range(0, END)

class FrameButton?(Frame):
    def __init__(self, racine):
        Frame.__init__(self)

    def create_elements(self, stop_command, search_command,
                            close_command):
        self.button = Button(self,text="Stop",
                            command=stop_command)
        self.button.pack(side=RIGHT, padx=5, pady=5)
        self.button = Button(self,text="Rechercher",
                            command=search_command)
        self.button.pack(side=RIGHT, padx=5, pady=5)
        self.button3 = Button(self,text="Fermer",
                            command=close_command)
        self.button3.pack(side=RIGHT)

class FrameResultat?(Frame):
    def __init__(self, racine):
        Frame.__init__(self)
        self.fenetre_resultats = Listbox(self)
        self.resultats_ascenseur = Scrollbar(self, orient=VERTICAL,
                            command=self.fenetre_resultats.yview)
        self.fenetre_resultats.config(yscrollcommand=\
                                    self.resultats_ascenseur.set)

        self.fenetre_resultats.pack(side=LEFT, expand=1, fill=BOTH)
        self.resultats_ascenseur.pack(side=RIGHT, fill=Y)

#
# Application  
#
class Application(object):
    """ Frame contenant l'interface de recherche
    et d'affichage des résultats
    """
    def __init__(self):
        self._tk = Tk()

        # création des 4 frames
        options = {'expand': 1, 'fill': BOTH}
        self.add_frame('frm_chemin', FrameChemin?, **options)
        self.add_frame('frm_texte', FrameTexte?, **options)

        self.add_frame('frm_bouton', FrameButton?, **options)
        self.frm_bouton.create_elements(self.stop_recherche,
                                                self.recherche,
                                        self.ferme_fenetre)

        self.add_frame('frm_resultat', FrameResultat?, **options)
        #, 'relief': RIDGE
        self.chercheur = None

        # titre fenêtre application
        self._tk.wm_title('Recherche')

    def mainloop(self):
        self._tk.mainloop()

    def add_frame(self, name, class_, **pack_options):
        instance = class_(self._tk)
        setattr(self, name, instance)
        instance.pack(**pack_options)

    def _retour(self, msg):
        """ appelée par le thread """
        self.frm_resultat.fenetre_resultats.insert(END, msg)

    def _pourcent(self, msg):
        """ appelée par le thread """
        self._tk.wm_title(msg)

    def recherche(self):
        """ lance une recherche """
        self.stop_recherche()

        self.frm_resultat.fenetre_resultats.delete(0, END)
        chemin = self.frm_chemin.chemin.get()
        texte = self.frm_texte.texte.get()

        # lance le thread de recherche
        self.chercheur = Recherche(chemin, texte, self._pourcent,  
                                   self._retour)
        self.chercheur.start()

    def stop_recherche(self):
        """ stoppe une éventuelle recherche en cours """
        if self.chercheur is not None:
            self.chercheur.stop()

    def ferme_fenetre(self):
        """ demande de fermeture, arrêt d'une éventuelle recherche """
        self.stop_recherche()
        self._tk.destroy()

if __name__ == '__main__':
    app = Application()
    app.mainloop()

Tarek Ziadé. Copyright 2006. Tous droits réservés. Licence contenu site