I am programming in Python and I have a few questions that I can't find the answer to anywhere (please read all questions as they build up to my last question):
1.What Does the .mainloop() really do? I read the all the answers in Stack Overflow, I also checked the documentations explanation.
2.Does the .mainloop() always have to be at the end of a turtle program?
3.I have used .mainloop() before. My question is, if I have the f.f.g code:
import turtle
screen = turtle.Screen()
alex = turtle.Turtle()
tess = turtle.Turtle()
def yes(x, y):
alex.onclick(yes)
print("Hello World")
tess.onclick(yes)
turtle.mainloop()
Why does alex get an action event when the function yes() is run? I know it does because the function is called, but what is actually happening? I mean the statement turtle.mainloop() is run before tess is clicked, and tess's action event is waited for in the event loop, so how does alex's event get in the event loop since its statement is run after turtle.mainloop() is run?
1.What Does the .mainloop() really do?
Turtle's mainloop() calls tkinter's mainloop() which calls Tk's Tk_MainLoop() which is surprisingly simple:
void
Tk_MainLoop(void)
{
while (Tk_GetNumMainWindows() > 0) {
Tcl_DoOneEvent(0);
}
}
It handles events, one at a time, in an infinite loop while there are any main windows open. The events processed include keyboard input, button clicks, window reshapes, file I/O, network activity, timers, display refreshes and any other registered callbacks.
An excellent, one page description of mainloop can be found in the introduction to Chapter 15. Anatomy of the MainLoop in the O'Reily book Mastering Perl/Tk by Steve Lidie and Nancy Walsh. Although it's a Perl/Tk book, the information regarding mainloop is valid for Python as well. You can find this material on-line but I won't include a link here as I don't know which, if any, of the online copies are legitimately posted. But you've enough information to search for it.
2.Does the .mainloop() always have to be at the end of a turtle program?
No. It should be part of a well designed program but isn't required. Most standalone programs will include it (or something that calls it like .done() or .exitonclick()) as the graphics window will close on completion without it. But some situations, eg. IDLE perhaps, don't need it to keep the graphics visible. A common error I find in beginner's turtle programs is creating an infinite loop of turtle activity ahead of calling mainloop() and then wondering why various events don't fire.
If you plan to have Tk process keyboard, mouse and timer events for you, then calling .mainloop() is how you get that started. In most Python/Tk programs, it's the last statement but there can be other code after it that gets executed when all the Tk windows have all closed down.
We can think of turtle programming as writing plug-in code for Tk's main loop. After we set things up, subsequent activity will be done by call back functions we've registered via on*() functions.
3.I have used mainloop() before. My question is, if I have the f.f.g code: ... Why does alex get an action event when the function
yes() is run
When your program runs, turtles Alex and Tess are piled atop each other in the center of the window. When you click on this turtle stack, the event goes to Tess, who's both on top and has an event handler. In her event handler, Tess installs an event handler on Alex. The act of installing an event handler on Alex causes Alex to move in front of Tess, rising to the top of the stack. From now on, when you click on the turtle stack, Alex handles the events and they no longer reach Tess. We can see this clearly if we give them different colors and different event handlers:
import turtle
alex = turtle.Turtle(shape="turtle")
alex.color("blue")
tess = turtle.Turtle(shape="turtle")
tess.color("pink")
def tess_handler(x, y):
alex.onclick(alex_handler)
print("Tess clicked")
def alex_handler(x, y):
print("Alex clicked")
tess.onclick(tess_handler)
turtle.mainloop()
Clicking on the turtle stack produces:
> python3 test.py
Tess clicked
Alex clicked
Alex clicked
Alex clicked
Alex clicked
Alex clicked
Alex clicked
You could move Alex and Tess to different locations in the window and then click on them to confirm that Alex doesn't start receiving events until the first time Tess is clicked.
So mainloop() is an infinite loop that basically blocks the execution of your code at a certain point. You call it once (and only once).
so lets say:
while true:
circle.draw()
sumden.mainloop()
print "circle is being drawn"
time.sleep(0.1)
You will never see the output and print statement because there is no loop.
Related
I was experimenting with pygame and noticed it raised a VideoExpose event when I press alt+tab and the window is fullscreen. when I switch press alt+tab again, everything on the screen is moved to the bottom left.
I know that this is supposed to mean that 'portions of the window must be redrawn', but how am I supposed to redraw them and what why does pygame even have this event in the first place?
If you are writing a program to use the windowing Event Model, the windowing environment sends the program events to notify it of environmental changes - window resize, mouse move, need to re-paint, etc.
Not handling these events will cause your application to be considered "non responsive" by the environment. Here on SO, there's about one question a week with PyGame and exactly this issue.
When working with PyGame re-drawing event handling may seem superfluous as the majority of PyGame games redraw the entire screen every frame, e.g.: 60 FPS. But if unnecessary, this method is a complete waste of resources (CPU-time, electricity, etc.) It is quite simple though, so good for beginners.
Say you were writing a card game like Solitaire... the screen updates only when interacting with the user. In terms of CPU, it's doing nothing 99.9% of the time while the user contemplates their next move. In this case, the program could be written to only re-draw the screen when necessary. When is it necessary? When the player gives input, or the program receives a pygame.VIDEOEXPOSE event from the widowing environment.
If your program is redrawing the window constantly, you can simply ignore the message. If not, when receiving the message call whatever block of code is normally used to render the window. The expose message may come with the region of the screen that needs to be re-drawn, in this case a really good application would only update that section of the display.
I have a video player application, with a graph display below it. My video player is fetching frames periodically, but when I move the mouse it freezes, and by printing what's happening I can see that the main loop didn't call anything
I've tried printing some text for every widget on_mouse_pos event but none of them is triggered, so I really don't know where should I look. Using the recorder module, I can see that there is no mouse event, so I'm not even sure the mouse event is recorder
I have several widgets now so I'm not sure posting them here would be useful, but I'd love to hear feeedback or any idea about this problem
Thanks a lot
So I was able to fix this, my frame pulling function was in a separate thread, moving it to a periodically triggered Clock event fixed this.
I'm still not sure why this bug happened, my 2 cents is that opencv block the GIL while reading a frame, and this somehow interfered with how kivy manages its events
I have created a game which has a pause feature. Once the player presses the escape key whilst a game is playing, the menu enables, once escaped is pressed again it disables the menu and resumes the game. But when i open my program and press escape without launching a game first the game crashes causes theirs no game to resume. How could i disable the escape key until at least one game has started.
I am using the Pygame-menu module by ppizarror to create my gui, iv'e tried looking up my question but no one has a clear answer. Below is the main parts of code from two different classes that handles the pause feature.
Class EntertheGauntlet:
# a function used throughout the menus that disables the previous menu for
the new one to be displayed
def resume_feature():
# disables menu
self.main_menu.disable()
# resumes the game paused in the background by calling upon it
from the main gameloop
self.game.main()
Class GUI:
# a function used throughout the game that initiates when the new
game button is pressed
def start_new():
# disable previous menu
self.main_menu.disable()
# Start new game by calling variable from EscapeTheGauntlet.py
self.game = EscapeTheGauntlet(self.window, clock, self.sfx)
# sets this new updated screen to the new main window
self.game.main()
The only solution i can see is disabling the escape key until the start new game feature is called upon at least once. Could you please show me how i would do that.
What you're suggesting sounds unnecessarily complex. You cannot mess with the system drivers of the keyboard, or with the key-to-character mapping, because the user might be working in a different window with a different program where the escape key is needed.
Can't you re-write your code that handles the pause function to check whether there is a paused game? Initialize some variable with False when the application starts, and set it to True when the function you expect to be called is called.
I made a Python game using Pygame. I try to make it so when it starts, it loads the shell, and entering a raw input would display the pygame window and start the game so that I can make the game playable without having to close the shell. It works, however, the window starts minimized. The game is a simple "dodge the object" and has no pause what so ever. The game still runs in the background, possibly having the player hit multiple projectiles before the user realizes it. Is there a way to focus on the window?
For anyone in the future who stumbles across this question:
As of 2022, pygame v2.1.2 has an experimental module ._sdl2 where: Window.focus() is used to make a window to be moved at the top and set focus. Windows.focus() supports optional input_only bool parameter for whenever the window should be moved at the top (False), or just collect input (True).
As I understood you, you don't want the game to start, before the window is in fullscreen-mode, right?
When I try you attempt (starting through rawinput), my display is fullscreen from the start. Have you set everything correctly?
I suggest that you stop the game until there is an actual key-input (whatever controls you have set). Like this the player has the time to arrange everything to his liking before starting the game. Because, even if you figure out how to analyse the focus-issue: When the game starts, the window HAS focus, therefore this approach wouldn't work anyway.
Using time.sleep in my wxPython code just after re-positioning a bitmapbutton caused my button to go totally blank. Just a white space was left in the region where the button should have been. Can any one please explain the reason and suggest any solution? Here's my code:
import wx
import time
class gui(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'New Window',pos=(0,0),size=wx.DisplaySize())
panel=wx.Panel(self)
self.SetBackGroundColour('green')
self.pic=wx.BitmapButton(self,-1,wx.Image("Candle.jpg",wx.BITMAP_TYPE_ANY).ConvertToBitmap(),pos=(700,300))
self.Bind(wx.EVT_BUTTON,self.position,self.pic)
def positon(self,event):
self.pic.Hide()
self.pic=wx.BitmapButton(self,-1,wx.Image("Candle.jpg",wx.BITMAP_TYPE_ANY).ConvertToBitmap(),pos=(700,300))
time.sleep(2)
self.pic.Hide()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=gui(None,-1)
frame.Show()
app.MainLoop()
Well there's no wonder your button goes blank, you've pretty much programmed it to do so.
self.pic.Hide() => hides the button
self.pic=wx.BitmapButton(self,-1,wx.Image("Candle.jpg",wx.BITMAP_TYPE_ANY).ConvertToBitmap(),pos=(700,300)) => displays the button once again
time.sleep(2) => takes a brake for 2 seconds
self.pic.Hide() => hides the button again
The conclusion is, your button won't show up. So I don't see what's the problem, as it does exactly what you programmed it to.
time.sleep() blocks wx's mainloop and makes the GUI unresponsive for however long you've told it to sleep. There are several alternatives. You can use a wx.Timer or use threads (or similar). I think using a Timer makes more sense in your use case though.
well it depends, was time sleep used in the button's event ?, cause I believe if it was it's because of that. The button waits for the event it triggered to end so it would go back to its initial state.
sleep is blocking, so execution is stuck in your position method for two seconds and is unable to return to the MainLoop to process other events, like painting your changes to the screen. After the two seconds are up the image is hidden, but was never drawn.
To get the effect you want you'll have to start a timer, and bind the timer to a handler which can show the StaticBitmap again.
By the way you can also call Show again rather than creating a new control, and it's parent should also be the panel, not the frame.