Je crée une horloge en utilisant Tkinter et Python.
Ce que je veux, c'est faire fonctionner l'horloge et vérifier automatiquement si le fichier JSON (qui contient les paramètres visuels de l'horloge) a été mis à jour. Si le fichier JSON a été mis à jour, l'horloge sera mise à jour en direct.
Cependant, ce n'est pas le cas. Ce que je dois faire, c'est mettre à jour le fichier JSON, fermer le programme d'horloge, puis rouvrir le programme d'horloge. Ce n'est que dans ce cas que les paramètres JSON modifiés seront appliqués.
clock.py
{ "window": { "full_screen": false, "window_title" : "chronoberry" }, "background": { "color": "black" }, "time": { "font": "arial", "size": 70, "weight": "bold", "slant": "roman", "color": "white", "format": "%-I:%M:%S %p" }, "date": { "font": "arial", "size": 20, "weight": "normal", "slant": "roman", "color": "white", "format": "%A, %B %-d %Y" } }
settings.py
import os import json with open('settings.json') as json_settings: settings = json.load(json_settings) # Window full_screen = settings['window']['full_screen'] window_title = settings['window']['window_title'] # Background background_color = settings['background']['color'] # Time time_font = settings['time']['font'] time_size = settings['time']['size'] time_weight = settings['time']['weight'] time_slant = settings['time']['slant'] time_color = settings['time']['color'] time_format = settings['time']['format'] # Date date_font = settings['date']['font'] date_size = settings['date']['size'] date_weight = settings['date']['weight'] date_slant = settings['date']['slant'] date_color = settings['date']['color'] date_format = settings['date']['format']
from tkinter import * from datetime import datetime from settings import * # Updates the program and clock settings def tick(): time_string = datetime.now().strftime(time_format) date_string = datetime.now().strftime(date_format) root.config(bg=background_color) container.configure(bg=background_color) current_time.configure(text=time_string, font=(time_font, time_size, time_weight, time_slant), fg=time_color, bg=background_color) current_date.configure(text=date_string, font=(date_font, date_size, date_weight, date_slant), fg=date_color, bg=background_color) current_time.after(1, tick) # TKInterface root = Tk() root.title(window_title) # Binds 'Esc' key to exit program root.bind('<Escape>', exit) # Runs program in full-screen if full_screen: root.attributes('-fullscreen', True) root.config(cursor='none') # Creates container to hold time and date container = Frame(root) current_time = Label(container) current_date = Label(container) container.pack(expand=True) current_time.pack() current_date.pack() tick() root.mainloop()
Effet souhaité:
Si je change la couleur d'arrière-plan de mon fichier JSON et que je l'enregistre, mon horloge devrait pouvoir mettre à jour sa couleur pendant l'exécution.
Avant de changer l'arrière-plan color
Après avoir changé la couleur d'arrière-plan
Ce que j'ai essayé:
3 Réponses :
Quelle est la gravité de ce code? Vous pouvez simplement vérifier la dernière heure de modification du fichier à un certain intervalle avec os.stat (path_to_file) .st_mtime
et actualiser votre interface si elle est postérieure à la dernière vérification. Rapide et sale.
Vous avez plusieurs options. 1 est l'option que benas a suggérée. Toutes les secondes environ, vérifiez la dernière heure de modification du fichier json pour voir si elle a changé.
Une autre option consiste à utiliser un package tel que PyiNotify . Ce package peut identifier les événements qui se produisent sur les fichiers et les dossiers. Un de ces événements est l'événement IN_MODIFY qui se déclenche lorsqu'un fichier a été modifié. Une liste d'événements est disponible ici .
Tout d'abord, vous devez installer le package en utilisant pip:
import pyinotify # The watch manager stores the watches and provides operations on watches wm = pyinotify.WatchManager() wm.add_watch('/path/to/file', mask, rec=True) mask = pyinotify.IN_MODIFY # watched events class EventHandler(pyinotify.ProcessEvent): def process_IN_MODIFY(self, event): print "Modifying:", event.pathname
Ce qui suit est un exemple de code (presque entièrement tiré de leur documentation)
pip install pyinotify
Je crois comprendre que pyinotify
n'est pas bien pris en charge (aucun changement depuis des années). La plupart des gens semblent recommander inotify
.
Votre module settings
est essentiellement un module de constantes, ce qui le rend assez difficile à réutiliser. Bien que vous puissiez faire quelque chose de piraté pour forcer le recharger
comme:
mysettings.date_color
, cela va être à la fois inefficace et une mauvaise utilisation du mécanisme d'importation (maintenant au lieu d'en lire un fichier, vous en lisez deux, le module et le JSON dont il dépend).
Au lieu de cela, je recommanderais de rendre les paramètres
un peu plus réutilisables avec une fonction qui peut lire les données et les mettre en cache, plutôt qu'un tas de globaux:
mysettings = Settings()
Maintenant, votre module clock
peut importer des paramètres
, Construisez un objet Settings
à l'avant, et à chaque tick
appelez update_settings ()
dessus. Si update_settings
renvoie True
, il doit également réappliquer la configuration. Le code aurait besoin de qualifier les différents noms, donc au lieu de simplement dire date_color
, vous mettriez:
import os import json class Settings: SETTINGS_FILE = 'settings.json' def __init__(self): self._load_settings() def update_settings(self): if self._last_update != os.stat(self.SETTINGS_FILE).st_mtime: self._load_settings() return True return False def _load_settings(self): with open(self.SETTINGS_FILE) as json_settings: settings = json.load(json_settings) self._last_update = os.fstat(json_settings.fileno()).st_mtime # Window self.full_screen = settings['window']['full_screen'] self.window_title = settings['window']['window_title'] # Background self.background_color = settings['background']['color'] # Time self.time_font = settings['time']['font'] self.time_size = settings['time']['size'] self.time_weight = settings['time']['weight'] self.time_slant = settings['time']['slant'] self.time_color = settings['time']['color'] self.time_format = settings['time']['format'] # Date self.date_font = settings['date']['font'] self.date_size = settings['date']['size'] self.date_weight = settings['date']['weight'] self.date_slant = settings['date']['slant'] self.date_color = settings['date']['color'] self.date_format = settings['date']['format']
au niveau supérieur, et se référer à date_color
avec:
def tick(): import settings, importlib importlib.reload(settings) from settings import * # ... rest of tick code ...
mais c'est un petit prix à payer pour améliorer le code.
Pour mémoire, je conviens que les interfaces inotify
seraient une amélioration ici et devraient être prises en compte, mais elles (IMO) sont trop avancées pour votre niveau de compétence en ce moment.
C'est une approche élégante de mon problème! J'apprécie le temps que vous avez pris pour expliquer cela à un programmeur novice. Merci!
Pour ma compréhension de base, c'est ce que fait le fichier settings.py modifié: Lors de la création d'un objet Settings (), la méthode _load_settings () est appelée. Ici, la dernière heure de modification enregistrée du fichier JSON est stockée à l'intérieur de _last_update.
@leecharles_: Ouais. Ensuite, chaque fois que vous appelez update_settings
, il vérifie si le fichier JSON a été modifié depuis son dernier chargement, et si tel est le cas, le recharge et renvoie True
(afin que vous sachiez à reconfigurer avec les nouveaux paramètres), sinon il renvoie False
(vous savez donc que vous pouvez simplement mettre à jour l'heure et laisser la configuration Tk inchangée)
une fois qu'un fichier est fermé, il est impossible de l'ouvrir à nouveau Non, ce n'est pas le cas. Pourquoi dites vous cela? Obtenez-vous une erreur lorsque vous essayez?
Savez-vous que
after (1, ...)
s'exécute après 1 milliseconde, pas une seconde? Étant donné que votre horloge n'a qu'une seconde de résolution, vous faites travailler le processeur beaucoup plus que nécessaire.