Je souhaite afficher des données en direct dans une interface graphique, dans tkinter
. Les données que j'obtiens contiennent une liste
de deux entiers [current, voltage]
. Je reçois de nouvelles données chaque seconde.
J'ai réussi à créer une interface graphique, maintenant je veux savoir comment afficher les données dans les widgets GUI Label
(python tkinter) et mettre à jour les étiquettes de manière dynamique. Toutes les suggestions s'il vous plaît
Voici mon code pour l'instant:
#data getting is a list eg. [10, 12] from tkinter import * import tkinter.font #main Window using Tk win = Tk() win.title("v1.0") win.geometry('800x480') win.configure(background='#CD5C5C') #Labels voltage = Label(win, text = "voltage") voltage.place(x=15, y=100) current = Label(win, text = "current") current.place(x=15, y=200) #display measured values #how to display here !!! currentValues = Label(win, text = "want to display somewhere like this") currentValues.place(x=200, y=100) voltageValues = Label(win, text = "want to display somewhere like this") voltageValues.place(x=200, y=200) mainloop()
3 Réponses :
Vous pouvez modifier le texte de l'étiquette de manière dynamique:
C'est une manière d'utiliser l'option textvariable
avec la méthode StringVar
et .set ()
win.update()
Une autre façon d'utiliser simplement la méthode .configure ()
currentValues = Label(win, text = "default") currentValues.configure(text="New value")
Enfin, pour faire le Mise à jour de l'interface utilisateur sans attendre le reste de la boucle faire une mise à jour
str_var = tk.StringVar(value="Default") currentValues= Label(win, textvariable=my_string_var) currentValues.place(x=200, y=100) str_var.set("New value")
@dayDreamer après avoir configuré ou modifié vos widgets. afin que votre fenêtre soit mise à jour avec les nouveaux paramètres
Je souhaite afficher des données en direct dans une interface graphique.
Je pense que ce que vous voulez faire est d'utiliser la méthode
.after ()
. La méthode.after ()
met en file d'attentetkinter
pour exécuter du code après un temps défini.Par exemple:
currentValues = Label(win, text = "want to display somewhere like this") currentValues.place(x=200, y=100) voltageValues = Label(win, text = "want to display somewhere like this") voltageValues.place(x=200, y=200) def live_update(): currentValues['text'] = updated_value voltageValues['text'] = updated_value win.after(1000, live_update) # 1000 is equivalent to 1 second (closest you'll get) live_update() # to start the update loop
Si vous souhaitez représenter graphiquement vos données en direct et que vous souhaitez éviter d'utiliser d'autres bibliothèques pour le faire à votre place, vous trouverez peut-être ce qui suit comme un point de départ éclairant pour créer vos propres graphiques. L'exemple trace un cercle complet de valeurs lors de l'évaluation de la fonction math.sin
fournie dans la bibliothèque standard. Le code prend en compte l'échantillonnage automatique, le redimensionnement et la mise à jour selon les besoins et doit être assez réactif.
#! /usr/bin/env python3 import math import threading import time import tkinter.ttk import uuid from tkinter.constants import EW, NSEW, SE class Application(tkinter.ttk.Frame): FPS = 10 # frames per second used to update the graph MARGINS = 10, 10, 10, 10 # internal spacing around the graph @classmethod def main(cls): tkinter.NoDefaultRoot() root = tkinter.Tk() root.title('Tkinter Graphing') # noinspection SpellCheckingInspection root.minsize(640, 480) # VGA (NTSC) cls(root).grid(sticky=NSEW) root.grid_rowconfigure(0, weight=1) root.grid_columnconfigure(0, weight=1) root.mainloop() def __init__(self, master=None, **kw): super().__init__(master, **kw) self.display = tkinter.Canvas(self, background='white') self.display.bind('<Configure>', self.draw) self.start = StatefulButton(self, 'Start Graphing', self.start_graph) self.grip = tkinter.ttk.Sizegrip(self) self.grid_widgets(padx=5, pady=5) self.data_source = DataSource() self.after_idle(self.update_graph, round(1000 / self.FPS)) self.run_graph = None def grid_widgets(self, **kw): self.display.grid(row=0, column=0, columnspan=2, sticky=NSEW, **kw) self.start.grid(row=1, column=0, sticky=EW, **kw) self.grip.grid(row=1, column=1, sticky=SE) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) def start_graph(self): self.run_graph = True threading.Thread(target=self.__simulate, daemon=True).start() return 'Stop Graphing', self.stop_graph def stop_graph(self): self.run_graph = False return 'Clear Graph', self.clear_graph def clear_graph(self): self.data_source.clear() self.reset_display() return 'Start Graphing', self.start_graph # def __simulate(self): # # simulate changing populations # for population in itertools.count(): # if not self.run_graph: # break # self.data_source.append(population, get_max_age(population, 200)) # def __simulate(self): # # simulate changing ages # for age in itertools.count(1): # if not self.run_graph: # break # self.data_source.append(age, get_max_age(250_000_000, age)) def __simulate(self): # draw a sine curve for x in range(800): time.sleep(0.01) if not self.run_graph: break self.data_source.append(x, math.sin(x * math.pi / 400)) def update_graph(self, rate, previous_version=None): if previous_version is None: self.reset_display() current_version = self.data_source.version if current_version != previous_version: data_source = self.data_source.copy() self.draw(data_source) self.after(rate, self.update_graph, rate, current_version) def reset_display(self): self.display.delete('data') self.display.create_line((0, 0, 0, 0), tag='data', fill='black') def draw(self, data_source): if not isinstance(data_source, DataSource): data_source = self.data_source.copy() if data_source: self.display.coords('data', *data_source.frame( self.MARGINS, self.display.winfo_width(), self.display.winfo_height(), True )) class StatefulButton(tkinter.ttk.Button): def __init__(self, master, text, command, **kw): kw.update(text=text, command=self.__do_command) super().__init__(master, **kw) self.__command = command def __do_command(self): self['text'], self.__command = self.__command() def new(obj): kind = type(obj) return kind.__new__(kind) def interpolate(x, y, z): return x * (1 - z) + y * z def interpolate_array(array, z): if z <= 0: return array[0] if z >= 1: return array[-1] share = 1 / (len(array) - 1) index = int(z / share) x, y = array[index:index + 2] return interpolate(x, y, z % share / share) def sample(array, count): scale = count - 1 return tuple(interpolate_array(array, z / scale) for z in range(count)) class DataSource: EMPTY = uuid.uuid4() def __init__(self): self.__x = [] self.__y = [] self.__version = self.EMPTY self.__mutex = threading.Lock() @property def version(self): return self.__version def copy(self): instance = new(self) with self.__mutex: instance.__x = self.__x.copy() instance.__y = self.__y.copy() instance.__version = self.__version instance.__mutex = threading.Lock() return instance def __bool__(self): return bool(self.__x or self.__y) def frame(self, margins, width, height, auto_sample=False, timing=False): if timing: start = time.perf_counter() x1, y1, x2, y2 = margins drawing_width = width - x1 - x2 drawing_height = height - y1 - y2 with self.__mutex: x_tuple = tuple(self.__x) y_tuple = tuple(self.__y) if auto_sample and len(x_tuple) > drawing_width: x_tuple = sample(x_tuple, drawing_width) y_tuple = sample(y_tuple, drawing_width) max_y = max(y_tuple) x_scaling_factor = max(x_tuple) - min(x_tuple) y_scaling_factor = max_y - min(y_tuple) coords = tuple( coord for x, y in zip(x_tuple, y_tuple) for coord in ( round(x1 + drawing_width * x / x_scaling_factor), round(y1 + drawing_height * (max_y - y) / y_scaling_factor))) if timing: # noinspection PyUnboundLocalVariable print(f'len = {len(coords) >> 1}; ' f'sec = {time.perf_counter() - start:.6f}') return coords def append(self, x, y): with self.__mutex: self.__x.append(x) self.__y.append(y) self.__version = uuid.uuid4() def clear(self): with self.__mutex: self.__x.clear() self.__y.clear() self.__version = self.EMPTY def extend(self, iterable): with self.__mutex: for x, y in iterable: self.__x.append(x) self.__y.append(y) self.__version = uuid.uuid4() if __name__ == '__main__': Application.main()
sensationnel. c'est une partie intéressante. Je veux aussi tracer mes données en direct. Je vais certainement essayer.
Pourriez-vous consulter ce lien -> stackoverflow.com/q/56937694/11372345