How can I create a text input box with Pygame?

十年热恋 提交于 2021-02-17 05:23:32

问题


I want to get some text input from the user in Python and display what they are typing in a text box, and when they press enter, it gets stored in a string.

I've looked everywhere, but I just can't find anything. I'm using Pygame.


回答1:


You can define a rect as the area of the input box. If a pygame.MOUSEBUTTONDOWN event occurs, use the colliderect method of the input_box rect to check if it collides with the event.pos and then activate it by setting a active variable to True.

If the box is active you can type something and Pygame will generate pygame.KEYDOWN events which have a unicode attribute that you can simply add to a string, e.g. text += event.unicode. If the user presses enter, you can do something with the text string (in the example I just print it) and reset it to ''.

import pygame as pg


def main():
    screen = pg.display.set_mode((640, 480))
    font = pg.font.Font(None, 32)
    clock = pg.time.Clock()
    input_box = pg.Rect(100, 100, 140, 32)
    color_inactive = pg.Color('lightskyblue3')
    color_active = pg.Color('dodgerblue2')
    color = color_inactive
    active = False
    text = ''
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            if event.type == pg.MOUSEBUTTONDOWN:
                # If the user clicked on the input_box rect.
                if input_box.collidepoint(event.pos):
                    # Toggle the active variable.
                    active = not active
                else:
                    active = False
                # Change the current color of the input box.
                color = color_active if active else color_inactive
            if event.type == pg.KEYDOWN:
                if active:
                    if event.key == pg.K_RETURN:
                        print(text)
                        text = ''
                    elif event.key == pg.K_BACKSPACE:
                        text = text[:-1]
                    else:
                        text += event.unicode

        screen.fill((30, 30, 30))
        # Render the current text.
        txt_surface = font.render(text, True, color)
        # Resize the box if the text is too long.
        width = max(200, txt_surface.get_width()+10)
        input_box.w = width
        # Blit the text.
        screen.blit(txt_surface, (input_box.x+5, input_box.y+5))
        # Blit the input_box rect.
        pg.draw.rect(screen, color, input_box, 2)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

Here's an object-oriented variant that allows you to easily create multiple input boxes:

import pygame as pg


pg.init()
screen = pg.display.set_mode((640, 480))
COLOR_INACTIVE = pg.Color('lightskyblue3')
COLOR_ACTIVE = pg.Color('dodgerblue2')
FONT = pg.font.Font(None, 32)


class InputBox:

    def __init__(self, x, y, w, h, text=''):
        self.rect = pg.Rect(x, y, w, h)
        self.color = COLOR_INACTIVE
        self.text = text
        self.txt_surface = FONT.render(text, True, self.color)
        self.active = False

    def handle_event(self, event):
        if event.type == pg.MOUSEBUTTONDOWN:
            # If the user clicked on the input_box rect.
            if self.rect.collidepoint(event.pos):
                # Toggle the active variable.
                self.active = not self.active
            else:
                self.active = False
            # Change the current color of the input box.
            self.color = COLOR_ACTIVE if self.active else COLOR_INACTIVE
        if event.type == pg.KEYDOWN:
            if self.active:
                if event.key == pg.K_RETURN:
                    print(self.text)
                    self.text = ''
                elif event.key == pg.K_BACKSPACE:
                    self.text = self.text[:-1]
                else:
                    self.text += event.unicode
                # Re-render the text.
                self.txt_surface = FONT.render(self.text, True, self.color)

    def update(self):
        # Resize the box if the text is too long.
        width = max(200, self.txt_surface.get_width()+10)
        self.rect.w = width

    def draw(self, screen):
        # Blit the text.
        screen.blit(self.txt_surface, (self.rect.x+5, self.rect.y+5))
        # Blit the rect.
        pg.draw.rect(screen, self.color, self.rect, 2)



def main():
    clock = pg.time.Clock()
    input_box1 = InputBox(100, 100, 140, 32)
    input_box2 = InputBox(100, 300, 140, 32)
    input_boxes = [input_box1, input_box2]
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            for box in input_boxes:
                box.handle_event(event)

        for box in input_boxes:
            box.update()

        screen.fill((30, 30, 30))
        for box in input_boxes:
            box.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    main()
    pg.quit()

There are also third party modules available like pygame_textinput.




回答2:


You can find a great module for Pygame text input here.

I have been using it for a while and I really like it. A tutorial how to use it is included in the description.

However, I have added the possibility to draw a (coloured) rectangle around the text, by adding a rect and a rect_color parameter to the *_init_() function and adding

if self.rect != None:
    pygame.draw.rect(screen, self.rect_color, self.rect)    #screen is my pygame display surface

to the update(self, events) function.




回答3:


Use the KEYDOWN event to get the input from the keyboard (see pygame.event). The key that was pressed can be obtained from the key attribute of the pygame.event.Event object. unicode contains a single character string that is the fully translated character. Add the character to the text when a key is pressed.
Two special keys need to be dealt with. If RETURN is pressed, the input is finished. If BACKSPACE is pressed, the last character of the input text must be removed:

repl.it/@Rabbid76/PyGame-TextInput

import pygame
pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()

font = pygame.font.SysFont(None, 100)
text = ""
input_active = True

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            input_active = True
            text = ""
        elif event.type == pygame.KEYDOWN and input_active:
            if event.key == pygame.K_RETURN:
                input_active = False
            elif event.key == pygame.K_BACKSPACE:
                text =  text[:-1]
            else:
                text += event.unicode

        window.fill(0)
        text_surf = font.render(text, True, (255, 0, 0))
        window.blit(text_surf, text_surf.get_rect(center = window.get_rect().center))
        pygame.display.flip()

pygame.quit()
exit()

Use the algorithm in a pygame.sprite.Sprite class. Handle the event in the update method.Determine whether the mouse clicks in the text entry field with collidepoint (see How to detect when a rectangular object, image or sprite is clicked) and activate the text input box:

class TextInputBox(pygame.sprite.Sprite):
    # [...]

    def update(self, event_list):
        for event in event_list:
            if event.type == pygame.MOUSEBUTTONDOWN and not self.active:
                self.active = self.rect.collidepoint(event.pos)
            if event.type == pygame.KEYDOWN and self.active:
                if event.key == pygame.K_RETURN:
                    self.active = False
                elif event.key == pygame.K_BACKSPACE:
                    self.text = self.text[:-1]
                else:
                    self.text += event.unicode
                self.render_text()

Pass the list of events to the update method of the Group that contains the Sprite:

event_list = pygame.event.get()
for event in event_list:
    if event.type == pygame.QUIT:
        run = False
group.update(event_list)

Minimal example: repl.it/@Rabbid76/PyGame-SpriteTextInput

import pygame

class TextInputBox(pygame.sprite.Sprite):
    def __init__(self, x, y, w, font):
        super().__init__()
        self.color = (255, 255, 255)
        self.backcolor = None
        self.pos = (x, y) 
        self.width = w
        self.font = font
        self.active = False
        self.text = ""
        self.render_text()

    def render_text(self):
        t_surf = self.font.render(self.text, True, self.color, self.backcolor)
        self.image = pygame.Surface((max(self.width, t_surf.get_width()+10), t_surf.get_height()+10), pygame.SRCALPHA)
        if self.backcolor:
            self.image.fill(self.backcolor)
        self.image.blit(t_surf, (5, 5))
        pygame.draw.rect(self.image, self.color, self.image.get_rect().inflate(-2, -2), 2)
        self.rect = self.image.get_rect(topleft = self.pos)

    def update(self, event_list):
        for event in event_list:
            if event.type == pygame.MOUSEBUTTONDOWN and not self.active:
                self.active = self.rect.collidepoint(event.pos)
            if event.type == pygame.KEYDOWN and self.active:
                if event.key == pygame.K_RETURN:
                    self.active = False
                elif event.key == pygame.K_BACKSPACE:
                    self.text = self.text[:-1]
                else:
                    self.text += event.unicode
                self.render_text()

pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)

text_input_box = TextInputBox(50, 50, 400, font)
group = pygame.sprite.Group(text_input_box)

run = True
while run:
    clock.tick(60)
    event_list = pygame.event.get()
    for event in event_list:
        if event.type == pygame.QUIT:
            run = False
    group.update(event_list)

    window.fill(0)
    group.draw(window)
    pygame.display.flip()

pygame.quit()
exit()



回答4:


The pygame_gui module allows you to create a text_input box from the user by creating a UITextEntryLine instance. You'll need to set up an instance as in the quick start guide.

Create the text_input:

from pygame.rect import Rect
from pygame_gui.elements.ui_text_entry_line import UITextEntryLine
text_input = UITextEntryLine(relative_rect=Rect(0, 0, 100, 100), manager=manager)

Get the text if enter is clicked:

for event in pygame.event.get():
    if event.type == pygame.USEREVENT:
        if event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
            if event.ui_element == text_input:
                entered_text = text


来源:https://stackoverflow.com/questions/66103997/making-login-system-onto-pygame-using-pre-existing-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!