Newer
Older
#Reference for Threading and GUI architecture: https://maldus512.medium.com/how-to-setup-correctly-an-application-with-python-and-tkinter-107c6bc5a45
import queue
import matplotlib.pyplot as plt
import numpy as np
from tkinter import TOP, BOTH, X, LEFT, RIGHT
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from types import SimpleNamespace
from enum import Enum
from threading import Thread
TIME_OUT = 0.5 #Time out used for refreshing the User Interface
class Messages(Enum):
HRSETALARM = 0
#Method in charge of updating the UI. It is called from another thread and uses queue for communication
def refreshUI(guiRef, model, guiQueue):
msg = None
while True:
try:
msg = guiQueue.get(timeout = TIME_OUT)
if msg == Messages.HRSETALARM:
model.count += 1
guiRef.entry["state"] = 'normal'
guiRef.entry.delete(0,"end")
guiRef.entry.insert(0,"12")
guiRef.entry["state"] = 'disabled'
guiRef.entry_two.delete(0,"end")
guiRef.entry_two.insert(0,"Prueba")
except queue.Empty:
pass
#Other tasks...
print("Han pasado 500 milisegundos")
#Class for the User Interface
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
#self.master.geometry('1000x1000')
self.master.title('Smart Watch')
self.pack(fill=BOTH, expand=True)
self.create_widgets()
def create_widgets(self):
#FRAME 1
self.frame_one = tk.Frame(self.master)
self.frame_one.pack(fill=X)
self.label_title = tk.Label(self.frame_one, text = "Smart Watch")
self.label_title.pack(side=LEFT)
self.frame_two = tk.Frame(self.master)
self.frame_two.pack(fill=X)
figure = plt.Figure(figsize=(6,5), dpi=100)
ax = figure.add_subplot(111)
chart_type = FigureCanvasTkAgg(figure, self.frame_two)
chart_type.get_tk_widget().pack()
x = np.arange(10)
y = 2.5 * np.sin(x / 20 * np.pi)
ax.plot(x, y, color='tab:blue')
ax.set_xlim([0, 10])
ax.set_ylim([-1, 1])
ax.set_title('PPG - RED')
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#FRAME 3
self.frame_three = tk.Frame(self.master)
self.frame_three.pack(fill=X)
self.label_subtitle_two = tk.Label(self.frame_three, text = "Valores Instantáneos")
self.label_subtitle_two.pack(side=LEFT)
#FRAME 4
self.frame_four = tk.Frame(self.master)
self.frame_four.pack(fill=X)
self.label_heartrate = tk.Label(self.frame_four, text = "Heart Rate")
self.label_heartrate.pack(side=LEFT)
#TODO Entry must be enabled before updating it
self.entry_heartrate = tk.Entry(self.frame_four, state='disabled')
self.entry_heartrate.pack(side=LEFT)
self.label_heartrate_units_one = tk.Label(self.frame_four, text = "bpm")
self.label_heartrate_units_one.pack(side=LEFT)
self.label_heartrate_alarm = tk.Label(self.frame_four, text = "ALARMA")
self.label_heartrate_alarm.pack(side=LEFT)
self.label_heartrate_minimum = tk.Label(self.frame_four, text = "Mínimo")
self.label_heartrate_minimum.pack(side=LEFT)
self.entry_heartrate_minimum = tk.Entry(self.frame_four)
self.entry_heartrate_minimum.pack(side=LEFT)
self.label_heartrate_units_two = tk.Label(self.frame_four, text = "bpm")
self.label_heartrate_units_two.pack(side=LEFT)
self.label_heartrate_maximum = tk.Label(self.frame_four, text = "Máximo")
self.label_heartrate_maximum.pack(side=LEFT)
self.entry_heartrate_maximum = tk.Entry(self.frame_four)
self.entry_heartrate_maximum.pack(side=LEFT)
self.label_units_heartrate_three = tk.Label(self.frame_four, text = "bpm")
self.label_units_heartrate_three.pack(side=LEFT)
self.button_heartrate = tk.Button(self.frame_four, text = "Configurar alarma")
#self.button_heartrate = tk.Button(self.frame_four, text = "Configurar alarma", command = self.configure_heartrate_alarm)
self.button_heartrate.pack(side=LEFT)
#FRAME 5
self.frame_five = tk.Frame(self.master)
self.frame_five.pack(fill=X)
self.quit = tk.Button(self.frame_five, text="QUIT", fg="red", command=self.master.destroy)
self.quit.pack(side=RIGHT)
def configure_heartrate_alarm(self):
self.entry_heartrate["state"] = 'normal'
self.entry_heartrate.delete(0,"end")
self.entry_heartrate.insert(0,"88")
self.entry_heartrate["state"] = 'disabled'
print("Alarma HR!")
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#Method that provides reference to the user interface. It uses a queue to communicate the UI with the exterior. It returns references to
#inner objetcs so the exterior can communicate with it. More references can be given in "SimpleNameSpace"
def gui_reference(self, root, queue):
entry = self.entry_heartrate
entry["state"] = 'normal'
entry.delete(0,"end")
entry.insert(0,"10")
entry["state"] = 'disabled'
self.button_heartrate["command"] = lambda : queue.put(Messages.HRSETALARM)
#Just for testing purposes to emit reference to another widget
entry_two = self.entry_heartrate_minimum
return SimpleNamespace(entry=entry, entry_two = entry_two)
if __name__ == '__main__':
root = tk.Tk()
app = Application(master=root)
#Queue used to communicate the UI with the exterior
guiQueue = queue.Queue()
guiRef = app.gui_reference(root, guiQueue)
model = SimpleNamespace(count=0)
#Thread used to separate the use interface with the front end. It is used to not slow down the GUI when processing information
t = Thread(target=refreshUI, args=(guiRef, model, guiQueue,))
t.daemon = True
t.start()
app.mainloop()