PyGame blit image disappears when no mouse event is fired? - python

When using surface.blit during a mouse event, the blit doesn't remain on the screen.
I have two almost identical images. The standard image already exists on the surface and when the mouse hovers over the image, another image needs to be placed on top of the existing image and when the mouse leaves the image it needs to be removed.
My current code works except a mouse event needs to be going on - when the mouse is stationary inside the image, the overlay image is removed. How do I fix this?
def Execute(self):
while self.Running == True:
NewGameButton = pygame.image.load("./Assets/Interface/newgame.png").convert_alpha()
NewGameButtonHover = pygame.image.load("./Assets/Interface/newgame_hover.png").convert_alpha()
self.Display.blit(NewGameButton, (460,260))
pygame.display.flip()
for Event in pygame.event.get():
if NewGameButton.get_rect(topleft=(460,260)).collidepoint(pygame.mouse.get_pos()):
self.Display.blit(NewGameButtonHover, (460,260))
pygame.display.update()
pygame.quit()
Note: The Execute() function is a method within the class App.

Your code currently only does its mouse position checking inside a loop over the events that have been generated during the frame. That means it won't run if there are no events. Try moving that code outside of the for Event in pygame.event.get() loop, and it will run once a frame, regardless of the event status.
Note that you probably do want to deal with events, but you're not doing so now. If you really don't care about any events (not even the QUIT event?), you could replace looping over the events with a call to pygame.events.pump(), which will let Pygame handle any internal events (like dragging or resizing the window), without sending anything to you.

Related

Pygame lagging due to repeated looping, but don't know any alternative solution

In my game I want to make it so that whenever my mouse moves over slots in the player's inventory, an information window will pop up if there is an item in the slot. However, the only way I can think of to do this is to loop over all the inventory slot objects whenever the mouse cursor moves and check whether or not the x and y of the mouse cursor are inside the slot.
This is the code for whenever the mouse cursor moves to check if the cursor is within the inventory slot object (if event.type == pygame.MOUSEMOTION):
for slot in self.inventory:
if slot.rect.collidepoint(pygame.mouse.get_pos()) and slot.item is not None:
# show information window if True
pass
Though this works, it makes the game lag whenever the mouse cursor moves due to the looping.
Is there any way I can do this kind of checking without going through each of the slots in the player's inventory?
Fixed it.
Whenever I moused over the slots, I wanted them to light up as well. It turns out that I was calling pygame.image.loadevery time I moved my mouse to do this. Changed it so that it was already pre-loaded and I was just switching between images instead, and the lag stopped.
Thanks again!

Avoid event grab during motion in Tkinter

Is it possible in Tkinter to avoid the event grab which occures when you press a mouse button over a widget and keep it pressed while you move the mouse?
I want to register the mouse button and then track all widgets the user enters while he moves his mouse with the button pressed. When the user releases the mouse button the application executes the same action for all tracked widgets.
The following code should explain what I want to do.
# Set a tracking flag
widget.bind('<Button>', start_tracking)
# Add the entered widget to the tracked widgets, if the tracking flag is set
widget.bind('<Enter>', add_to_tracked_widgets)
# Execute an action for every tracked widget; unset the flag
widget.bind('<ButtonRelease>', end_tracking)
I took a look at the grab_current and grab_status methods, but they always returned None.
Python version is 3.4.1.
This is probably the most complicated way to do this, but okay.
One thing that makes this more complicated is Tkinter itself, because event.widget still refers to the widget that was clicked on initally. A different event we can use is Motion which is activated when the mouse moves inside a widget.
tk.bind("<Motion>", add_tracked)
I think you can implement the list and state variables yourself, so we come to the add_tracked method (I just renamed it, it's your add_to_tracked_widgets):
def add_tracked(event):
if tracking:
# Get coordinated of the event and use the master window method to determine
# wich widget lays inside these.
widget = tk.winfo_containing(event.x_root, event.y_root)
# Since 'Motion' creates many events repeatedly, you have to convert this
# list into a set to remove duplicates.
widgets.append(widget)

How to get mouse button controls?

I trying to work out how to get the mouse button controls.
I tried looking in pygame docs but it doesn't say; it just returns the state of the mouse. I do understand this but I don't know how to use that info to control the buttons on the mouse.
I have made a game where you could shoot bullets. Whenever you place the MOUSEBUTTONDOWN command in my python script and you try clicking the buttons on the mouse, the right and the left shoots bullets. How can I make it so that only the left mouse button only shoots bullets while the right button does something else?
Also, can you add automatic on the mouse? Instead of clicking the mouse button several times, whenever the left or the right mouse button is pressed the bullet shoots automatically instead of clicking on the button several times.
It starts to get annoying when you're playing a game. Any help is appreciated.
You can use pygame.mouse.get_pressed() (link to docs) to get a
sequence of booleans representing the state of all the mouse buttons. A True value means the mouse is currently being pressed at the time of the call.
As far as "automatic" fire goes, each time round your pygame.event loop you can check if the button is still pressed and fire another bullet.

Trouble programming a "start over" screen which starts a level over using pygame in python

Basically, my main idea is that we would program most of the entire game in a while loop (except when constructing a screen). When the game ends, I let the user enter another while loop so that the player is getting the chance to click the mouse (which starts the game over) while in the loop. The loop I coded is below. However, the screen keeps freezing (i.e. the mouse press method never works) without any errors. I don't know why it's happening.
while not pygame.mouse.get_pressed()[0]:
clock.tick(20)
background_image = pygame.image.load("GameOver.jpg").convert()
When the mouse is pressed, the while loop guiding the rest of the game goes over once again. Please ask if you're confused about anything about my problem.
You need to be sure you're calling pygame.event.get() to get the events from the cue before checking for pygame.mouse.get_pressed() or it will not work.
It's a bit difficult to suggest where to put into your code without seeing what's around it but basically:
pygame.event.get()
while not pygame.mouse.get_pressed()[0]:
#DO SOMETHING
pygame.event.get()
You may find it is easier to just set a flag when they enter this mode and check on the flag instead of creating another while loop.

Force repaint in wxPython Canvas

I've got a Canvas which manipulates objects in the mouse event handler. After modifying the objects, I want to trigger the OnPaint() event for the same Canvas to show (rerender) the changes. What is the right way to do this? It doesn't let me call OnPaint() directly. Also, is triggering an event from another event "wrong" in some sense, or likely to lead to trouble?
I would just call self.Refresh() or maybe RefreshRect() and pass the area that needs to be repainted.
I tried self.refresh() as suggested by Mike Driscoll. That worked partially. I'm moving my own objects with mouse events and then repainting the image - rendering my objects. So the mouse events were updating coordinates and the repaint was updating the display. The problem is that refresh() seems to be called lazily or has lower priority than the mouse events. Refresh() thus produces a choppy display.
Since I am using a buffered display via the wxDemo for Scrolled Area, I took the following line from the Paint event:
dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)
And called my drawing function with that DC from within the mouse event handler. Upon completion dc is freed and (according to the comments in the demo) copied to the screen. It was not previously clear to me how the Paint event was handling DCs, so I was trying to call the event. Turns out you can use that DC and just render from inside the mouse events. This results in smooth dragging of my custom drawn objects.

Categories