Précédent   Forum du club des développeurs et IT Pro > Autres langages > Python & Zope > GUI
GUI Forum d'entraide sur les bibliothèques pour interfaces graphiques en Python
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 30/06/2012, 09h47   #1
babsh
Invité de passage
 
Femme
Étudiant
Inscription : juin 2012
Messages : 5
Détails du profil
Informations personnelles :
Sexe : Femme
Localisation : Islande

Informations professionnelles :
Activité : Étudiant
Secteur : Arts - Culture

Informations forums :
Inscription : juin 2012
Messages : 5
Points : 2
Points : 2
Par défaut execution periodique avec GUI

Bonjour,
je recherche un moyen simple d´executer periodiquement (toutes les x min.) une commande. L´execution periodique doit commencer quand l´utilisateur appuie sur un bouton "commencer" et s´arreter lorsqu´il appuie sur un bouton "terminer".

J´ai bien reussi avec Tkinter de Python a faire les boutons, mais je ne sais pas comment faire l´execution periodique qui s´arreterait quand on appuie sur un bouton.
Quelqu´un pourrait-il me dire comment faire? Si possible sans trop consommer de ressource.
babsh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 10h43   #2
PauseKawa
Expert Confirmé
 
Avatar de PauseKawa
 
Homme Patrice BLANGARIN
Technicien Help Desk, maintenance, réseau, système et +
Inscription : juin 2006
Messages : 2 616
Détails du profil
Informations personnelles :
Nom : Homme Patrice BLANGARIN
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Technicien Help Desk, maintenance, réseau, système et +
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2006
Messages : 2 616
Points : 3 728
Points : 3 728
Bonjour,

Pas compris: Si c'est périodique pas besoin de bouton "commencer" /"terminer". Cela se passe via un daemon/thread etc... Et pas besoin de GUI.
Pouvez vous préciser ce que vous voulez faire ?
Pour ce qui est de Tkinter avez vous vus que le Widget Button a une option command ? C'est pour spécifier une fonction a exécuter.

@+
__________________
Merci d'utiliser le forum pour les questions techniques.
PauseKawa est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 10h57   #3
PauseKawa
Expert Confirmé
 
Avatar de PauseKawa
 
Homme Patrice BLANGARIN
Technicien Help Desk, maintenance, réseau, système et +
Inscription : juin 2006
Messages : 2 616
Détails du profil
Informations personnelles :
Nom : Homme Patrice BLANGARIN
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Technicien Help Desk, maintenance, réseau, système et +
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2006
Messages : 2 616
Points : 3 728
Points : 3 728
Voila pour la partie GUI
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sys
 
if sys.version_info[0] > 2:
    import tkinter as tk
else:
    import Tkinter as tk
 
def hideme():
    root.withdraw()
    root.after(2000, root.deiconify) # 2000 est en ms
 
root = tk.Tk()
tk.Button(root, text="Cacher", command=hideme).pack(padx=5, pady=5)
tk.Button(root, text="Quitter", command=root.destroy).pack(padx=5, pady=5)
root.mainloop()
Pour le reste dans l'attente de vous lire.

@+
__________________
Merci d'utiliser le forum pour les questions techniques.
PauseKawa est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 11h57   #4
VinsS
Membre Expert
 
Homme
Inscription : octobre 2008
Messages : 941
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : Belgique

Informations forums :
Inscription : octobre 2008
Messages : 941
Points : 1 408
Points : 1 408
Salut,

Moi, je comprends plutôt que le bouton sert simplement à mettre en marche le timer et ensuite à le stopper.

Si c'est bien cela, il suffit de montrer le code du timer, il doit bien y avoir un moyen de l'arrêter.
__________________
Vincent
Oqapy . Qarte . PaQager
VinsS est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 12h00   #5
babsh
Invité de passage
 
Femme
Étudiant
Inscription : juin 2012
Messages : 5
Détails du profil
Informations personnelles :
Sexe : Femme
Localisation : Islande

Informations professionnelles :
Activité : Étudiant
Secteur : Arts - Culture

Informations forums :
Inscription : juin 2012
Messages : 5
Points : 2
Points : 2
Ce que j´ entends par periodique c´est une repetition a intervalle regulier d´une commande jusqu´a ce que l´utilisateur dise: stop. L´information stop peut etre donne par GUI, ce n´est effectivement pas obligatoire, mais plus pratique.

Je pourrais lancer une boucle infinie genre:

while true
ma commande
pause x min

et "killer" le processus quand je veux l´arreter, mais ce n´est pas tres elegant comme methode!

En fait j´ai ecrit un script python qui actualise une base de donnee. J´aimerai pouvoir lancer regulierement (toutes les x min.) ce script quand j´ai besoin d´avoir cette base de donnee toujours actualisee. Quand je n´en ai plus besoin, j´aimerais pouvoir arreter l´actualisation de ma base de donnee.
babsh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 13h11   #6
VinsS
Membre Expert
 
Homme
Inscription : octobre 2008
Messages : 941
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : Belgique

Informations forums :
Inscription : octobre 2008
Messages : 941
Points : 1 408
Points : 1 408
C'est bien ce que j'avais copris, mais ton 'timer' tu l'as écrit comment ?

Un thread ? threading.Timer ?

Une boucle while, ça m'étonnerait.

Bref, on veut du code.
__________________
Vincent
Oqapy . Qarte . PaQager
VinsS est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 13h15   #7
wiztricks
Expert Confirmé Sénior
 
Inscription : juin 2008
Messages : 3 709
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 3 709
Points : 4 541
Points : 4 541
Salut

Avec Tkinter, vous avez la méthode .after(delay, callback) qui permet d'appeler la fonction "callback" après "delay" millisecondes.

La discussion récente montre comment utiliser la chose pour "répéter" l'opération "tant que".

La méthode .after retourne un identifiant qui pourra être passé en paramètre à la méthode .cancel pour arrêter le monstre.

Ces méthodes .after, .cancel sont disponibles pour tous les widgets Tk.
Vous pouvez aussi lire la discussion qui traite de ce sujet.

Ces indications devrait vous permettre d'écrire un premier code et de râler sur les aspects que vous ne comprenez pas.

- W
__________________
Architectures Post-Modernes
wiztricks est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 30/06/2012, 16h17   #8
babsh
Invité de passage
 
Femme
Étudiant
Inscription : juin 2012
Messages : 5
Détails du profil
Informations personnelles :
Sexe : Femme
Localisation : Islande

Informations professionnelles :
Activité : Étudiant
Secteur : Arts - Culture

Informations forums :
Inscription : juin 2012
Messages : 5
Points : 2
Points : 2
La methode .after(delay, callback) marche nickel! Par contre je n´arrive pas a l´arreter avec le .cancel. Comment utilise-t-on le .cancel? Auriez-vous un exemple?
Voici un extrait de mon code:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
 
class App:
	def __init__(self,parent):
#...
	def update_loop(self):
		#ici ma commade "lancer actualisation". Pr l instant juste un print:
                print periode
	        boucle_identifiant=root.after(1000, self.update_loop)
 
 
	def stop_loop(self):
		root.cancel(boucle_identifiant)
 
root = Tk()
app = App(root)
root.mainloop()
babsh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 16h59   #9
wiztricks
Expert Confirmé Sénior
 
Inscription : juin 2008
Messages : 3 709
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 3 709
Points : 4 541
Points : 4 541
Désolé, j'ai m...
Il faut utiliser .after_cancel et non .cancel (que je ne sais même pas ce que c'est):

Un exemple posté, il y a longtemps:
Code :
1
2
3
4
5
6
7
8
9
10
11
counter_id = None
def decompte(count=10):
    global counter_id
    lab['text'] = count
    if count > 0 :
        counter_id = fen1.after(1000, decompte, count-1)
 
def stop():
    if counter_id:
        fen1.after_cancel(counter_id)
        lab['text'] = "stop!"
- W
__________________
Architectures Post-Modernes
wiztricks est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 30/06/2012, 18h21   #10
babsh
Invité de passage
 
Femme
Étudiant
Inscription : juin 2012
Messages : 5
Détails du profil
Informations personnelles :
Sexe : Femme
Localisation : Islande

Informations professionnelles :
Activité : Étudiant
Secteur : Arts - Culture

Informations forums :
Inscription : juin 2012
Messages : 5
Points : 2
Points : 2
Merci ca marche nickel!

Mon code si ca interesse quelqu´un:

Code :
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
import glob, os
import sys
import time, threading
from Tkinter import *
from tkFileDialog import askopenfilename
 
 
class App:
	def __init__(self,parent):
 
		f = Frame(parent)
		f.pack(padx=15,pady=15)
 
   		self.entry = Entry(f,text="enter your choice")
		self.entry.pack(side= TOP,padx=10,pady=12)
 
		self.exit = Button(f, text="exit", command=f.quit)
		self.exit.pack(side=BOTTOM,padx=10,pady=10)
 
		self.button = Button(f, text="print bonjour",command=self.effacer_intraday)
		self.button.pack(side=BOTTOM,padx=10,pady=10)
 
		self.button = Button(f, text="print once",command=self.update_once)
		self.button.pack(side=BOTTOM,padx=10,pady=10)
 
		self.button = Button(f, text="Stop",command=self.stop_loop)
		self.button.pack(side=BOTTOM,padx=10,pady=10)
 
		self.button = Button(f, text="print each second",command=self.update_loop)
		self.button.pack(side=BOTTOM,padx=10,pady=10)
 
 
	def effacer_intraday(self):
		print "bonjour"
 
	def update_loop(self):
		global counter_id
		periode = self.entry.get()
		print periode
	        counter_id =root.after(1000, self.update_loop)
 
	def update_once(self):
		periode = self.entry.get()
		print periode
 
	def stop_loop(self):
	    if counter_id:
	        root.after_cancel(counter_id)
 
 
root = Tk()
root.title('Tkwidgets application')
Label (text="Enter text to print:").pack(side=TOP,padx=0,pady=0)
app = App(root)
root.mainloop()
babsh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/06/2012, 20h15   #11
PauseKawa
Expert Confirmé
 
Avatar de PauseKawa
 
Homme Patrice BLANGARIN
Technicien Help Desk, maintenance, réseau, système et +
Inscription : juin 2006
Messages : 2 616
Détails du profil
Informations personnelles :
Nom : Homme Patrice BLANGARIN
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Technicien Help Desk, maintenance, réseau, système et +
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2006
Messages : 2 616
Points : 3 728
Points : 3 728
Bonjour,

Deux ou trois petites choses qui me sont venues à l'esprit à la lecture du code:

Ne mélanger pas tabulations et espaces.

Pas besoin de global puisque vous avez self.

Utilisez parent.destroy et non f.quit.

Le fait d'utiliser le même nom pour tout vos Widgets Button fait vous écrasez la référence à chaque fois. Mais au fait: Pourquoi la garder puisque seul command nous intéresses.

padx=0,pady=0 ne sert à rien. De même ici les side= puisque .pack() le places de haut en bas. Mais bon, cela ne gène en rien.

L’intérêt du Label hors de la Frame ? Et l’intérêt de la Frame en fait puisque .pack() positionne les Widgets de haut en bas ?

root.after(1000, self.update_loop) ? self.parent.after(1000, self.update_loop) En fait.

Code :
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
from Tkinter import *
 
 
class App:
    def __init__(self, parent):
        self.parent = parent
        Label(self.parent, text="Enter text to print:").pack(padx=10, pady=10)
        self.entry = Entry(self.parent, text="enter your choice")
        self.entry.pack(padx=10, pady=10)
 
        Button(self.parent, text="exit", command=self.parent.destroy).pack(padx=10, pady=10)
 
        Button(self.parent, text="print bonjour", command=self.effacer_intraday).pack(padx=10, pady=10)
 
        Button(self.parent, text="print once", command=self.update_once).pack(padx=10, pady=10)
 
        Button(self.parent, text="Stop", command=self.stop_loop).pack(padx=10, pady=10)
        Button(self.parent, text="print each second", command=self.update_loop).pack(padx=10, pady=10)
 
    def effacer_intraday(self):
        print "bonjour"
 
    def update_loop(self):
        periode = self.entry.get()
        print periode
        self.counter_id = self.parent.after(1000, self.update_loop)
 
    def update_once(self):
        periode = self.entry.get()
        print periode
 
    def stop_loop(self):
        if self.counter_id:
            root.after_cancel(self.counter_id)
 
 
root = Tk()
root.title('Tkwidgets application')
app = App(root)
root.mainloop()
Je vois un import threading donc je pense que c'est utile pour votre code complet: Attention avec Tkinter qui n'est pas threadsave.

Astuce: Lorsque vous utilisez les mêmes options de géométrie pour un groupe de Widget vous pouvez utiliser un dico.

L’intérêt de la classe ici ? A la limite si cela dérive de Tk.

if self.counter_id est source à erreur (AttributeError) si vous cliquez sur stop avant. Soit vous utilisez hasattr, soit (le plus simple) vous donnez une valeur à self.counter_id.
Code :
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
 
from Tkinter import *
 
 
class App(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title('Tkwidgets application')
        geometry = {'padx': 10, 'pady': 10}
        self.counter_id = None
 
        Label(self, text="Enter text to print:").pack(geometry)
        self.entry = Entry(self, text="enter your choice")
        self.entry.pack(geometry)
 
        Button(self, text="exit", command=self.destroy).pack(geometry)
 
        Button(self, text="print bonjour", command=self.effacer_intraday).pack(geometry)
 
        Button(self, text="print once", command=self.update_once).pack(geometry)
 
        Button(self, text="Stop", command=self.stop_loop).pack(geometry)
        Button(self, text="print each second", command=self.update_loop).pack(geometry)
        self.mainloop()
 
    def effacer_intraday(self):
        print("bonjour")
 
    def update_loop(self):
        print(self.entry.get())
        self.counter_id = self.after(1000, self.update_loop)
 
    def update_once(self):
        print(self.entry.get())
 
    def stop_loop(self):
        if self.counter_id:
            self.after_cancel(self.counter_id)
 
 
if __name__ == "__main__":
    App()
Petit modif pour rendre l'exemple compatible Python 2/3

Code :
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
import sys
if sys.version_info[0] > 2:
    import tkinter as tk
else:
    import Tkinter as tk 
 
 
class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title('Tkwidgets application')
        geometry = {'padx': 10, 'pady': 10}
        self.counter_id = None
 
        tk.Label(self, text="Enter text to print:").pack(geometry)
        self.entry = tk.Entry(self, text="enter your choice")
        self.entry.pack(geometry)
 
        tk.Button(self, text="exit", command=self.destroy).pack(geometry)
 
        tk.Button(self, text="print bonjour", command=self.effacer_intraday).pack(geometry)
 
        tk.Button(self, text="print once", command=self.update_once).pack(geometry)
 
        tk.Button(self, text="Stop", command=self.stop_loop).pack(geometry)
        tk.Button(self, text="print each second", command=self.update_loop).pack(geometry)
        self.mainloop()
 
    def effacer_intraday(self):
        print("bonjour")
 
    def update_loop(self):
        print(self.entry.get())
        self.counter_id = self.after(1000, self.update_loop)
 
    def update_once(self):
        print(self.entry.get())
 
    def stop_loop(self):
        if self.counter_id:
            self.after_cancel(self.counter_id)
 
 
if __name__ == "__main__":
    App()
Une autre astuce au passage pour les Widgets identiques

Code :
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
import sys
if sys.version_info[0] > 2:
    import tkinter as tk
else:
    import Tkinter as tk 
 
 
class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title('Tkwidgets application')
        geometry = {'padx': 10, 'pady': 10}
        self.counter_id = None
 
        tk.Label(self, text="Enter text to print:").pack(geometry)
        self.entry = tk.Entry(self, text="enter your choice")
        self.entry.pack(geometry)
 
        buttons = {"exit": self.destroy, "print bonjour": self.effacer_intraday,
                   "print once": self.update_once, "Stop": self.stop_loop,
                   "print each second": self.update_loop}
 
        for cmd in buttons:
            tk.Button(self, text=cmd, command=buttons[cmd]).pack(geometry)
 
        self.mainloop()
 
    def effacer_intraday(self):
        print("bonjour")
 
    def update_loop(self):
        print(self.entry.get())
        self.counter_id = self.after(1000, self.update_loop)
 
    def update_once(self):
        print(self.entry.get())
 
    def stop_loop(self):
        if self.counter_id:
            self.after_cancel(self.counter_id)
 
 
if __name__ == "__main__":
    App()
Mais en fait ici pas besoin d'une classe

Code :
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
import sys
if sys.version_info[0] > 2:
    import tkinter as tk
else:
    import Tkinter as tk 
 
 
def effacer_intraday():
    print("bonjour")
 
def update_loop():
    print(entry.get())
    root.counter_id = root.after(1000, update_loop)
 
def update_once():
    print(entry.get())
 
def stop_loop():
    if root.counter_id:
        root.after_cancel(root.counter_id)
 
 
root = tk.Tk()
root.title('Tkwidgets application')
geometry = {'padx': 10, 'pady': 10}
root.counter_id = None
 
tk.Label(root, text="Enter text to print:").pack(geometry)
entry = tk.Entry(root, text="enter your choice")
entry.pack(geometry)
 
buttons = {"exit": root.destroy, "print bonjour": effacer_intraday,
           "print once": update_once, "Stop": stop_loop,
           "print each second": update_loop}
 
for cmd in buttons:
    tk.Button(root, text=cmd, command=buttons[cmd]).pack(geometry)
 
root.mainloop()
@+ et bon code

Edit: Bonus géométrique
geometry = {'padx': 10, 'pady': 10, 'fill': tk.BOTH}

Edit: Erreur de tabulation.
__________________
Merci d'utiliser le forum pour les questions techniques.
PauseKawa est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 01/07/2012, 12h03   #12
babsh
Invité de passage
 
Femme
Étudiant
Inscription : juin 2012
Messages : 5
Détails du profil
Informations personnelles :
Sexe : Femme
Localisation : Islande

Informations professionnelles :
Activité : Étudiant
Secteur : Arts - Culture

Informations forums :
Inscription : juin 2012
Messages : 5
Points : 2
Points : 2
En fait mon code c´ est de la recupe de codes que j'ai trouve sur internet. D'ou toutes les incoherences. Je debute en python, c'est l'un de mes premiers codes.
En tous cas, merci a tous pour votre aide!

Juste une petite derniere question. L'execution de la boucle periodique n'est en fait pas exactement periodique.

La periode d'execution de la fonction update_loop:
Code :
1
2
3
def update_loop():
    print(entry.get())
    root.counter_id = root.after(1000, update_loop)
est en faite de 1 seconde + le temps d'execution de:
Bon dans ce cas, l'execution de print est quasi instantannee, donc ca n'a pas d'importance. Mais j'utilise ce code pour lancer un autre python (actualiser une base de donnee), dont le temps d'execution est non negligeable et irregulier. La meilleure solution que j'ai trouve pour que la periode d'execution de la fonction update_loop soit independante de la duree de l'application que je lance (ici print(entry.get()) ), c'est de mettre le root.after avant le print:
Code :
1
2
3
def update_loop():
    root.counter_id = root.after(1000, update_loop)
    print(entry.get())
Je voulais juste avoir votre avis sur cette astuce. Est-ce correcte? Bon chez moi ca a l'air demarche.
babsh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/07/2012, 13h13   #13
PauseKawa
Expert Confirmé
 
Avatar de PauseKawa
 
Homme Patrice BLANGARIN
Technicien Help Desk, maintenance, réseau, système et +
Inscription : juin 2006
Messages : 2 616
Détails du profil
Informations personnelles :
Nom : Homme Patrice BLANGARIN
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Technicien Help Desk, maintenance, réseau, système et +
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2006
Messages : 2 616
Points : 3 728
Points : 3 728
C'est bien cela.
Je rajouterais que si vous modifiez quelque chose il n'est sans doute pas bon de lancer le même traitement deux fois en même temps, dans le cas ou le premier n'est pas fini. Comprendre que votre traitement doit 'signaler' qu'il a fini avant d'en faire un autre.
Code :
1
2
3
4
5
def update_loop():
    root.counter_id = root.after(1000, update_loop)
    if in_progress:
        return
    #ici le code qui à la fin fait un in_progress = False. Utilisez self.in_progress ou global au choix.
__________________
Merci d'utiliser le forum pour les questions techniques.
PauseKawa est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 20h11.


 
 
 
 
Partenaires

Hébergement Web