Time.sleep() affecting the code above it in python - python

I am making a KIVY program in python and have a time.sleep(3) in my code so that it waits three seconds before changing the screen. But the function above it works after the 3 seconds and not before it. I am having no errors and I have tried everything but nothing seems to work.
Here is the snippet.
def input_button(self, instance): # creating the button that when pressed updates the label
query = "You Said {}".format(self.command()) # making the query
if query == "You Said None":
self.update_info('Please input a command')
else:
self.update_info(query) # updating the label
time.sleep(3)
pa_app.screen_manager.current = "Result"
The self.update_info(query) runs after three seconds but the time.sleep is after it.

I fixed this problem by using the from kivy.clock import as Clock module. I used Clock.schedule_once functions and passed self.change_screen, 10. I created the self.change_screen function as the Clock.schedule_once only takes a function and time as the parameters. Although I wanted to wait for 3 seconds, passing 3 in the function didn't make it wait for 3 seconds but less than it. So for having the same effect I passed in 10. This solved the problem.

Kivy is a GUI framework and you cannot add sleep statements safely.
when
self.update_info(query)
is called kivy will update the GUI only after the last line of your function is called, because this is when you give back the control to the Kivy gui engine.
You have to check whether kivy does have timers.
You can start a timer and tell it to call another function that does the
pa_app.screen_manager.current = "Result"
whenever the timer finished.

Related

How can my program be prevented from freezing?

I have decided to finally work on a project, as I've tried to code in python before, with at least some success. In my project, I am trying to build a menu that lets me "Auto-farm" in a game. It uses 3 modules, namely pynput, pause, and PySimpleGUI.
Whenever I run the code, it runs fine, until I click the button that starts the automation part. It runs completely fine, but I have to force close the GUI prompt that shows up as it just completely stops responding to input until you close it.
How I can make a stop button, and stop my program from freezing up?
I am using 2 files to keep this project slightly more organized, although I don't know if this is the best way to go around doing this. These 2 files are main.py and chand.py.
main.py
import PySimpleGUI as sg
import chand
loop = 0
layout = [[sg.Text("Welcome to RedGrowie's autofarm menu!")], [sg.Button("Chandeliers")]]
window = sg.Window("Autofarming Menu", layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
if event == "Chandeliers":
loop = 1
if loop == 1:
chand.Chandeliers.start(self=chand.Chandeliers)
window.close
chand.py
from pynput.keyboard import Key, Controller
import pause
keyboard = Controller()
start = "0"
class Chandeliers:
def d_press(self):
keyboard.press("d")
pause.milliseconds(70)
keyboard.release("d")
pause.milliseconds(300)
keyboard.release(Key.space)
def space_press(self):
keyboard.press(Key.space)
pause.milliseconds(1)
#keyboard.release(Key.space)
def start(self):
start = "1"
while start == "1":
self.d_press(self)
self.space_press(self)
Your Chandeliers.start function loops indefinitely, so the call from the main loop in main.py never gets returned to. If you want both loops to be running at the same time, you probably need to use threading or some other means of concurrency. Or you might be able to interleave the two loops somehow, depending on the timing requirements for each one.
As a side note, you are using your Chandeliers class in a very odd way. You're never creating an instance of the class, but rather calling the methods it defines as if they were class methods (but with manual passing of the class, in the misleadingly named self argument.
You should probably not do that. Either treat the class as a normal one, and create an instance:
cha = chand.Chandeliers()
chat.start() # and change start to not manually pass self any more
Or you should do away with the unneeded class all together and just make the methods into top-level functions.

Python tkinter time.sleep()

How come when I run my code, it will sleep for 3 seconds first, then execute the 'label' .lift() and change the text? This is just one function of many in the program. I want the label to read "Starting in 3...2...1..." and the numbers changing when a second has passed.
def predraw(self):
self.lost=False
self.lossmessage.lower()
self.countdown.lift()
self.dx=20
self.dy=0
self.delay=200
self.x=300
self.y=300
self.foodx=self.list[random.randint(0,29)]
self.foody=self.list[random.randint(0,29)]
self.fillcol='blue'
self.canvas['bg']='white'
self.lossmessage['text']='You lost! :('
self.score['text']=0
self.countdown['text']='Starting in...3'
time.sleep(1)
self.countdown['text']='Starting in...2'
time.sleep(1)
self.countdown['text']='Starting in...1'
time.sleep(1)
self.countdown.lower()
self.drawsnake()
It does this because changes in widgets only become visible when the UI enters the event loop. You aren't allowing the screen to update after calling sleep each time, so it appears that it's sleeping three seconds before changing anything.
A simple fix is to call self.update() immediately before calling time.sleep(1), though the better solution is to not call sleep at all. You could do something like this, for example:
self.after(1000, lambda: self.countdown.configure(text="Starting in...3"))
self.after(2000, lambda: self.countdown.configure(text="Starting in...2"))
self.after(3000, lambda: self.countdown.configure(text="Starting in...1"))
self.after(4000, self.drawsnake)
By using after in this manner, your GUI remains responsive during the wait time and you don't have to sprinkle in calls to update.

Urwid ProgessBar does not update properly

I'm playing around with the urwid library and it's been pretty great so far.
But i can't get the Progressbar to work. I wrote a simple test program like this:
import os
import urwid
# a function that takes some times to complete
def dosomething(steps, bar):
bar.done = steps
for i in range(steps + 1):
bar.set_completion(i)
os.system('sleep 0.2')
# make a button to start
task_btn = urwid.Button(u'Task')
# progressbar object
pbar = urwid.ProgressBar('pg normal', 'pg complete')
# function called when the task button is clicked
def on_task_clicked(button):
dosomething(10, pbar)
# setup signal handler for the button
urwid.connect_signal(task_btn, 'click', on_task_clicked)
"""
create the interface and the mainloop.
filler objects are our friend to prevent unpacking errors :D
"""
loop = urwid.MainLoop(urwid.Pile([urwid.Filler(task_btn), urwid.Filler(pbar)]))
loop.run()
If i start it the progressbar is to 0% as it should be. Then i press the button, and a few seconds later the progressbar shows 100%. but i'm missing the steps between 0% and 100%. they just won't show up.
Also an additional call of the render function won't work.
I've also tried something like this:
def on_task_clicked(button):
pbar.set_completion(pbar.current+1)
And this works just fine. It just seems that the progressbar is not happy with being called in a loop. That seems strange?! Someone got any ideas in order to resolve this?
Thanks in advance :)
PS:
INFO:
urwid 1.2.0
tested on python 2.6.6, 2.7, 3.3 all the same
It's probably because the main loop's draw_screen method isn't being called (it's normally called automatically when the loop enters the idle state).
Add loop.draw_screen() inside your for-loop.

Is there an instant-updating function for texts or patterns as button.config() in tkinter?

I wrote a modified program of the 'mines' game, and I hope it shows every step/click graphically. I use time.sleep(0.5) to make a pause. So, in general the main program is like:
check_block():
if mine == 0:
buttons[current].config(image = tile_clicked)
elif mine == 1:
buttons[current].config(image = tile[1])
...
while(1):
time.sleep(0.5)
check_block()
get_next()
if check_fail():
break
However, the buttons don't update every 0.5 second: they are all updated together when the game(loop) finishes.
I guess it's just like 'cout' in C++: if you don't flush they will get stacked. So, is there a method to get them updated step by step, or say, instantly?
Thanks!
In all GUI systems you have to allow the message loop to run so that Windowing events occur promptly. So do not use a while loop like this. Instead, create a method that calls check_block() and get_next() and use after to call that function after a delay. At the end of that function, you use after again to call the same function again so that this function is called every 0.5 second forever. The after function queues a timer event and then lets the message queue be processed. Once your timer event fires, the callback function is run which allows you to do things and keep the UI responsive.
You should never call sleep in a GUI program. This is because the GUI must be "awake" at all times so that it can service events (including internal events that cause the screen to update). Instead, leverage the already-running eventloop by using the after method to put events on the queue at regular intervals.
In your case, you would replace the while loop with something like:
def do_check():
check_block()
if not check_fail():
root.after(500, do_check)
# in your initialization code, start the loop by calling it directly:
do_check()
I don't know what your get_next function does, so I don't know if you need to call it periodically too. Probably not. I'm guessing it waits for the next button press, which you don't need to do with tkinter or most other GUI toolkits. Instead, you configure the button to call a function when clicked.
Regardless, the way to do the type of looping you want is to place events on the event queue at a regular interval.

Python using turtle button

I am attempting for a homework assignment to implement Simon Says in python. I'm trying to do it using the turtle library (a requirement).
However, I've run into a stumbling block in that while I can get the screen to register click events (currently just printing the x,y coordinates) I can't get it to wait for a click event.
Specifically what I'm planning on doing is having areas on the screen that when they click within that location it is considered as if they had clicked a button. Screen clears and game does whatever.
However, in experiments in trying to get a working 'button' all that it does is set it so it prints the x,y coordinates but the rest of the program finishes. Didn't wait for the user to click anything. I tried a blocking method of...
while clicked == False:
pass
or
while clicked == False:
time.sleep(1)
but both methods hangs the program until I manually interrupt and then it'll print the clicks.
Am I missing an option somewhere?
Turtles don´t have buttons, but they do have callbacks for clicks.
Furthermore, you should use onclick for Screen to detect general clicks and onclick for turtle to detect clicking in turtles. You can, for example, make a 4 BIG turtles with different colors by using a dynamic shape.
Also, turtle is based on Tk, so you must be aware of things like mainloop()
The following program give some hints for Python 2.7.5.
import turtle as t
from random import randint
class MyTurtle(t.Turtle) :
def __init__(self,**args) :
t.Turtle.__init__(self,**args)
def mygoto(self,x,y) :
t1.goto(x,y)
print x,y
def randonics(self,x,y) :
self.left(randint(90,270))
def minegoto(x,y) :
print x,y
t1.goto(x,y)
wt=t.Screen()
t1=MyTurtle()
wt.register_shape("big",((0,0),(30,0),(30,30),(0,30)))
t1.shape("big")
wt.onclick(t1.mygoto,btn=1)
wt.onclick(minegoto,btn=2)
t1.onclick(t1.randonics,btn=3)
t1.goto(100,100)
t.mainloop()
So after extensive search there isn't necessarily a way pause execution of the code in python while using turtle to wait for some click event. Maybe in Tk I could do that but not in turtle.
However, there is a way to get around that. As an example. A method sets up the fake button on the screen, sets the click event, and terminates. The click event when clicked calls the next method needed for execution. So until the button is clicked the actual code isn't doing anything but remains in memory for use.
So more specifically.
1. Create a 'button'.
2. Have your program behave normally until it needs to wait for a click event.
3. Set up the on screen click (or on turtle) in such a way when the 'button' is clicked the next part of the code is run.
Special note. The code in question can't depend on waiting for a click event for later on in code. Instead, the click causes the next part of the execution of your code.
You can make the function registered with onclick() test the x,y position. If it is inside some region you do whatever you must.
I don´t see the difference between what you want to do and what this code does, the modification of turtle position is just an example, you can do anything when a click is captured by onclick(), even start a thread if you really need it (using Creating Threads in python)
import turtle as t
from random import randint
from threading import Thread
from time import sleep
def threaded_function(arg,t1):
for i in range(arg):
print "running",i
sleep(1)
t1.forward(i*10)
def minegoto(x,y) :
print x,y
t1.goto(x,y)
thread = Thread(target = threaded_function, args = (10,t1 ))
thread.start()
thread.join()
print "thread finished...exiting"
wt=t.Screen()
t1=t.Turtle()
wt.register_shape("big",((0,0),(30,0),(30,30),(0,30)))
t1.shape("big")
wt.onclick(minegoto,btn=1)
t1.goto(100,100)
t.mainloop()

Categories

Resources