Imagina que tienes varias estaciones donde se procesa algún tipo de pieza y quieres medir cuanto tiempo permanece cada pieza en cada estación. Supongamos también que cada estación tiene su tiempo de ciclo (unas inician antes otras despues, otras al mismo tiempo).
En el siguiente programa muestro como medir una cantidad determinada de tiempos con un solo temporizador y un solo hilo (thread). El programa calcula minutos, segundos y centésimas de segundo de cada estacion. La interfase de usuario es dinámica, es decir, se puede determinar el numero de registros de tiempo que se deseen (yo puse 20 pero lo puedes cambiar la variable numtimers al numero que quieras), el programa genera los elementos nesesarios. Este programa apenas consume CPU (se podría usar en un Raspberry Pi).El programa inicia el conteo al presionar un botón correspondiente, cuando se presiona de nuevo detiene el conteo de tiempo y lo guarda en un archivo de texto.
Programa en windows |
El programa tiene comentarios en la mayoría de las líneas de código para que se pueda entender lo que sucede.
AVISO: Cada temporizador crea un archivo de texto, si pones 50, se crean 50 archivos de texto en el lugar donde esta el script. Se recomienda correrlo dentro de su propio folder.
Este programa fue probado con python 3.7. También nesecitas wxpython para correr este programa.
import wx
from time import sleep
from threading import Thread
from wx.lib.scrolledpanel import ScrolledPanel
class TimeReg(): #clase para registrar conteo de tiempo y estado del conteo.
def __init__(self):
self.tiempo = [0,0,0] #registro de minutos, segundos y decasegundos
self.activado = False #iniciar desactivado
def update(self):
self.tiempo[2] += 1 # incremento cada centisegundo (1/100)
if (self.tiempo[2] >= 100): # Han pasado 100 centisegundos (1 segundo)?
self.tiempo[2] = 0 # resetear cuenta de centisegundos.
self.tiempo[1] += 1 # incrementar segundero
if (self.tiempo[1] >= 60): # Han pasado 60 segundos (1 minuto)?
self.tiempo[0] += 1 # incrementar minutero
self.tiempo[1] = 0 # resetear segundero
def reset(self):
self.tiempo = [0, 0, 0] # 0 minutos, 0 segundos, 0 centisegundos
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Timers")#llamar a la funcion constructor de Frame
#---------------------------------------------------
# VARIABLES
#---------------------------------------------------
self.numtimers = 20 # cuantos timers quieres 20, 50, 200?
self.CronometrArr = [] # Arreglo de registro de tiempos
self.TimeRegePattern = '{0:02d}:{1:02d}:{2:02d}' # Darle formato al tiempo
self.thread = Thread(target = self.WrkrThred) # poner funcion WrkrThred en un hilo
self.thread.daemon = True # Poner hilo en modo daemon, si el programa termina, tambien el hilo
self.exitFlag = False # Bandera para parar el ciclo del hilo
self.LblTimeRegeArr = [] # Arreglo de etiquetas de tiempos
self.BtnTimeRegrArr = [] # Arreglo de botones.
FntLblTimeRegrs = wx.Font(16, wx.MODERN, wx.NORMAL, wx.BOLD) #fuente a usar
self.TiempoStr = ""
for i in range(self.numtimers):
self.CronometrArr.append(TimeReg()) #Arreglo de objetos de registro de tiempos
self.createFiles() #crear los archivos de texto nesesarios
#---------------------------------------------------
# WIDGETS
#---------------------------------------------------
PnlTimeRegpos = ScrolledPanel(self) #Panel de lecturas de tiempos
for i in range(self.numtimers):
# crear etiquetas y llenar arreglo
self.LblTimeRegeArr.append(wx.StaticText(PnlTimeRegpos,
-1,
style = wx.ALIGN_CENTER|wx.ST_ELLIPSIZE_MIDDLE))
self.LblTimeRegeArr[i].SetFont(FntLblTimeRegrs) #asignar fuente
self.LblTimeRegeArr[i].SetBackgroundColour('black') #asignar color de fondo
self.LblTimeRegeArr[i].SetForegroundColour('white') #asignar color de letra
self.LblTimeRegeArr[i].SetLabel("00:00:00") #texto inicial
# crear botones y llenar arreglo de botones
self.BtnTimeRegrArr.append(wx.ToggleButton(PnlTimeRegpos ,
-1,
str(i),
size=(50,40)))
#--------------------------------------------------
# BINDS
#--------------------------------------------------
self.Bind(wx.EVT_CLOSE, self.onClosed) # trabajo de limpieza al salir de la aplicacion
for i in range(self.numtimers):
# poner bind a todos los botones a self.onTggleBtn
self.BtnTimeRegrArr[i].Bind(wx.EVT_TOGGLEBUTTON,self.onTggleBtn)
#---------------------------------------------------
# MAIN LAYOUT
#--------------------------------------------------
MainSizer = wx.BoxSizer(wx.VERTICAL)
#--------- Panel de lecturas ------
TimeRegposSizrArr = [] #Arreglo de sizers
PnlTimeRegposSizr = wx.BoxSizer(wx.VERTICAL)
for i in range(self.numtimers):
TimeRegposSizrArr.append(wx.BoxSizer(wx.HORIZONTAL))
TimeRegposSizrArr[i].Add(self.BtnTimeRegrArr[i],0,wx.EXPAND|wx.ALL,2)
TimeRegposSizrArr[i].Add(self.LblTimeRegeArr[i],1,wx.EXPAND|wx.ALL,2)
PnlTimeRegposSizr.Add(TimeRegposSizrArr[i],1,wx.EXPAND|wx.ALL,0)
PnlTimeRegpos.SetSizer(PnlTimeRegposSizr)
PnlTimeRegpos.SetupScrolling() #calcular espacio para scroll bar
#--------------------------------------------------
MainSizer.Add(PnlTimeRegpos, 1,wx.EXPAND|wx.ALL,5)
self.SetSizer(MainSizer)
#---------------------------------------------------
# INICIAR HILOS AL ULTIMO
#---------------------------------------------------
self.thread.start() # Iniciar hilo
def WrkrThred(self):
while True: #loop "infinito"
if self.exitFlag == False: # programa sigue corriendo?
sleep(0.01) # reterdo de 1 centi sedundo
for i in range(self.numtimers): #iterar en los registros
if self.CronometrArr[i].activado == True: #si esta activado
self.CronometrArr[i].update() #actualizar registro i
self.TiempoStr = self.TimeRegePattern.format(self.CronometrArr[i].tiempo[0],
self.CronometrArr[i].tiempo[1],
self.CronometrArr[i].tiempo[2]) #Dar formato a los tiempos
wx.CallAfter(self.LblTimeRegeArr[i].SetLabel,self.TiempoStr) #Actualizar Texto correspondiente
#wx.callafter es un modo seguro de actualizar GUI desde un hilo.
else:
break #Romper el ciclo infinito
def onTggleBtn(self, evt):
BTN = evt.GetEventObject() #obtener el objeto boton que emite la señal
BtnID = BTN.GetLabelText() #obtener el texto del boton
BtnIdInt = int(BtnID) #convertir el texto del boton en entero.
if BTN.GetValue():
self.CronometrArr[BtnIdInt].reset() #reestablecer conteo
self.CronometrArr[BtnIdInt].activado = True #iniciar conteo
else:
self.savetimefile(BtnID) #Guardar conteo
self.CronometrArr[BtnIdInt].activado = False #detener conteo
def savetimefile(self,timer):
f = open(timer+".txt", "a+")
f.write(self.TiempoStr+"\n")
f.close()
def createFiles(self):
for x in range(self.numtimers):
open(str(x)+".txt","w+").close()
def onClosed(self, evt):
self.exitFlag = True #Salir del ciclo while del hilo
self.Destroy() #Destruir TODO
if __name__ == "__main__":
app = wx.App()
frame = MyForm().Show()
app.MainLoop()
No hay comentarios.:
Publicar un comentario