Display a python countdown timer that does not freeze the application - python-3.x

I have built a game, and I am trying to display a countdown timer display to let the player know how much time he/she has to make a move.
def countdown(sec):
while sec:
minn, secc = divmod(sec, 60)
timeformat = '{:02d}:{:02d}'.format(minn, secc)
self.messages['text'] = timeformat
t.sleep(1)
sec -= 1
countdown(15)
The issue i run into is that this code freeze my application, where the user is unable to play until the countdown finishes. So I am trying to see how I could rewrite this code so that it does not affect the application. I think sleeps puts the game to sleep.
I have used Tkinter to build the interface of my app, and so the timer would need to be displayed on screen.
Thanks in advance.

Related

How to tell if user has released slider

There's an issue on the github to add a released() signal to the slider node, but how would I do the same thing without it?
I want to have a slider, and when the user moves it it says "Value is now X" on a label on the screen. But when I do it based on the 'value_changed(x)' it calls many times while the slider is being dragged. I want it to set my only label when the player releases after sliding, or when presses and releases an area on the slider's range to select a new value without using the grabber.
Okay, this is what I've come up with. It doesn't literally let me know when the slider is released, but it tells me when the player stops editing the slider. It still sends an alert if you pause briefly, but that is okay for my game. It doesn't send continuous alerts like if you just use _on_HSlider_value_changed(), which is what I wanted to avoid.
var old = self.value #start value of slider
var timer_on = false
#will be called continuously while editing timer
func editing_slider(new):
#only start a timer, if there isn't one already or you'll have a million
if not timer_on:
#start timer
timer_on = true
yield(get_tree().create_timer(.2), "timeout" )
timer_on = false
#if still editing, re call function
if old != new:
editing_slider(new)
#done editing
else:
print("slider set to " + str(value))
old = new
func _on_HSlider_value_changed(value):
editing_slider(value)
If you wanted to avoid the alert being called when the user pauses but hasn't released, you'd have to do do some kind of InputEvent check.
You can achieve what you want by overriding the _gui_input function. Attach a script to your slider, and then add this code:
func _gui_input(event):
if (event is InputEventMouseButton) && !event.pressed && (event.button_index == BUTTON_LEFT):
print("Released")
This will work whether the user releases the grabber or "releases an area on the slider's range to select a new value without using the grabber", and achieves what you want. However, if the code is meant to run on a device with a keyboard (e.g. a PC), then the user can also change the value via the cursor keys on the keyboard, and you may want to add support for that too.

Repeat function call while button is pressed PyQt5

I started with some code like this which connects a function to a GUI button.
def on_click():
call_other_funct()
time.sleep(1)
button = QPushButton('Do the thing', self)
button.pressed.connect(on_click)
The problem is I need to repeatedly call on_click() every second for the duration of the mouse being held down on the button. I've searched quite a bit but haven't found a solution using PyQt.
I've been trying to fix this using a timer interval
def on_release():
self.timer.stop()
def on_click():
self.timer.start(1000)
self.timer.timeout.connect(on_click())
print('click')
button.pressed.connect(on_click)
button.released.connect(on_release)
This sort of works, but for some reason there seem to be and exponential number of on_click() calls happening. (on the first call, "click" prints once, then twice, then 4 times, then 8 etc). Is there a way to make this work correctly so each call only calls itself again once?
Or is there an all together better way to be doing this?
I suspect that the "exponential growth" comes from the fact that in the event handler on_click, you create a connection between the timer and the event handler itself. So I would expect something like this to happen:
on_click is executed once and the timer is connected once to on_click
after a second, the timer runs out and triggers on_click. During execution of on_click, the timer is connected to on_click again.
after a second, the timer runs out and triggers on_click twice (due to 2 connections). Which in turn then generate 2 more connections.
etc.
What you should do is connect your timer to another function which actually does the thing you want to execute every second while the mouse button is down.
def on_release():
self.timer.stop()
def on_press():
self.timer.start(1000)
def every_second_while_pressed():
print('click')
button.pressed.connect(on_press)
button.released.connect(on_release)
self.timer.timeout.connect(every_second_while_pressed)

do something after a period of gui user inactivity tkinter

What is the general method for 'doing something' after a period of user inactivity in tkinter? In my case the 'do something' will be to go to the start screen (tk.frame) that is already instantiated.
The simplest solution I can think of looks something like this:
start a timer
set a binding on any key press or any button click to reset the timer
if the timer goes off, do something
Create a function to call when the user is inactive:
def user_is_inactive():
<your code here>
Create a function to reset the timer.
We want to be able to call it from an event or directly, so the event argument needs to be optional:
timer = None
def reset_timer(event=None):
global timer
# cancel the previous event
if timer is not None:
root.after_cancel(timer)
# create new timer
timer = root.after(10000, user_is_inactive)
Set up bindings to reset the timer
Using bind_all means that every widget can potentially handle these events:
root.bind_all('<Any-KeyPress>', reset_timer)
root.bind_all('<Any-ButtonPress>', reset_timer)
Start the timer
A good time to do this is right before calling mainloop.
reset_timer()
root.mainloop()
I will admit that I have no experience in this, but maybe a sort of watchdog timer could work? A timer would count up to your desired time, but anytime an element is activated it would reset the counter. This concept is used in micro-controllers a lot but I'm not sure how you would apply it to python.

Freeze when using tkinter + pyhook. Two event loops and multithreading

I am writing a tool in python 2.7 registering the amount of times the user pressed a keyboard or mouse button. The amount of clicks will be displayed in a small black box in the top left of the screen. The program registers clicks even when another application is the active one.
It works fine except when I move the mouse over the box. The mouse then freezes for a few seconds after which the program works again. If I then move the mouse over the box a second time, the mouse freezes again, but this time the program crashes.
I have tried commenting out pumpMessages() and then the program works. The problem looks a lot like this question pyhook+tkinter=crash, but no solution was given there.
Other answers has shown that there is a bug with the dll files when using wx and pyhook together in python 2.6. I don't know if that is relevant here.
My own thoughts is that it might have something to do with the two event loops running parallel. I have read that tkinter isn't thread safe, but I can't see how I can make this program run in a single thread since I need to have both pumpmessages() and mainlooop() running.
To sum it up: Why does my program freeze on mouse over?
import pythoncom, pyHook, time, ctypes, sys
from Tkinter import *
from threading import Thread
print 'Welcome to APMtool. To exit the program press delete'
## Creating input hooks
#the function called when a MouseAllButtonsUp event is called
def OnMouseUpEvent(event):
global clicks
clicks+=1
updateCounter()
return True
#the function called when a KeyUp event is called
def OnKeyUpEvent(event):
global clicks
clicks+=1
updateCounter()
if (event.KeyID == 46):
killProgram()
return True
hm = pyHook.HookManager()# create a hook manager
# watch for mouseUp and keyUp events
hm.SubscribeMouseAllButtonsUp(OnMouseUpEvent)
hm.SubscribeKeyUp(OnKeyUpEvent)
clicks = 0
hm.HookMouse()# set the hook
hm.HookKeyboard()
## Creating the window
root = Tk()
label = Label(root,text='something',background='black',foreground='grey')
label.pack(pady=0) #no space around the label
root.wm_attributes("-topmost", 1) #alway the top window
root.overrideredirect(1) #removes the 'Windows 7' box around the label
## starting a new thread to run pumMessages() and mainloop() simultaniusly
def startRootThread():
root.mainloop()
def updateCounter():
label.configure(text=clicks)
def killProgram():
ctypes.windll.user32.PostQuitMessage(0) # stops pumpMessages
root.destroy() #stops the root widget
rootThread.join()
print 'rootThread stopped'
rootThread = Thread(target=startRootThread)
rootThread.start()
pythoncom.PumpMessages() #pump messages is a infinite loop waiting for events
print 'PumpMessages stopped'
I've solved this problem with multiprocessing:
the main process handles the GUI (MainThread) and a thread that consumes messages from the second process
a child process hooks all mouse/keyboard events and pushes them to the main process (via a Queue object)
From the information that Tkinter needs to run in the main thread and not be called outside this thred, I found a solution:
My problem was that both PumpMessages and mainLoop needed to run in the main thread. In order to both receive inputs and show a Tkinter label with the amount of clicks I need to switch between running pumpMessages and briefly running mainLoop to update the display.
To make mainLoop() quit itself I used:
after(100,root.quit()) #root is the name of the Tk()
mainLoop()
so after 100 milliseconds root calls it's quit method and breaks out of its own main loop
To break out of pumpMessages I first found the pointer to the main thread:
mainThreadId = win32api.GetCurrentThreadId()
I then used a new thread that sends the WM_QUIT to the main thread (note PostQuitMessage(0) only works if it is called in the main thread):
win32api.PostThreadMessage(mainThreadId, win32con.WM_QUIT, 0, 0)
It was then possible to create a while loop which changed between pumpMessages and mainLoop, updating the labeltext in between. After the two event loops aren't running simultaneously anymore, I have had no problems:
def startTimerThread():
while True:
win32api.PostThreadMessage(mainThreadId, win32con.WM_QUIT, 0, 0)
time.sleep(1)
mainThreadId = win32api.GetCurrentThreadId()
timerThread = Thread(target=startTimerThread)
timerThread.start()
while programRunning:
label.configure(text=clicks)
root.after(100,root.quit)
root.mainloop()
pythoncom.PumpMessages()
Thank you to Bryan Oakley for information about Tkinter and Boaz Yaniv for providing the information needed to stop pumpMessages() from a subthread
Tkinter isn't designed to be run from any thread other than the main one. It might help to put the GUI in the main thread and put the call to PumpMessages in a separate thread. Though you have to be careful and not call any Tkinter functions from the other thread (except perhaps event_generate).

Don't let the display go to stand-by in JavaME

Im streaming video to my MIDLET. And while it is playing it, after 20 seconds (depends on a system setting) display on the phone goes to stand-by mode.
How can I prevent this so I can watch the video for 5 minutes for example without having to tap something to wakeup the display?
Yeeeey I figured it out!!! But its a little hack and not the actual "Dont-Go-To-Stand-By" functionality... nevertheless it works PERFECT!!!! =D
Ok so the idea is to define the timeout that the display needs to be woken up. I let the user define this in the "Settings" screen and I write that in RMS so I can read it later...
Next, I define the TimerTask that calls getDisplay().flashBacklight(100); method every time that the defined timeout expires. And, this works like a charm!!! =D
Here is the concept code. First on the VideoCanvas (screen for drawing video) I define the TimerTask:
private class WakeTask extends TimerTask
{
public void run()
{
display.flashBacklight(100);
}
}
Next in the VideoCanvas constructor I start the timer and pass it the timeout, for example 10 seconds... and thats it:
***
timer = new Timer();
timer.schedule(new WakeTask(), 0, 10000);
***
So if the display goes to stand by after 15 seconds, and the timer runs every 10 seconds, it will never go to stand by, and will stay waken until you stop the timer. And if it goes to stand by in 5 seconds, timer will wake it up every time it runs just like you do when you tap something on the phone to wake it up. =)))
Yaaaay... =)))
P.S. Tested on NOKIA N96.

Resources