Python Forum

Full Version: Waiting screen until user input - PiBooth
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
hey guys,

in advance: I'm new in PyGame.

I'm working on a photo booth / photo box with the software "PiBooth" - https://github.com/pibooth/pibooth.

It is possible to create your own plugins – hooks in different states. I created a plugin that displays a screen when the Photo Booth printer needs to be refilled:

When the print counter reaches the refill level (after 38 prints), a message should appear with a “Done” button or something similar.

My problem is: I don't know how to display the screen UNTIL user input.

Here the code:

@pibooth.hookimpl
def state_wait_do(win, app, events):
    #and app.print_ok != 0  and app.find_print_event(events).printer == 1
    if app.find_print_event(events) != None:
        LOGGER.info("sate_print_do")

        printed = app.count.printed

        if((printed % 38) == 0):
            text = "Bitte Transferrolle wechseln und Papier auffuellen, 38 gedruckte Bilder.\n\nStatus Drucker:\n"
            sendstatusmail("Transferrolle wechseln und Papier auffuellen", text)
            
            win_rect = win.get_rect()
            text = "Bitte warten..."
            font = fonts.get_pygame_font(text, fonts.CURRENT,
                                    win_rect.width//1.5, win_rect.height//1.5)
        
            text_surface = font.render(text, True, win.text_color)
        
            if isinstance(win.bg_color, (tuple, list)):
                win.surface.fill(win.bg_color)
            else:
                bg_surface = pictures.get_pygame_image(win.bg_color, win_rect.size, crop=True, color=None)
                win.surface.blit(bg_surface, (0, 0))
        
            win.surface.blit(text_surface, text_surface.get_rect(center=win_rect.center).topleft)
        
            pygame.display.update()
            pygame.event.pump()
        
            n = 0
            gef = False
            #time.sleep(5)
            while True:
                time.sleep(5)
                if gef:
                    break
                events = pygame.event.get()
                print(n)
                n = n + 1
                m = 0
                for event in events:
                    print(str(n) + str(m))
                    print(event)
                    if event.type == pygame.KEYDOWN:
                        print("Jetzat")
                        gef = True
What is wrong with your code? The while loop should prevent anything changing the screen until the KEYDOWN event.

I think it makes more sense to connect to the PRINT plugin instead of the WAIT plugin.
It's not necessary, in my opinion, to compute every ray point. As each point is calculated, I would review it and halt when a collision is found.
def illuminate_block(self, blocks, ray_point):
    """ Find first block that collides with ray_point,  Returns block or None """
    for block in blocks:
        if block[1].rect.collidepoint(ray_point):
            block[1].illuminated = True
            return block
    return None
   
def cast_rays(self):
    cx = self.rect.centerx
    cy = self.rect.centery
    blocks = []
    for b in self.game.level.block_dict.values():
        b.illuminated = False
        # Cull the block list here so it doesn't have to happen for each ray point.
        if abs(b[0][0] - cx) < 200 and abs(b[0][1] - cy) < 200:
            blocks.append[b]
    for ray in range(0, 360, 20):
        # Do expensive sin and cos once per ray
        sin_ray = math.sin(ray)
        cos_ray = math.cos(ray)
        for depth in range(20, 100, 5):
            ray_point = (cx - sin_ray * depth, cy + cos_ray * depth)
            if self.illuminate_block(blocks, ray_point) is not None:
                break
There are pygame routines that can do the task for you if they are sprites.
To display a screen in PyGame until user input is received, you can use a loop that checks for events. Here's a basic example of how you might implement that:

python
Copy
import pygame
import sys

# Initialize Pygame
pygame.init()

# Set up the display
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Photo Booth Refill Alert")

# Define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# Function to display the refill message
def display_refill_message():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:  # Check for key press
                return  # Exit the loop and go back to the main program
        
        # Fill the screen with white
        screen.fill(WHITE)

        # Render the message
        font = pygame.font.Font(None, 74)
        text = font.render("Printer Needs Refill", True, BLACK)
        screen.blit(text, (100, 250))

        # Render the "Done" button
        button_font = pygame.font.Font(None, 36)
        button_text = button_font.render("Press any key to continue...", True, BLACK)
        screen.blit(button_text, (200, 350))

        # Update the display
        pygame.display.flip()

# Simulate the print counter reaching 38
print_counter = 38
if print_counter >= 38:
    display_refill_message()
To display a screen in your PyGame application until user input is received, you can modify your loop to continuously render the screen and check for events. Here’s how you can adjust your code:
  • Create a loop that keeps displaying the message until a key is pressed.
  • Use pygame.event.get() to capture events within the loop.

Here's an updated version of your code:
@pibooth.hookimpl
def state_wait_do(win, app, events):
    if app.find_print_event(events) is not None:
        LOGGER.info("state_print_do")

        printed = app.count.printed

        if (printed % 38) == 0:
            text = "Bitte Transferrolle wechseln und Papier auffuellen, 38 gedruckte Bilder.\n\nStatus Drucker:\n"
            sendstatusmail("Transferrolle wechseln und Papier auffuellen", text)

            win_rect = win.get_rect()
            message = "Bitte warten..."
            font = fonts.get_pygame_font(message, fonts.CURRENT,
                                          win_rect.width // 1.5, win_rect.height // 1.5)

            text_surface = font.render(message, True, win.text_color)

            if isinstance(win.bg_color, (tuple, list)):
                win.surface.fill(win.bg_color)
            else:
                bg_surface = pictures.get_pygame_image(win.bg_color, win_rect.size, crop=True, color=None)
                win.surface.blit(bg_surface, (0, 0))

            win.surface.blit(text_surface, text_surface.get_rect(center=win_rect.center).topleft)

            pygame.display.update()

            # Main loop for waiting for user input
            waiting_for_input = True
            while waiting_for_input:
                events = pygame.event.get()  # Capture events
                for event in events:
                    if event.type == pygame.KEYDOWN:  # Check for key press
                        print("Key pressed, exiting wait...")
                        waiting_for_input = False  # Exit the loop

                time.sleep(0.1)  # Add a small delay to reduce CPU usage
Key Changes:
Event Loop: The loop now continuously checks for events until a key is pressed.
Small Delay: A time.sleep(0.1) is added to prevent the loop from consuming too much CPU.
Exit Condition: The loop continues until a key press is detected.
This way, your message will stay on the screen until the user interacts with it, ensuring a smooth user experience.