Timer in Guizero/ TKinter - python-3.x

Right now I am busy with making a GUI for my project. It also needs a test driven by time. However when I press the start button, the counter starts counting but the Gui freezes, so you cannot press the stop button. And eventually the Program stall and shut his self down.
Take a look at my code :
###import libaries ###
from guizero import *
import tkinter as tk
import time
timeLoop = False
###Variabelen###
Sec = 0
Min = 0
Hour = 0
test_stat = 0
###Define Loops###
def verlaat_settings():
window2.hide()
window3.hide()
window4.hide()
window.show(wait=True)
def stop_test():
info("test_result","Test stopped at" + str(Hour) + " Hour " + str(Min) + " Mins " + str(Sec) + " Sec ")
text_test.value = "Test Stopped..."
timeLoop: False
def test_loopt():
global Sec
global Min
text_test.value = "Test is running....."
timeLoop = True
while timeLoop:
Sec +=1
print(str(Min) + " Mins " + str(Sec) + " Sec ")
time.sleep(1)
if Sec == 60:
Sec = 0
Min += 1
app= App(title="Profiberry",layout="",width=480, height=272)
window3 = Window(app,title="Profiberry-Tester", layout="grid",width=480, height=272)
window3.show
###Window3###
welkom_tester= Text(window3, text="Profibus Tester",grid=[2,0,1,1])
Plaatje_profi= Picture(window3,image="logoprofi.gif",grid=[2,1,1,1])
lege_ruimte1 = Text(window3, text="", grid=[2,2,1,1])
text_test= Text(window3,text=" Waiting for input..... ",grid=[2,3,1,1])
timer_test= Text(window3,text=(""),grid=[2,4,1,1] )
lege_ruimte2 = Text(window3, text="", grid=[2,5,1,1])
lege_ruimte2 = Text(window3, text="", grid=[1,6])
Start_knop= PushButton(window3,text="Start",command=test_loopt,padx=50, pady=10, grid=[1,6] )
Start_knop.tk.config(foreground="white",background="green")
Stop_knop= PushButton(window3,text="Stop",command=stop_test,padx=50,pady=10,grid=[3,6])
Stop_knop.tk.config(foreground="white",background="red")
Exit_setting = PushButton(window3,command=verlaat_settings,text="Exit to Main Menu(F2)",padx=30,pady=10,grid=[2,6])
I will talk you trough this part of my program:
Import the libraries used for this purpose.
Give timeLoop, our while variable, a false state.
Give our variables value.
Below that are our Def loops verlaat_settings is used to move trough windows in the GUI Stop_test is used to preform actions when stop is pressed (also to reset the while state) test_loopt is the actual test, the counter has to run by here what it does in the shell.
Below that we open the window and place the widgets.

This answer is to help over users encountering a similar situation.
Although the proposed answer is imaginative, it is a bit long winded.
In GuiZero, the .display() function creates an infinite loop. Therefore, any use of normal python time functions will prevent the display loop from executing.
When using GuiZero, do not use sleep, or while loops.
It is simpler and easier to use .repeat(duration, command)
For instance the code above should work if this line:
Start_knop= PushButton(window3,text="Start",command=test_loopt,padx=50, pady=10, grid=[1,6] )
is changed into those:
Start_knop= PushButton(window3,text="Start",padx=50, pady=10, grid=[1,6])
Start_knop.repeat(1000, test_loopt)
and the original test_loopt function:
def test_loopt():
global Sec
global Min
text_test.value = "Test is running....."
timeLoop = True
while timeLoop:
Sec +=1
print(str(Min) + " Mins " + str(Sec) + " Sec ")
time.sleep(1)
if Sec == 60:
Sec = 0
Min += 1
if Min == 60:
Sec = 0
Min = 0
Hour = 1
if stop_test():
timeLoop = False
is modified as:
def test_loopt():
global Secs, Mins, Hrs
text_test.value = "Test is running....."
Secs +=1
print(str(Hrs) + " Hours " + str(Min) + " Mins " + str(Sec) + " Sec ")
if Secs%60 == 0:
Secs = 0
Mins += 1
if Min%60 == 0:
Secs, Mins = 0, 0
Hrs += 1
If must be noted that the result is not displayed on the GUI but in the IDE and that there is no end to this loop.
It is also necessary to modify the stop_test function from:
def stop_test():
info("test_result","Test stopped at" + str(Hour) + " Hour " + str(Min) + " Mins " + str(Sec) + " Sec ")
text_test.value = "Test Stopped..."
timeLoop: False
to
def stop_test():
info("test_result","Test stopped at" + str(Hrs) + " Hour " + str(Mins) + " Mins " + str(Secs) + " Sec ")
text_test.value = "Test Stopped..."
Start_knop.after(pause_loop)
def pause_loop():
pass
or something along those lines

so after searching for a while I found a page on here with someone on python 2.7 having the exact same problem.
the solution to this is that everything runs in the main loop and the main loop waits for ever on this test_loopt the solution was making a Thread, which in my case was :
def test_loopt():
global Sec
global Min
text_test.value = "Test is running....."
timeLoop = True
while timeLoop:
Sec +=1
print(str(Min) + " Mins " + str(Sec) + " Sec ")
time.sleep(1)
if Sec == 60:
Sec = 0
Min += 1
if Min == 60:
Sec = 0
Min = 0
Hour = 1
if stop_test():
timeLoop = False
def start_test_loopt_thread():
global test_loopt_thread
test_loopt_thread = threading.Thread(target=test_loopt)
test_loopt_thread.deamon = True
test_loopt_thread.start()

There's a basic answer to this in GuiZero's Documentation. The problem is that, because of the loop, GuiZero's display loop is being blocked, like you said, stalling it and eventually crashing it. This is because GuiZero is an event-driven loop, which is why it uses the .display() loop to check for events.
You need to use the .repeat method (shown below) for the application to repeat that action.
.repeat( [enter delay here in milliseconds] , [command to execute] )
This means the loop in the function is not needed.
I understand I'm a bit late to answer this question, but I hope it helped.

Related

Timer shutdown computer(python3.x)

i had code a timer shutdown pc which will shutdown after the times up, but it will keep printing the time remaining which is not good if i want to shutdown my computer after 30 minutes, it will print about 1800 lines, how should i modify it if i want it to print one line of time remaining which will keep changing.
import time
seconds = int(input("seconds:"))
for i in range(seconds):
x = (seconds - i)
print(x)
time.sleep(1)
check = input("do u want to shutdown ur computer?(yes/no):")
if check == "no":
exit()
else:
os.system("shutdown /s /t 1")
Try this. Just replace the string "Shutdown has started" with the shutdown command.
import time
import sys
x=int(input("seconds: "))
print("The timer has started. Time remaining for shut down: ")
def custom_print(string, how = "normal", dur = 0, inline = True):
if how == "typing": # if how is equal to typing then run this block of code
letter = 1
while letter <= len(string):
new_string = string[0:letter]
if inline: sys.stdout.write("\r")
sys.stdout.write("{0}".format(new_string))
if inline == False: sys.stdout.write("\n")
if inline: sys.stdout.flush()
letter += 1
time.sleep(float(dur))
if new_string=="0":
print("\nShut down has started")
else:
pass
for k in range(1,x+1):
k=x-k
custom_print(str(k), "typing", 1)

How do I keep printing after the user has given the input?

from timeit import default_timer as timer
import random
num_1 = random.choice(range(12))
num_2 = random.choice(range(12))
score = 0
start = timer()
end = timer()
t = (end - start) # Time in seconds, e.g. 5.38091952400282
if t < 5 :
score += 100
if t > 5 :
score += 50
print(score)
how do i print the input again???
like after i have written what is 6 * 8 for example it gives me the score. How do i ask users for the question again???
Put the input inside the while loop:
num_1 = random.choice(range(12))
num_2 = random.choice(range(12))
score = 0
start = timer()
end = timer()
t = (end - start) # Time in seconds, e.g. 5.38091952400282
while True:
ans = input("what is "+num1" * "+num2+"?")
if t < 5 :
score += 100
if t > 5 :
score += 50
print(score)

Keep getting else/elif invalid syntax error

Currently I'm writing a code where I want to ask motor values from motor controller using raspberry pi. However my code is throwing InvalidSyntax Error in else and elif statements. I've already read about if and elif statements in python, but I can't figure out mistake by myself. The code is below:
def motor_values():
while 1:
command_1 = '?A '+str(1)+' \r' #Asking first motor current
command_2 = '?A '+str(2)+' \r' #Asking second motor current
counter = 0
#First motor current
if counter = 0:
ser.write(command_1.encode()) #string to bytes
data_1 = ser.readline().decode().strip() #bytes to string
#Checking if data is received and extracting current value
if 'A=' in data_1:
value_1 = int(data_1.split('=')[1])
print("Motor Current(Channel 1): " + str((value_1) + " Ampers")
counter += 1
else:
print("Message is not received")
#Second motor current
elif counter == 1:
ser.write(command_2.encode()) #string to bytes
data_2 = ser.readline().decode().strip() #bytes to string
if 'A=' in data_2:
value_2 = int(data_2.split('=')[1])
print("Motor Current(Channel 2): " + str((value_2) + " Ampers")
counter += 1
else:
print("Message is not received")
else:
counter = 0
A few syntax errors here:
use == in the if clause condition
#First motor current
if counter == 0: #
remove one of the two ( in str((value_2)
print("Motor Current(Channel 1): " + str(value_1) + " Ampers")
print("Motor Current(Channel 2): " + str(value_2) + " Ampers")
you missed closing brace in print function
print("Motor Current(Channel 1): " + str(value_1) + " Ampers")

Euler 12 need optimization

I have solved euler problem 12, but it needs some optimization. I have read on the euler forums, but it has not helped me optimized it. However, I have managed to get the solution, I just need to speed it up. It currently takes 4 minutes to run. Here is my code:
import time
def nthtriangle(n):
return (n * (n + 1)) / 2
def numberofnfactors(n):
count = 0
if n==1:
return 1
for i in range(1, 1 + int(n ** 0.5)):
if n % i == 0:
count += 2
return count
def FirstTriangleNumberWithoverxdivisors(divisors):
found = False
counter = 1
while not found:
print(int(nthtriangle(counter)), " ", numberofnfactors(nthtriangle(counter)))
if numberofnfactors(nthtriangle(counter)) > divisors:
print(" first triangle with over ",divisors, " divisors is ", int(nthtriangle(counter)))
found = True
break
counter += 1
start_time = time.time()
FirstTriangleNumberWithoverxdivisors(500)
print("My program took", time.time() - start_time, "to run")
Instead of calculating each triangle number individually, use a generator to get the triangle numbers
from timeit import timeit
def triangle_numbers():
count = 1
num = 0
while True:
num += count
count += 1
yield num
def count_divisors(n):
count = 0
if n==1:
return 1
for i in range(1, 1 + int(n ** 0.5)):
if n % i == 0:
count += 2
return count
print(timeit('next(num for num in triangle_numbers() if count_divisors(num) >= 500)',
globals=globals(), number=1))
Gives me 3.8404819999996107 (seconds) on my machine. You could probably also improve the divisor counting.
What's really slowing you down is calling nthtriangle and numberoffactors more than once in your loop! Plus, those calls to print aren't free.

Python: Using Variable From Different Function Without Renaming

I'm working on creating a short battle from a game (for fun). I have several variables that need to change throughout the sequence, such as m_hp (monster health). Here is the code I have (Forgive me if I formatted incorrectly, this is my first time using this website):
def battle(p_lvl):
print("A goblin engages you in battle!")
p_hp = p_lvl * 25 + 25
p_dmg = p_lvl * 7 + 5
print("Player Stats (Level: " + str(p_lvl) + " Health: " + str(p_hp) + " ATK: " + str(p_dmg) + ")")
m_lvl = p_lvl - 1
m_hp = m_lvl * 20 + 15
m_dmg = m_lvl * 6 + 3
scr_dmg = m_hp / 4
dus_eft = p_hp / 5
print("Goblin Stats (Level: " + str(m_lvl) + " Health: " + str(m_hp) + " ATK: " + str(m_dmg) + ")")
act()
def act():
menu = 'Attack','Block','Use Item'
print("What will you do?")
print(menu)
action = input()
if action == ‘Attack':
m_hp = m_hp - p_dmg
print("You dealt " + str(p_dmg) + "damage to the goblin!")
p_hp = p_hp - m_dmg
print("The goblin struck back with " + str(m_dmg) + " damage!”)
act()
I get problems after act() initiates. If I enter "attack" for the input(), I get this error:
UnboundLocalError: local variable 'm_hp' referenced before assignment
To my understanding, this is because I have m_hp placed under battle(), but act() cannot reach it. I want to be able to change m_hp without writing it in act(). I believe if I do so, then m_hp will reset each time act() initiates, and m_hp cannot drop. I've searched through questions on here, but the cases I've seen don't seem to work. Also, I am admittedly new to coding, so I couldn't understand some of the solutions.
Tl;dr I'm looking for a simple solution as to how to use variables from a different function without putting them into the function.
You're seeing that error message because the 'm_hp' variable is local to the scope of the 'battle' function. It is created inside the function, and ceases to exist after that function exits.
It doesn't look like battle actually gets called anywhere though...
It also looks like you call the act() function before you define it.
There are a number of other reasons why the code would not run if that error was fixed as well.
The feature you're probably looking for where you have access to variables inside multiple functions without passing them in is some kind of global variable. In general, global variables are strongly discouraged anywhere they can be reasonably avoided.
I've retooled your code a bit so that you have something working to mess around with. I've used classes to try to group related things together.
There is now a 'Player' object with all the player's stats and a 'Monster' object with all the monster's stats.
Try running the code below, then making incremental changes and seeing if it continues to run.
class Player(object):
def __init__(self, level):
self.level = level
self.stats_for_level()
def stats_for_level(self):
self.attack_damage = (self.level * 7) + 5
self.hitpoints = (self.level * 25) + 25
def take_damage(self, damage):
self.hitpoints -= damage
def print_stats(self):
print("Player Stats (Level: " + str(self.level) +
" Health: " + str(self.hitpoints) +
" ATK: " + str(self.hitpoints) + ")")
class Monster(object):
def __init__(self, level, name="Goblin"):
self.level = level
self.name = name
self.stats_for_level()
def stats_for_level(self):
self.attack_damage = (self.level * 6) + 3
self.hitpoints = (self.level * 20) + 15
def take_damage(self, damage):
self.hitpoints -= damage
def print_stats(self):
print(self.name + " Stats (Level: " + str(self.level) +
" Health: " + str(self.hitpoints) +
" ATK: " + str(self.hitpoints) + ")")
class Game(object):
def __init__(self, starting_level=1):
self.player = Player(starting_level)
# create monster
self.monster = Monster(level=self.player.level - 1, name='Goblin')
def battle(self, player, monster):
print("A {} engages you in battle!".format(monster.name))
monster.take_damage(player.attack_damage)
print("You dealt " + str(player.attack_damage) + " damage to the goblin!")
self.player.take_damage(monster.attack_damage)
print("The goblin struck back with " + str(monster.attack_damage) + " damage!")
def act(self):
# print stats
self.player.print_stats()
self.monster.print_stats()
# show menu
menu = 'Attack', 'Block', 'Use Item'
print(menu)
print("\nWhat will you do?: ")
action = input()
# take an action
if action == 'Attack':
self.battle(self.player, self.monster)
def main():
game = Game(starting_level=3)
while(True):
game.act()
if __name__ == '__main__':
main()

Resources