Order of execution of Tkinter mousePressed event - python

I have recently been trying to finish a project I started a few years ago, and on revisiting the problem, finally decided to seek help since I cannot figure out what is going on exactly.
The scenario is a game called Reversi, and I have created an algorithm (albeit not a very good one) for the computer. Now, when player A plays against the computer, I have written the order of execution to be as follows, upon mouse click event:
makeMove(canvas, row_clicked, column_clicked)
if canvas.data["computer"] and not canvas.data["noMove"]:
#time.sleep(2)
computerAI2(canvas)
makeMove makes a move and updates the main board (update: in tkinter, I delete the entire canvas [my board] then recreate the whole board). This works perfectly fine player to player, but when I include the computer, it seems to complete the updating all in one go, even though makeMove is (supposedly) completed before the computerAI2 starts its calls. computerAI2 also calls makeMove, so it should be updating after my mouseclick, and then once more after the computerAI2 finishes its algorithm.
But it doesn't. I have looked towards threading (note I haven't "actually" tried this, since I have never threaded before and seems difficult to implement and integrate in), towards adding time.sleep(), adding more pauses and phases in between to try and update the board before it gets to the computerAI2.
For absolute conviction that ordering is the problem, I tested by including
makeMove(canvas, row_clicked, column_clicked)
canvas.delete(ALL)
if canvas.data["computer"] and not canvas.data["noMove"]:
computerAI2(canvas)
And no response (same if placed above computerAI2 after the if). It just updates all in one go. Comparing to:
makeMove(canvas, row_clicked, column_clicked)
if canvas.data["computer"] and not canvas.data["noMove"]:
computerAI2(canvas)
canvas.delete(ALL)
Then this does delete everything after all is resolved, and I'm left with a blank slate (as expected). So the fact that it doesn't wipe everything inbetween... the fact is, I have some extra debugging inbetween that shows the computerAI2 is running (prints feedback) between my mouseclick and the eventual completion and update of the canvas/board. So it is not like it can't run and delays things in between, only for some odd reason refuses to reupdate the board in between!
def mousePressed(event):
(... set up etc)
makeMove(canvas, row_clicked, column_clicked)
if canvas.data["computer"] and not canvas.data["noMove"]:
computerAI2(canvas)
So my query is, what exactly is happening with the order here? Does it have something to do with the fact that its a mousePressed event?
This almost certainly, provided that the above information is not enough, requires looking at the source code to see how I am building the board through tkinter and the functions I call to. It is quite comprehensive to take it all in however. I am happy to share if someone is up to the task (it is clear if you know which parts to ignore and jump to the important sections). I will tell you the relevant functions that are being in use.
Thank you so much for your insights.
edit: the functions simplified for logic:
def makeMove(canvas, row, col):
flipCounters(canvas, row, col)
redrawAll(canvas)
def redrawAll(canvas):
canvas.delete(ALL)
drawBoard(canvas)
def ComputerAI2(canvas)
(the source of issue may be originating here, ie it may be nothing to do with order of execution, rather some error in the behaviour. However I have checked extensively here)
algorithm --> makeMove(canvas, row, col)
edit2:
100% determined problem is not to do with computerAI2. It can only originate from makeMove, or really is some ordering problem to do with mousePressed Event.
makeMove(canvas, row_clicked, column_clicked)
if canvas.data["computer"] and not canvas.data["noMove"]:
time.sleep(2)
makeMove(canvas, 1,1)
The above STILL delays. Ie, it updates both moves at once, not update one move, wait 2 seconds, then updates the other move.
However, 95% certain that makeMove is not the problem. If someone would create a quick mousePressed event in tkinter and test "print 1,2,3,4,5, time.sleep(5), print ok", if THAT doesn't delay, and works as 1,2,3,4,5ok all at once, then that resolves the root of the problem is with the mousePressed(event) problem. But how to FIX that, through threading?
edit3: Still no progress, havent managed to find the problem. If anyone could help I would really appreciate it, its a shame not to get such a nice project working.
edit4: Managed to google the solution out of luck, involves using "update" Haven't implemented yet but was from another thread answered by BryanOakley to do with running a function before the frame, "frame.update()" was the solution.

Related

Window moving behind other open windows when button pressed (Python with Tkinter)

Apologies if this is a completely easy fix and I've just missed it. I am learning Python and I am trying to develop a GUI alongside my backend code using Tkinter. This is completely foreign to me and I have recently come across the problem that when I press my buttons there is a very small chance that it will make my window move behind all other open programs.
I am not entirely sure what is causing this but my guess is it stems somehow from one of two functions I have; one meant to minimise the main root window and the second to reveal it. However, these functions are not called in any place in my program that I would not expect them and the windows being minimised are not the root window (which my two functions act on).
I have both functions added below (hopefully, I am pretty new to SO) but if any additional code is needed I will supply it. I have quite a bit of code and everything else functions perfectly so I didn't want to post all my code is all.
There is no particular combination of button presses or buttons in particular which cause it, it appears to be any of them seemingly at random. It sends whatever window I have up to the taskbar.
def revealMenu():
root.update()
root.deiconify()
def hideMenu():
root.withdraw()

Odd clicking noise while attempting to play a sound in python

While working on a simple little timer I was creating to simultaneously help me learn more about Python and to help me keep on schedule with my schoolwork; I decided to add a little tune to let me know when your time was up. However, after using the following snippet of code to program each individual note:
winsound.Beep(Freq, Dur)
I realized that whenever I actually played the little song, an odd clicking sound happened between each note. Does anyone know what's going on? Should I use a different expression? Am I just losing my mind?
Edit: Since posting this, I realized what the issue is, the program is waiting about a sixteenth of second in between playing each note. So I'd like to ask another question (any answers relating to the others would still be appreciated), namely, how can I make it not wait in between the notes.
import winsound
winsound.Beep(262,500)
winsound.Beep(277,500)
winsound.Beep(294,500)
winsound.Beep(311,500)
winsound.Beep(330,500)
winsound.Beep(349,500)
winsound.Beep(370,500)
winsound.Beep(392,500)
winsound.Beep(415,500)
winsound.Beep(440,500)
winsound.Beep(466,500)
winsound.Beep(493,500)
winsound.Beep(523,500)
All the above code does is play a simple chromatic scale from middle c to c2, but once one runs it, one would immediately see what Im talking about

Why are tkinter windows/boxes closing erratically and stopping the program?

To cut a long story short, I've been doing an interactive GUI (tkinter) word-game program for school. At first, everything went smoothly, but having finished the code, it has started to behave in unexpected ways when I run it. Some dialog boxes (particularly the
if tkinter.messagebox.askyesno():
thingy) just rapidly answer themselves with the 'no' option, rather than waiting for user input. Sometimes, the windows close off completely and cause the whole program to quit. However, although these errors are all the same (i.e. tkinter windows closing/answering themselves/stopping the program before they should), they usually happen in different places every time. I'm not sure if that's to do with the fact that tkinter is nested, opened, re-opened and closed numerous times within other code, which is making it run messily, but I have only destroyed tkinter windows in the right places, as far as I know.
Part of my code involves a while loop - I'm not sure if that could be interfering with the mainloop()s, but I couldn't find another way to allow the user to repeat the game as many times as they want.
I know this question is vague, but I'm mainly looking for tips - if it would be easier to diagnose if I split it up into different sections and tidy it up a bit, found an alternative for the while loop, etc.
Thanks!
TKinter dialogs should be fully completed and the results stored before moving onto the next section of code.
Make sure you provide all the arguments to the dialog (your example doesn't include the parameters).
result = tkinter.messagebox.askyesno('Confirm', 'Do you want to do this')
if result == true:

Having a little bug with my first Arduino/Python project [Reaction.py], time.sleep seems to be causing it

So I'm trying to complete my first projects, nothing special but having few problems.
1. When I run the code, the diode is constantly on, but it should go off. When I close the program I get error for this line
time.sleep(random.uniform(2,5))
Seems like it doesn't like being in the while loop.
2. While the diode is still on, if either of the players presses its button, it should get -2 points in penalty. But since I added the penalty, every time either of the players press it's button, they always get -2 points.
I think I might be related to the time.sleep bug.
For your convenience I put the code on Pastebin because it looks really bad and quite hard to read.
Link to code # Pastebin
It might help to have the whole error for the time.sleep line
But aside from any errors, your LED is always on because you only have one sleep, the IF statements are "instantaneous". The code basically boils down to this:
while True:
GPIO.output(led, 1)
time.sleep(random.uniform(2,5))
GPIO.output(led, 0)
Which is basically the same as this:
while True:
time.sleep(random.uniform(2,5))
GPIO.output(led, 0)
GPIO.output(led, 1)
Hope this helps!
Edit: I realized I didn't answer question 2. I have a suspicion it's related to whether or not board is "listening" while it's sleeping, but I don't have any experience with this. Based on https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/ maybe you need to use GPIO.event_detected for example...

How should I display a constantly updating timer using PyGTK?

I am writing a timer program in Python using PyGTK. It is precise to the hundredths place. Right now, I am using a constantly updated label. This is a problem, because if I resize the window while the timer is running, Pango more often than not throws some crazy error and my program terminates. It's not always the same error, but different ones that I assume are some form of failed draw. Also, the label updates slower and slower as I increase the font size.
So, I am wondering if there is a more correct way to display the timer. Is there a more stable method than constantly updating a label?
Updating a label should work perfectly reliably, so I suspect you're doing something else wrong. Are you using threads? What does your code look like? How small can you condense your program (by removing functionality, not by obfuscating the code), without making the problem go away?
I figured out the problem. It was indeed a problem with the threads. I never would've guessed that myself. The trick is to use gobject.timeout_add() to create a timer instead of a threaded loop. Here is some information about gobject.timeout_add():
http://faq.pygtk.org/index.py?req=show&file=faq01.021.htp
Don't forget to have your function return True, or the timer will stop.

Categories