Python Forum

Full Version: adding button status updates to countdown counter
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have gotten my script farther and farther along thanks to some help here. I am now trying to get things to where the temperature bar has an automatic cool down to a set level if the keyboard is not pressed, a temperature warning and stop on further key presses until a quarter second cool down occurs and then a critical alert at 100 rounds and 0 round alert. The alerts would come from one button/label. Programatically is there a good example I can reference so I can figure this out a little more easily myself?

This is the code:
import tkinter.ttk as ttk
import tkinter as tk
 
# sets ammo count to initial value of 500 
INITIAL_COUNTER_VALUE = 500
# sets initial time at 100%
INITIAL_TIMER_VALUE = 33000 
# sets initial gun terminal ID
#sets gun rate
RMMAX = 0
# sets initial temparature
TEMP_INITIAL = 30
# sets text string for ammo/temp/low ammo status button
STATUS = "OK"
# initial class declaration for main body of program
class TkApp(tk.Tk):
# these arguments initialize the class and how to form arguments within 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # set screen options
        self.geometry("640x400")
        self.configure(bg='black')
        self.title("Sentry Terminal")
        # locally initialize ammo count down
        self.counter = tk.IntVar()
        self.counter.set(INITIAL_COUNTER_VALUE)
        # locally sets the timer count down at 100%
        self.timer = tk.IntVar()
        self.timer.set(INITIAL_TIMER_VALUE)
        # locally sets rmbar to 0%
        self.rmcount = tk.IntVar()
        self.rmcount.set(RMMAX)
        # locally sets tempbar
        self.temperature = tk.IntVar()
        self.temperature.set(TEMP_INITIAL) 
        # locally sets text string for ammo status button
        self.stat = tk.StringVar()
        self.stat.set(STATUS)
        # this arranges the grid row and column groupings.  
        tk.Grid.rowconfigure(self, 0, weight=1, uniform='c')
        tk.Grid.rowconfigure(self, 1, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 2, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 3, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 4, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 5, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 6, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 7, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 8, weight=1, uniform='b')

        tk.Grid.columnconfigure(self, 0, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 1, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 2, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 3, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 4, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 5, weight=1, uniform='a')

        # these are the button and label declarations
        rounds = tk.Label(self, justify=tk.CENTER, textvariable=self.counter)
        rounds.grid(row=3, column=2, columnspan=1, sticky="EW")
        label1 = tk.Label(self, textvariable=self.timer)
        label1.grid(row=7, column=2, sticky="EW")
        temp = tk.Button(self,justify=tk.CENTER,text="Temp",bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        temp.grid(row=2,column=4,sticky="NSEW")
        rm = tk.Button(self,justify=tk.CENTER,text="R(M)",bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        rm.grid(row=2,column=5,sticky="NSEW")
        # rounds rate bar
        rmbar = ttk.Progressbar(self, orient="vertical", variable=self.rmcount)
        rmbar.grid(row=3,column=5,rowspan=6, sticky="NS")
        # temperature bar
        tempbar = ttk.Progressbar(self, orient="vertical", variable=self.temperature)
        tempbar.grid(row=3,column=4,rowspan=6,sticky="NS")
        # declarative buttons
        timestat = tk.Button(self,bg='black',state=tk.DISABLED, fg='yellow',disabledforeground='yellow',highlightbackground='yellow',borderwidth=2,justify=tk.CENTER,text="TIME AT 100% \n (msecs)")
        timestat.grid(row=7,column=0,columnspan=2,sticky="NSEW")
        roundsr = tk.Button(self,bg='black',state=tk.DISABLED, fg='yellow',disabledforeground='yellow',highlightbackground='yellow',borderwidth=2,justify=tk.CENTER,text="Rounds \n Remaining")
        roundsr.grid(row=3,column=0,columnspan=2,sticky="NS")


        # crit menu bar
        crit = tk.Button(self,justify=tk.CENTER,textvariable=self.stat, bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        crit.grid(row=5,column=0,columnspan=2,sticky="NSEW")
        

        # static center header
        headernew = tk.Button(self, bg='black',state=tk.DISABLED,justify=tk.CENTER, text="UA 571-C \n REMOTE SENTRY WEAPON SYSTEM")
        headernew.grid(row=0,column=1,columnspan=4,rowspan=2,sticky="NSEW")
        # displays gun id on top left and right of screen
        gun_1 = tk.Label(self, borderwidth=7,bg='black',fg='yellow',disabledforeground='yellow',state=tk.DISABLED,text="kp")
        gun_1.grid(row=0,column=0,rowspan=2,sticky="NS")
        gun_2 = tk.Button(self, borderwidth=7,bg='black',fg='yellow',disabledforeground='yellow',state=tk.DISABLED,text="kp")
        gun_2.grid(row=0,column=5,rowspan=2,sticky="NS")


        # this quits by clicking a button labeled q
        quit = tk.Button(self, bg='black', fg='yellow', text='q', command=self.quit)
        quit.grid(row=8,column=0,sticky="SW")

        # these are the attachments for input from keyboard into the application
        # These are the button inputs from the original flash app that were used
        # I added a q as well to quit and close window in case there was a need to close

        self.bind("<KeyPress-f>", self.on_keypress_f)
        self.bind("<KeyRelease-f>", self.on_keyrelease_f)
        self.bind("<KeyPress-a>", self.on_keypress_a)
        self.bind("<KeyPress-b>", self.on_keypress_b)
        self.bind("<KeyPress-c>", self.on_keypress_c)
        self.bind("<KeyPress-d>", self.on_keypress_d)
        self.bind("<KeyPress-r>", self.on_keypress_r)
        self.bind("<KeyPress-q>", self.on_keypress_q)
        self.bind("<KeyPress-space>", self.on_keypress_space)

    # this defines the fire ammo count down sequence and resets 
    def on_keypress_f(self, evet):
        
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)
        # this is logic to try and get ammo warnings
        if counter_value == 490:
          
          stat_value = "OUT"
        else:
          stat_value = "OK"
          self.stat.set(stat_value)
        # this sets the time at 100%
        timer_value = self.timer.get()
        timer_value = timer_value-66 or INITIAL_TIMER_VALUE
        self.timer.set(timer_value)
        # this sets the rmbar to 40%
        rmcount_count = self.rmcount.get()
        rmcount_count = 40
        self.rmcount.set(rmcount_count)
        # this sets the temperature
        temperature_count =  self.temperature.get()
        temperature_count = temperature_count+1
        self.temperature.set(temperature_count)
    def on_keyrelease_f(self, evet):
        #this adds logic to say rate is zero if not firing
        rmcount_count = self.rmcount.get()
        rmcount_count = 0
        self.rmcount.set(rmcount_count)
        # this adds logic to say if not firing cool down
        temperature_count =  self.temperature.get()
        temperature_count = temperature_count-10
        self.temperature.set(temperature_count)
    
    # this sets the gun terminal identification
    # this can also be expanded to do other things if you want to alter the script
    def on_keypress_a(self, evet):
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)

    def on_keypress_b(self, evet):
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)

    def on_keypress_c(self, evet):
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)

    def on_keypress_d(self, evet):
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)

    def on_keypress_space(self, evet):
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)

# this reloads the window, you have to click it to make it the active window again
    def on_keypress_r(self, evet):
        self.destroy()
        self.__init__()

# this quits and closes the window by hitting a single key
    def on_keypress_q(self, evet):
        self.quit()
 
# this executes the main loop and tkinter self delcared class.  It declares the function then runs it in the main loop. 
tk_app = TkApp()
tk_app.mainloop()
If I need to make a separate thread on each Issue, just say the word and I will do so.
You could do this by using a timer similar to this post
You can then check on the state of things at a certain interval of time passed and adjust things as needed.
(Apr-15-2021, 06:26 PM)Yoriz Wrote: [ -> ]You could do this by using a timer similar to this post
You can then check on the state of things at a certain interval of time passed and adjust things as needed.

Well I added these functions to the class:
    def coolbar(self):
        temperature_count = self.temperature.get()
        self.temperature.set(temperature_count)
        while temperature_count >= 20:
          self.temperature.set(temperature_count)
          temperature_count = temperature_count-1
          self.temperature.set(temperature_count)
          print("key not pressed")
 #         time.sleep(0.1)          

    def overheat(self):
        temperature_count = self.temperature.get()
        temperature_count = temperature_count-1
        self.temperature.set(temperature_count)
        print("overheat")
        time.sleep(0.1)
The coolbar or cooldown function auto resets to the starting value on the bar. It behaves kind of like I want.

The coolbar only seems to work when I use a while loop. Unfortunately I can not use a time.sleep function on it as that seems to break things. I think the issue is that it is not updating the screen draw as it is cooling down in the while loop.
A while loop with a time.sleep will block the GUI's loop which I why I suggested using a timer and altering the state at an interval of time passed.
(Apr-17-2021, 04:40 PM)Yoriz Wrote: [ -> ]A while loop with a time.sleep will block the GUI's loop which I why I suggested using a timer and altering the state at an interval of time passed.

I have slept some. I will try that approach again. Learning is learning. Failing to make something work teaches one that a way of doing something does not work.

Thanks for the pointers and help!
With the example you provided using the:
self.after(msec, self.function)
helped a lot.

I just have to figure out logic to make the cycling work properly, but that is progressing slowly, I think. logic in programs is not failable, only the creator is.
The bars are working the way I want now. the self.after(msec, functionname) command did the trick.

This function:
    def coolbar(self):
        temperature_count = self.temperature.get()
        if temperature_count >= 21:
          temperature_count = self.temperature.get()
          temperature_count = temperature_count-1 or TEMP_INITIAL      
          self.temperature.set(temperature_count)
          print("key not pressed", temperature_count)
          self.after(300, self.coolbar)
with this one on key release f:

    def on_keyrelease_f(self, evet):
        #this adds logic to say rate is zero if not firing
        #this automatically turns off rate bar moment key is released fixing a logic issue
        rmcount_count = self.rmcount.get()
        rmcount_count = 0
        self.rmcount.set(rmcount_count)
        temperature_count =  self.temperature.get()
        if temperature_count >= 20:
          self.coolbar()
but I had to add this on keypress f:

    def on_keypress_f(self, evet):        
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)
        counter_value = self.counter.get()
        # this is logic to try and get ammo warnings
        counter_value = self.counter.get()

        self.reload()
        self.critical()
        self.out()

 
        # this sets the time at 100%
        timer_value = self.timer.get()
        timer_value = timer_value-66 or INITIAL_TIMER_VALUE
        self.timer.set(timer_value)
        # this sets the rmbar to 40%
        rmcount_count = self.rmcount.get()
        rmcount_count = 40
        self.rmcount.set(rmcount_count)
        # this sets the temperature
        temperature_count =  self.temperature.get()
        temperature_count = temperature_count+1
        self.temperature.set(temperature_count)
        if temperature_count == 90:
          self.coolbar()
          self.overheat()
        else:
          state_stat = self.stat.get()
          state_stat = ""
          self.stat.set(state_stat)
Now on to updating a label depending upon temp reading or ammo levels. I am thinking it is a logic issue with the way the readings are taken and then updated.

import tkinter.ttk as ttk
import tkinter as tk
import datetime as dt
import time
#import os
#from tkinter import messagebox
from threading import Thread

 
# sets ammo count to initial value of 500 
INITIAL_COUNTER_VALUE = 500
# sets initial time at 100%
INITIAL_TIMER_VALUE = 33000 
# sets initial gun terminal ID
#sets gun rate
RMMAX = 0
# sets initial temparature
TEMP_INITIAL = 20
# sets text string for ammo/temp/low ammo status button
STATUS = ""

COOLED = 20

GUN = ""

# initial class declaration for main body of program
class TkApp(tk.Tk):
# these arguments initialize the class and how to form arguments within 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # set screen options
        self.geometry("640x400")
        self.configure(bg='black')
        self.title("Sentry Terminal")
        # locally initialize ammo count down
        self.counter = tk.IntVar()
        self.counter.set(INITIAL_COUNTER_VALUE)
        # locally sets the timer count down at 100%
        self.timer = tk.IntVar()
        self.timer.set(INITIAL_TIMER_VALUE)
        # locally sets rmbar to 0%
        self.rmcount = tk.IntVar()
        self.rmcount.set(RMMAX)
        # locally sets tempbar
        self.temperature = tk.IntVar()
        self.temperature.set(TEMP_INITIAL) 
        # locally sets text string for ammo status button
        self.stat = tk.StringVar()
        self.stat.set(STATUS)
#
        self.cooldown = tk.IntVar()
        self.stat.set(COOLED)

        self.gun = tk.StringVar()
        self.gun.set(GUN)

        # this arranges the grid row and column groupings.  
        tk.Grid.rowconfigure(self, 0, weight=1, uniform='c')
        tk.Grid.rowconfigure(self, 1, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 2, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 3, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 4, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 5, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 6, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 7, weight=1, uniform='b')
        tk.Grid.rowconfigure(self, 8, weight=1, uniform='b')

        tk.Grid.columnconfigure(self, 0, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 1, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 2, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 3, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 4, weight=1, uniform='a')
        tk.Grid.columnconfigure(self, 5, weight=1, uniform='a')

        # these are the button and label declarations
        rounds = tk.Label(self, justify=tk.CENTER, textvariable=self.counter)
        rounds.grid(row=3, column=2, columnspan=1, sticky="EW")
        label1 = tk.Label(self, textvariable=self.timer)
        label1.grid(row=7, column=2, sticky="EW")

        temp = tk.Button(self,justify=tk.CENTER,text="Temp",bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        temp.grid(row=2,column=4,sticky="NSEW")

        rm = tk.Button(self,justify=tk.CENTER,text="R(M)",bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        rm.grid(row=2,column=5,sticky="NSEW")
        # rounds rate bar
        rmbar = ttk.Progressbar(self, orient="vertical", variable=self.rmcount)
        rmbar.grid(row=3,column=5,rowspan=6, sticky="NS")

        # temperature bar
        tempbar = ttk.Progressbar(self, orient="vertical", variable=self.temperature)
        tempbar.grid(row=3,column=4,rowspan=6,sticky="NS")

        # declarative buttons
        timestat = tk.Button(self,bg='black',state=tk.DISABLED, fg='yellow',disabledforeground='yellow',highlightbackground='yellow',borderwidth=2,justify=tk.CENTER,text="TIME AT 100% \n (msecs)")
        timestat.grid(row=7,column=0,columnspan=2,sticky="NSEW")
        roundsr = tk.Button(self,bg='black',state=tk.DISABLED, fg='yellow',disabledforeground='yellow',highlightbackground='yellow',borderwidth=2,justify=tk.CENTER,text="Rounds \n Remaining")
        roundsr.grid(row=3,column=0,columnspan=2,sticky="NS")


        # crit menu bar
        crit = tk.Button(self,justify=tk.CENTER,textvariable=self.stat, bg='black', fg='yellow', highlightbackground='yellow', highlightcolor='black',activebackground='yellow')
        crit.grid(row=5,column=0,columnspan=2,sticky="NSEW")
        

        # static center header
        headernew = tk.Button(self, bg='black',state=tk.DISABLED,justify=tk.CENTER, text="UA 571-C \n REMOTE SENTRY WEAPON SYSTEM")
        headernew.grid(row=0,column=1,columnspan=4,rowspan=2,sticky="NSEW")




        # displays gun id on top left and right of screen
        gun_1 = tk.Label(self, borderwidth=7,bg='black',fg='yellow',disabledforeground='yellow',state=tk.DISABLED,textvariable=self.gun)
        gun_1.grid(row=0,column=0,rowspan=2,sticky="NS")
        gun_2 = tk.Button(self, borderwidth=7,bg='black',fg='yellow',disabledforeground='yellow',state=tk.DISABLED,textvariable=self.gun)
        gun_2.grid(row=0,column=5,rowspan=2,sticky="NS")


        # this quits by clicking a button labeled q
        quit = tk.Button(self, bg='black', fg='yellow', text='q', command=self.quit)
        quit.grid(row=8,column=0,sticky="SW")

        # these are the attachments for input from keyboard into the application
        # These are the button inputs from the original flash app that were used
        # I added a q as well to quit and close window in case there was a need to close

        self.bind("<KeyPress-f>", self.on_keypress_f)
        self.bind("<KeyRelease-f>", self.on_keyrelease_f)
        self.bind("<KeyPress-a>", self.on_keypress_a)
        self.bind("<KeyPress-b>", self.on_keypress_b)
        self.bind("<KeyPress-c>", self.on_keypress_c)
        self.bind("<KeyPress-d>", self.on_keypress_d)
        self.bind("<KeyPress-r>", self.on_keypress_r)
        self.bind("<KeyPress-q>", self.on_keypress_q)
        self.bind("<KeyPress-space>", self.on_keypress_space)
    #    self.coolbar(temperature_count)

    def coolbar(self):
        temperature_count = self.temperature.get()
        if temperature_count >= 21:
          temperature_count = self.temperature.get()
          temperature_count = temperature_count-1 or TEMP_INITIAL      
          self.temperature.set(temperature_count)
          print("key not pressed", temperature_count)
          self.after(300, self.coolbar)
    

    def overheat(self):
        rmcount_count = self.rmcount.get()
        rmcount_count = 0
        self.rmcount.set(rmcount_count)
        state_stat = self.stat.get()
        state_stat = "OVERHEAT"
        self.stat.set(state_stat)
        time.sleep(0.7)

    def critical(self):
        counter_value = self.counter.get()
        if counter_value <= 50:
          counter_value = self.counter.get()
          state_stat = self.stat.get()
          state_stat = "CRITICAL"
          self.stat.set(state_stat)
          counter_value = self.counter.get()
          print("ammo CRIT", counter_value) 

    def out(self):
        counter_value = self.counter.get()
        if counter_value == 1:
          state_stat = self.stat.get()
          state_stat = "OUT"
          self.stat.set(state_stat)
          counter_value = self.counter.get()
          print("ammo CRIT", counter_value) 

    def reload(self):
        counter_value = self.counter.get()
        if counter_value >= 1:
          state_stat = self.stat.get()
          state_stat = ""
          self.stat.set(state_stat)
          counter_value = self.counter.get()
          print("ammo CRIT", counter_value)


    # this defines the fire ammo count down sequence and resets 
    def on_keypress_f(self, evet):        
        counter_value = self.counter.get()
        counter_value = counter_value-1 or INITIAL_COUNTER_VALUE
        self.counter.set(counter_value)
        counter_value = self.counter.get()
        # this is logic to try and get ammo warnings
        counter_value = self.counter.get()

        self.reload()
        self.critical()
        self.out()

 
        # this sets the time at 100%
        timer_value = self.timer.get()
        timer_value = timer_value-66 or INITIAL_TIMER_VALUE
        self.timer.set(timer_value)
        # this sets the rmbar to 40%
        rmcount_count = self.rmcount.get()
        rmcount_count = 40
        self.rmcount.set(rmcount_count)
        # this sets the temperature
        temperature_count =  self.temperature.get()
        temperature_count = temperature_count+1
        self.temperature.set(temperature_count)
        if temperature_count == 90:
          self.coolbar()
          self.overheat()
        else:
          state_stat = self.stat.get()
          state_stat = ""
          self.stat.set(state_stat)

    def on_keyrelease_f(self, evet):
        #this adds logic to say rate is zero if not firing
        #this automatically turns off rate bar moment key is released fixing a logic issue
        rmcount_count = self.rmcount.get()
        rmcount_count = 0
        self.rmcount.set(rmcount_count)
        temperature_count =  self.temperature.get()
        if temperature_count >= 20:
          self.coolbar()
   
    # this sets the gun terminal identification
    # this can also be expanded to do other things if you want to alter the script
    def on_keypress_a(self, evet):
        which_gun = self.gun.get()
        which_gun = "A"
        self.gun.set(which_gun)

    def on_keypress_b(self, evet):
        which_gun = self.gun.get()
        which_gun = "B"
        self.gun.set(which_gun)

    def on_keypress_c(self, evet):
        which_gun = self.gun.get()
        which_gun = "C"
        self.gun.set(which_gun)

    def on_keypress_d(self, evet):
        which_gun = self.gun.get()
        which_gun = "D"
        self.gun.set(which_gun)

    def on_keypress_space(self, evet):
        print("space pressed")

# this reloads the window, you have to click it to make it the active window again
    def on_keypress_r(self, evet):
        self.destroy()
        self.__init__()

# this quits and closes the window by hitting a single key
    def on_keypress_q(self, evet):
        self.quit()
 
# this executes the main loop and tkinter self delcared class.  It declares the function then runs it in the main loop. 
tk_app = TkApp()

tk_app.mainloop()
I am slowly figuring this out.