How should I display a constantly updating timer using PyGTK? - python

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.

Related

Add Kivy Widgets Gradually

I would like to ask how could I add dynamically some widgets in my application one by one and not all at once. Those widgets are added in a for loop which contains the add_widget() command, and is triggered by a button.
So I would like to know if there is a way for the output to be shown gradually, and not all at once, in the end of the execution. Initially I tried to add a delay inside the for loop, but I'm afraid it has to do with the way the output is built each time.
EDIT: Well, it seems that I hadn't understood well the use of Clock.schedule_interval and Clock.schedule_once, so what I had tried with them (or with time.sleep) didn't succeed at all. But obviously, this was the solution to my problem.
Use Clock.schedule_interval or Clock.schedule_once to schedule each iteration of the loop at your desired time spacing.

tkinter updating gui after mainloop()

I understand that in tkinter once mainloop() has been run, no code after it will run until the window has been destroyed. I have found that the common solution is to use tk.after to call a function repeatedly at certain intervals. However I am using a for loop, and every time it loops it updates a variable which I want to see change in the GUI.
PB=myProgressBar()
for i in range (0, len(dataset)):
performfunction
PB.update(i)
PB.quit()
The aim is while performing an operation on each item in the dataset, the GUI will show how far the program is.
Within my progress bar class I have tried using a tk.IntVar as my ttk.ProgressBar value and setting the value through the PB.update(i) to update it.
I have also tried using ProgressBar['value']=i in my update method of the progress bar class.
In both cases if i run mainloop() before the loop, the for loop doesn't run (as you'd expect) but I'm not sure how to run mainloop and get update the GUI without a messy tk.after function that would probably have to involve a self.i value (and then do self.i+=1 at the end of the function that replaces the loop).
Is there a clean 'pythonic' way to do this?

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:

Order of execution of Tkinter mousePressed event

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.

Using Python, how to stop the screen from updating its content?

I searched the web and SO but did not find an aswer.
Using Python, I would like to know how (if possible) can I stop the screen from updating its changes to the user.
In other words, I would like to buid a function in Python that, when called, would freeze the whole screen, preventing the user from viewing its changes. And, when called again, would set back the screen to normal. Something like the Application.ScreenUpdating Property of Excel VBA, but applied directly to the whole screen.
Something like:
FreezeScreen(On)
FreenScreen(Off)
Is it possible?
Thanks for the help!!
If by "the screen" you're talking about the terminal then I highly recommend checking out the curses library. It comes with the standard version of Python. It gives control of many different aspects of the terminal window including the functionality you described.

Categories