Ivan Ivan - 1 year ago 92
Python Question

Blit user text input to screen

I want to blit text that is input by the user to the screen. Each time the user presses Return, the typed text should be blitted to the screen. For text input I use this [text_input module] (https://github.com/Nearoo/pygame-text-input).

Here is the code I came up with so far:

import pygame_textinput
import pygame
pygame.init()

# Set some parameters
duration = 5.0
time = pygame.time.get_ticks()/1000

screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

yoffset = 5
# Function that positions user input rects on screen
def renderInput(text, xoffset, yoffset):
font = pygame.font.SysFont("arial", 20)
renderText = font.render(text, False, (0, 0, 0))
rectText = renderText.get_rect()
rectText = rectText.move((0 + xoffset), (screen.get_height()/2 + yoffset))
return renderText, rectText

# Fills the screen once at the beginning
screen.fill((225, 225, 225))

while (pygame.time.get_ticks()/1000) < time + duration:
# creat new text input object on every trial
textinput = pygame_textinput.TextInput()

while True:
# Fills the surface after each keypress
screen.fill((225, 225, 225))

# Check events
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()

# Feed with events every frame
# This evaluates to True once Return is pressed
if textinput.update(events):
userInput = textinput.get_text()
yoffset += 20
break

# Blit surface onto the screen
screen.blit(textinput.get_surface(), (10, 10))
# Update screen
pygame.display.update()
clock.tick(30)

# Blits user input to screen each time "Return" is pressed
# First get input text and the rectangle of the text
text, textrect = renderInput(userInput, 5, yoffset)
# Then blit it to the screen
screen.blit(text, textrect)
pygame.display.update()


My problem is, that the blitting only works if I do not fill the screen after each keypress within the while-loop that handles the input. If I do that, then the text input, however, is not cleared after each time the user presses Return.

So is there a way to have both, redraw after each keypress and have the text displayed below after each time Return is pressed by the user.

Thanks.

Answer Source

If I understand you correctly, the text in the input field should be cleared and it should be blit in the main area of the screen. I'd assign the text to the user_input variable if the user presses enter and then create a new pygame_textinput.TextInput() instance to clear the input field.

I've tried to simplify your code, because the two while loops are a bit confusing and I'm not sure what their purpose is. There should usually be only one while loop in a game.

import pygame
import pygame_textinput


pygame.init()

screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 20)

textinput = pygame_textinput.TextInput()
user_input = ''

done = False

while not done:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            done = True

    if textinput.update(events):
       user_input = textinput.get_text()
       textinput = pygame_textinput.TextInput()

    # Draw everything.
    screen.fill((225, 225, 225))

    screen.blit(textinput.get_surface(), (10, 10))

    user_input_surface = font.render(user_input, True, (30, 80, 100))
    screen.blit(user_input_surface, (10, 50))

    pygame.display.update()
    clock.tick(30)

pygame.quit()

Edit: In this version I append the rendered text surfaces to a list and blit them with an offset.

import pygame
import pygame_textinput


pygame.init()

screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 20)

textinput = pygame_textinput.TextInput()
user_inputs = []

done = False

while not done:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            done = True

    if textinput.update(events):
       user_inputs.append(
           font.render(textinput.get_text(), True, (30, 80, 100)))
       textinput = pygame_textinput.TextInput()

    screen.fill((225, 225, 225))

    screen.blit(textinput.get_surface(), (10, 10))

    for y, text_surf in enumerate(user_inputs):
        screen.blit(text_surf, (10, 50+30*y))

    pygame.display.update()
    clock.tick(30)

pygame.quit()

Edit2: To get a table, you can use modulo for the row offset and floor division for the column offset. The problem with this example is that the text surfaces can overlap if they are too wide.

for n, text_surf in enumerate(user_inputs):
    # 5 rows. Offset = 30 pixels.
    y_pos = 50 + (n%5) * 30
    # After 5 rows add a new column. Offset = 100 pixels.
    x_pos = 10 + n // 5 * 100
    screen.blit(text_surf, (x_pos, y_pos))
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download