HALT (python 3) a music file? - python

The user has limited time to solve a problem. On the program, I run a music file at the same time as a GUI (tkinter) timer, and they both finish when the time is up. Some users may finish EARLY. I want to make the music stop when they close the timer window. 'winsound' does not accept 'stop()', and I am having no success with 'winsound.SND_PURGE'. This is more complicated than I thought. I tried this:
# python 3.5
winsound.PlaySound('The Countdown.wav', winsound.SND_FILENAME)
root = Tk() # IMAGINE this is a box with a number ticking down
root.mainloop()
root.protocol("WM_DELETE_WINDOW", winsound.SND_PURGE) # nothing happens :(
Is there a way of using flags? Perhaps an alternative audio-file player? Anything?
Let me know if you do. Thanks!

winsound.SND_PURGE is just an integer constant, that happens to have the value of 64 (and furthermore, is documented as "not supported on modern Windows platforms"). What were you expecting root.protocol() to do with it? You need to pass a function to be called when the window is closed. It looks like:
lambda: winsound.PlaySound(None, 0)
would be a suitable function for stopping sound playback, although I haven't actually tested it.
I think you're also going to need to add winsound.SND_ASYNC to your original PlaySound call's flags, or your window won't even open until the sound is finished.

Related

PyGObject (Glade) Window Never Showing (Multithreaded)

I've been fighting for three hours now to get this process multithreaded, so that I can display a progress box. I finally got it working, insomuch as the process completes as expected, and all the functions call, including the ones to update the progress indicator on the window.
However, the window never actually displays. This is a PyGObject interface designed in Glade. I am not having fun.
def runCompile(obj):
compileWindow = builder.get_object("compilingWindow")
compileWindow.show_all()
pool = ThreadPool(processes=1)
async_result = pool.apply_async(compileStrings, ())
output = async_result.get()
#output = compileStrings() #THIS IS OLD
compileWindow.hide()
return output
As I mentioned, everything works well, except for the fact that the window doesn't appear. Even if I eliminate the compileWindow.hide() command, the window never shows until the process is done. In fact, the whole stupid program freezes until the process is done.
I'm at the end of my rope. Help?
(By the way, the "recommended" processes of using generators doesn't work, as I HAVE to have a return from the "long process".)
I'm not a pyGobject expert and i don't really understand your code. I think that you should post more. Why are you calling the builder in a function? you can call it at the init of the GUI?
Anyways.. It seems that you are having the common multithread problems..
are you using at the startup GObject.threads_init() and Gdk.threads_init() ?
Then, if you want to show a window from a thread you need to use Gdk.threads_enter() and Gdk.threads_leave().
here is an useful doc
I changed the overall flow of my project, so that may affect it. However, it is imperative that Gtk be given a chance to go through its own main loop, by way of...
if Gtk.events_pending():
Gtk.main_iteration()
In this instance, I only want to call it once, to ensure the program doesn't hang.
(The entire program source code can be found on SourceForge. The function in question is on line 372 as of this posting, in function compileModel().

Joining process during quitting - Tkinter + multiporcessing

I'm writing a GUI application that has a button which invokes a long task. In order for it not to freeze the GUI I delegate the task to a different process using python 3.3's multiprocessing module. Then I return the result for display using a Pipe.
I want the application not to leave any zombie process even if quit during the computation. As I'm on a mac this can happen one of two ways: through quitting the application (Command+Q) or but closing it's window.
Here's the code in the function linked to a button in the GUI:
main_pipe,child_pipe=Pipe()
p=Process(target=worker,args=(child_pipe,data))
p.start()
try:
while not main_pipe.poll():
root.update()
value_array=main_pipe.recv()
finally:
p.join()
This doesn't work the application doesn't respond to Command+q, and closing the window leaves two zombie process running (one for the GUI and one for the worker).
How to make it work in the other case as well?
Is this good practice? Is the a nicer, more pythonic way of doing it?
Additionally at the very end of the script I have those two lines (the exit() closes the application if the window is closed while not processing anything):
root.mainloop()
exit()
And finally, what's the difference between update() and mainloop()? Is it only that the latter hogs up the program while update() doesn't?
Ok, I finally solved it. Although I not complete sure regarding this method's pythoness or side effects, if somebody needs it here it is.
I figured that quitting correctly can only happen in a mainloop() not in a update() so I wrote two functions, one for creating the process, and one for checking it's output and they call each other using root.after(). I set the processes daemon flag to true to ensure proper quitting behaviour. Here's the code:
def process_start():
global value_array
global main_pipe
main_pipe,child_pipe = Pipe()
p=Process(target=worker,args=(child_pipe,data))
p.daemon=True
p.start()
root.after(500,check_proc)
def check_proc():
if not main_pipe.poll():
root.after(500,check_proc)
else:
global value_array
value_array=main_pipe.recv()
I'm still not sure if p.join() is needed but the deamon thing seems to get around the zombie-proceses problem
I was facing the similar problem earlier (except I wasn't using multiprocess). After nearly a whole days research, I come up with the following conclusion:
mainloop and root.waitwindow will (sometimes) block the sys.exit signal, which your program should receive after you hit ⌘Q.
You can bind ⌘Q to a new function, although you may still receive the sys.exit signal
Another way (more reliable in my case) is to remap the tcl quitting signal to another function, instead of the default one. You can remap the quit event (dock quit and ⌘Q) using this: root.createcommand('::tk::mac::Quit',function)
When trying to quit the software, use sys.exit instead of exit() or quit()
You can also use root.wm_protocol("WM_DELETE_WINDOW", function) to define the behavior when users clicking on the red button.
You can actually make the border of the window and the three default buttons disappear by flagging root.overridedirect(1) and thus force the user to click on a button on your GUI instead of closing the window.

Tkinter window says (not responding) but code is running

I have a program that runs a long process after you click an action button. As the process is running the root window will say that it is not responding even though I know the program is running in the background. This program is going to be released to a few people that I work with and I want to make sure they don't freak out and close the window when they see this. The solution I have is sitting a root.update in the loop of the process that is running but I am not sure this was the best fix.
Using the python 3.3
Here is a sample of the code so you get an idea of what I am doing, this is called from the main loop:
def combine(boxes_to, boxes_from, frame):
to_value,to_pos = gui.checkBoxes(boxes_to)
from_value,from_pos = gui.checkBoxes(boxes_from)
frame.destroy()
running = Label(root,text="Running please do not close..",font = (16))
running.pack()
root.update()
map_to = open("map_to",'r')
for line in map_to:
root.update()
process(line)
running.destroy()
map_to.close()
finish = Button(root, text="Done",command=gui.stop)
finish.pack()
While you can call root.update() in your loop, this will still produce some (potentially) undesirable side-effects.
The program may act laggy, meaning it takes a long time to respond to user input.
You will only be able to run this one action. Any other action has to wait for this to finish.
As an alternative I would suggest that you implement simple multi-threading. Python multithreading is pretty simple, and will prevent both of these drawbacks. You will be able to execute your long running code, while still providing a clean and responsive UI.
If your application is trivially parallelizable, you could use multiple threads to decrease running time. Ex. Thread 1 handles entries 1-100, while thread 2 handles entries 101-200.
The best you can do here is to use multithreading in Python. Here's how to do this:
Let's say you have a function named combine() due to which the window is freezing, which is being used as a command for a button named 'btn' as shown here:
btn = Button(root, text="Click Me", command=combine)
Now, when btn is pressed you might be getting the 'not responding' problem. To fix this, edit the code as shown below:
import threading
btn = Button(root, text="Click Me", command=threading.Thread(target=combine).start)
Here threading.Thread creates a separate thread in which the combine() method is executed, so the GUI can continue to keep responding while the command is being executed.

Python EasyGUI: Systray icon xor multiple windows

I'm writing a simple program that gives you a message to take a break from sitting at your Computer every x minutes. However, I also need to be able to close the program without having to wait for a window to pop up after x minutes.
My ideas are that I either create a systray icon (I'm programming it for a friend who uses Windows) and add the possibility to exit it that way, or that I just add another window, which has an exit button and stays open all the time (less elegant).
From what I have read, it seems that the systray idea requires something more complex than easygui.
So, is there a way to implement any of those ideas with easygui and if not: what do I need to look at to get it working?
Thanks for your time and effort.

How to pause Python while Tkinter window is open?

I'm writing a program that sometimes encounters an error. When it does, it pops up a Tkinter dialog asking the user whether to continue. It's a more complicated version of this:
keep_going = False
KeepGoingPrompt(keep_going)
if not keep_going:
return
The prompt sets keep_going to True or leaves it False.
Problem is, the code seems to continue while KeepGoingPrompt is open. I tried storing a reference to the prompt and adding a loop like
while prompt:
time.sleep(1)
but python gets stuck in the loop and freezes.
Is there a better way to do it?
Thanks
You can use the tkMessageBox class to pop up a question dialog that is modal and won't return until the user clicks a button. See the Tkinter book for details.
1) Are you running your code inside IDLE? It might be responsible for making the dialogue non-blocking while it really should be blocking.
2) If running outside IDLE does not help, look for tkinter/dialogue options which specify whether behavior is blocking or non-blocking

Categories