I'm using pygame and updating to the screen every loop of the main loop. What I don't understand is nothing will update until I add a for loop looking for events, then suddenly all the updating does occur. Why is this?
def run(self):
two_pm = get_stand_up_timestamp()
pygame.init()
font = pygame.font.Font(None, 72)
screen = pygame.display.set_mode(self._dimensions)
before_two = True
while before_two:
# Blit the time to the window.
# Update Screen.
current_time = datetime.datetime.now()
text = font.render(f'{current_time.hour} : {current_time.minute} : {current_time.second}', True, (0, 0, 0))
blit_center = (
self._dimensions[0] // 2 - (text.get_width() // 2),
self._dimensions[1] // 2 - (text.get_height() // 2)
)
screen.fill((255, 255, 255))
screen.blit(text, blit_center)
pygame.display.flip()
# Get events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
When you call pygame.event.get() (or pump()), pygame processes all events that your window manager send to the window managed by pygame.
You don't see these events as they are not returned by get(), but pygame handles them internally. These events could be WM_PAINT on Windows or Expose on Linux (IIRC pygame uses Xlib), or other events (I guess you could look them up in pygame's source code).
E.g. if you run pygame on Windows, Pygame has to call Windows' GetMessage function, otherwise:
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding.
So the typical behaviour if you don't let pygame process the events is that it will basically run, but the mouse cursor will change to the busy cursor and you can't move the window before it will eventually freeze.
If you run pygame on other systems, e.g. Linux, you only see a black screen. I don't know the internals of the message loop when pygame runs on Linux, but it's similiar to the Windows message loop: you have to process the events in the queue to have pygame call Xlib's XNextEvent function (IIRC) to give the window manager a chance to draw the window.
See e.g. Message loop in Microsoft Windows and/or Xlib for more information on that topic.
No idea why it doesn't work on your end, however when I run
def run():
width = 500
height = 500
pygame.init()
font = pygame.font.Font(None, 72)
screen = pygame.display.set_mode((width, height))
before_two = True
while before_two:
# Blit the time to the window.
# Update Screen.
current_time = datetime.datetime.now()
text = font.render(f'{current_time.hour} : {current_time.minute} : {current_time.second}', True, (0, 0, 0))
blit_center = (
width // 2 - (text.get_width() // 2),
height // 2 - (text.get_height() // 2)
)
screen.fill((255, 255, 255))
screen.blit(text, blit_center)
pygame.display.flip()
run()
Everything works fine update wise. The clock ticks every second so it may be something with your version of python or pygame. Try updating them both. Alternately it could be a problem with how you get pass pygame the dimensions of the window with the run(self) and self._dimensions. Trying using static dimensions like I did above and see if that works on your end. Sadly without more code to see how you call run() its difficult to fully debug whats wrong.
Related
I've read everything I could find about the mouse in pygame and yet I miss something.
The device has (and will not) have a mouse attached so I need to remove the cursor from the game surface, ideally even before it draws the first screen.
But no matter what I try I always have a big oppalin cursor in the middle of the screen.
My current function is this :
# initialize the pygame module
pygame.init()
# create a surface on screen that has the size of 240 x 180
screen = pygame.display.set_mode((160,80))
# define a variable to control the main loop
running = True
pygame.display.flip()
# main loop
while running:
screen.fill((0, 0, 0))
# hide cursor
pygame.mouse.set_pos((160,80)) # my screen is actually 160 x 80 px so this should hide it by pushing it over the edge
pygame.mouse.set_visible(False) # this should hide the mouse plain and simple
# Here I do other unrelated (but working) stuff, like displaying images and text
# event handling, gets all event from the event queue
for event in pygame.event.get():
# only do something if the event is of type QUIT
if event.type == pygame.QUIT:
# change the value to False, to exit the main loop
running = False
pygame.display.flip()
And the mouse is still on screen, sometimes after a while it disappears.
I tried other method like making the cursor transparent, but that crash the app.
Note that I'm running Pygame on an Alpine Linux with direct output to the framebuffer on a Raspberry Pi. There's no mouse attached to the device but if I connect one I can move the cursor around.
Pygame is Version 2.1.2 (compiled and installed by pip)
Python is 3.10.0
Any help or pointer would be greatly appreciated.
(sorry if it's a dumb question; I'm a total noob with python/pygame)
Just write the set_visible(False) outside the main loop, you don't need to call this every frame:
pygame.init()
screen = pygame.display.set_mode((160,80))
pygame.mouse.set_visible(False) # Hide cursor here
running = True
pygame.display.flip()
# main loop
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# unrelated with your question but I also suggest that you clear your background inside the loop, at the contrary you likely will need this at each frame
screen.fill((0, 0, 0))
# ... your code, blitting images etc
pygame.display.flip()
I'm currently making a graph plotter and I'm in the early stages so Im just using the shell to get inputs from the user at the moment. However, due to other parts of my program, I need the pygame window to be open before they begin their inputs (I cannot change the order of this as their inputs are gotten by a function and I don't really want to open pygame in this function). This blocks the shell so I used pygame.display.iconify() which minimized the pygame window doing what I needed.
My problem is that when you have completed the inputs the pygame window is still minimized and I want it to be back as an active window. Is there such a thing that does the opposite of iconify() or should I change my code completely?
Thanks.
There's no way to do this with pygame only, but if you're on Windows, you can use the pywin32 package.
Here's an example that will minify and restore the window every second:
import pygame
import win32gui
import win32con
def main():
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((200, 200))
hwnd = win32gui.GetForegroundWindow()
EVENT = pygame.USEREVENT + 1
pygame.time.set_timer(EVENT, 1000)
while True:
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
return
if event.type == EVENT:
if win32gui.IsIconic(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_SHOWNOACTIVATE)
win32gui.BringWindowToTop(hwnd)
else:
pygame.display.iconify()
screen.fill((30, 30, 30))
clock.tick(30)
pygame.display.flip()
main()
Don't use pygame.display.iconify() as there is no pygame.display.uniconify() counterpart.
There is this ugly hack, where you can use pygame.display.set_mode() to hide the window, and then regain focus and size, when needed:
# Minimize window
pygame.display.set_mode((1,1))
# Restore window
pygame.display.set_mode((1024, 768))
You should write your plot on a surface, independent of the display surface, and then blit and flip it, when you need to display it.
This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 2 years ago.
I started learning pygame, wrote a simple program to display some text on the screen.
import pygame, time
pygame.init()
window = pygame.display.set_mode((600,300))
myfont = pygame.font.SysFont("Arial", 60)
label = myfont.render("Hello Pygame!", 1, (255, 255, 0))
window.blit(label, (100, 100))
pygame.display.update()
time.sleep(15)
pygame.quit()
But it keeps crashing.
I am using python2.7
The issue is that you are running the code only once and not repeating the lines of code that need to be repeated for every frame.
Then you are calling pygame.quit() without exiting the Python thread with quit() which results in the windows just "crashing" or not responding.
To fix this problem:
Include some code inside a while loop that will run on every frame and thus keep the program running and responding.
Make sure that initialization code is only ran once.
Add in some event handling to let the user exit the program when the "X" button is clicked.
Some useful additions:
Included a Clock which allows for an FPS-cap.
Filled the screen with black every frame
Exited the game properly with pygame.quit() to exit the pygame window and sys.exit() to exit the Python thread.
A Clock in pygame game allows you to specify an FPS. At the end of every main game loop iteration (frame) you call clock.tick(FPS) to wait the amount of time that will ensure the game is running at the specified framerate.
Here is the revised code example:
import pygame
import sys
# this code only needs to be ran once
pygame.init()
window = pygame.display.set_mode((600,300))
myfont = pygame.font.SysFont("Arial", 60)
label = myfont.render("Hello Pygame!", 1, (255, 255, 0))
clock = pygame.time.Clock()
FPS = 30
while True:
#allows user to exit the screen
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# this code should be ran every frame
window.fill((0, 0, 0))
window.blit(label, (100, 100))
pygame.display.update()
clock.tick(FPS)
I hope that this answer has helped you and if you have any further questions please feel free to post a comment below!
I am trying to create a simple program in which a user can move a shape on the screen using his finger (on a touchscreen).
this is my code so far:
import pygame
def main():
pygame.init()
DISPLAY = pygame.display.set_mode((1000,500),0,32)
WHITE = (255,255,255)
blue = (0,0,255)
DISPLAY.fill(WHITE)
pygame.mouse.set_visible(False)
pygame.draw.rect(DISPLAY, blue,(480,200,50,250))
pygame.display.update()
pygame.mouse.set_pos(480, 200)
while True:
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
pygame.draw.rect(DISPLAY, blue, (pos[0]-25,pos[1], 50, 250))
pygame.display. update()
DISPLAY.fill(WHITE)
main()
The problem is that when I touch the screen, nothing will happen until I move my finger. If I print the events I can see that there is no event listed until I start moving my finger, so that is probably the reason.
I want to be able to register the finger press (as an event I guess) on the screen even before it starts to move, is there anyway to do this using PyGame?
Thanks.
In case anyone is stumbling across this later, in pygame 2 there is much better touch support. You can install with
pip install pygame==2.0.0.dev6
(check the pygame github for the most recent version) And there are three new event types. pygame.FINGERDOWN, pygame.FINGERUP, and pygame.FINGERMOTION. The pygame.FINGERUP event registers the touch input right when the screen is touched instead of when the screen is released like pygame.MOUSEBUTTONDOWN
I have made a game that utilises a computer touch screen and manages the touch quite well by handling two types of events. One is pygame.MOUSEMOTION and the other one is pygame.MOUSEBUTTONDOWN. Both of them contain the attribute event.pos. Problem is, at least when it comes to my touch screen (Lenovo), that the initial touch is not registered by the event handler of pygame.
You can confirm this by printing all the events to the terminal while touching your screen. I get nothing until I release or move my finger but on release I get the event pygame.MOUSEBUTTONDOWN rapidly followed by pygame.MOUSEBUTTONUP.
I know that this doesn't really solve your problem, but it might perhaps help you in some way. Otherwise, check out Kivy. There might be a solution there.
import pygame
def main():
pygame.init()
DISPLAY = pygame.display.set_mode((1000,500),0,32)
WHITE = (255,255,255)
blue = (0,0,255)
DISPLAY.fill(WHITE)
pygame.mouse.set_visible(False)
pygame.draw.rect(DISPLAY, blue,(480,200,50,250))
pygame.display.update()
pygame.mouse.set_pos(480, 200)
while True:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN or event.type == MOUSEMOTION:
pos = event.pos
pygame.draw.rect(DISPLAY, blue, (pos[0]-25,pos[1], 50, 250))
pygame.display. update()
DISPLAY.fill(WHITE)
main()
I took this tutorial from pygame.org which should show how to resize the window properly (image has to be supplied to it, you can use for instance my gravatar). The image should resize to the window, but this doesn't happen with me. Only one VideoResize event is created as soon as I resize the window even so slightly:
<Event(16-VideoResize {'h': 500, 'w': 501, 'size': (501, 500)})>
No other VideoResize events are created (other things like mouse movement or keypresses work). So is the tutorial wrong? Is my computer wrong? What is the proper way of doing it?
I'm running: Python 2.7.5, Pygame 1.9.1, Fedora 20, MATE 1.8.1, Toshiba Satellite.
Here's the code (slightly modified to print the event, but neither the original nor this one work):
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((500,500), RESIZABLE)
pic = pygame.image.load("example.png")
screen.blit(pygame.transform.scale(pic, (500,500)), (0,0))
pygame.display.flip()
done = False
while not done:
pygame.event.pump()
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == VIDEORESIZE:
print event # show all VIDEORESIZE events
screen = pygame.display.set_mode(event.dict['size'], RESIZABLE) # A
screen.blit(pygame.transform.scale(pic, event.dict['size']), (0,0))
pygame.display.flip()
pygame.display.quit()
If I comment the line # A, then I get plenty of events, but this is the line which resizes the window.
Well I ran the tutorial example with only one change which is I used a pic of a cat called cat.png and it worked fine. The resize is working you just grab a corner and it allows me to adjust it freely with dragging. The picture fills the window whatever size I make it. Have you done other scripts with pygame successfully?