Search code examples
pythonpygametextbox

Why can't I type more than 1 letter into my pygame textboxes?


I want the user to be able to type a name into each of the 2 textboxes when they click on them. Instead what happens is the next letter will always replace the previous letter instead of writing out a new letter onto the screen. For example, if you try to type "mat" then the a will replace the m and the t will replace the a. How do I fix this?

from pygame import *

screen_width = 1400
screen_height = 800

init()
screen = display.set_mode((screen_width, screen_height))

name_font = font.Font(None, 32)
name_1 = ""
name_2 = ""


class Rectangle:

    def __init__(self, x, y):
        self.name = ""
        self.active = False
        self.x = x
        self.y = y

        self.text_surface = name_font.render(self.name, True, (255, 255, 255))
        self.rect_width = max(140, 10 + self.text_surface.get_width())
        self.input_rect = Rect(x, y, self.rect_width, 32)
        self.input_rect.w = self.text_surface.get_width() + 10
        self.click_value = 10

    def naming(self, player_name):

        for e in events:
            if e.type == MOUSEBUTTONDOWN:
                if self.input_rect.x + self.click_value >= mx >= self.input_rect.x - 10 and self.input_rect.y + 26 >= my >= self.input_rect.y - 10:
                    self.active = True
                else:
                    self.active = False

            if e.type == KEYDOWN:
                if self.active:
                    if e.key == K_BACKSPACE:
                        player_name = player_name[:-1]
                        screen.fill((0, 0, 0))
                    else:
                        player_name += e.unicode
                        self.click_value += 7

                    self.text_surface = name_font.render(player_name, True, (255, 255, 255))

    def draw(self, screen):
        draw.rect(screen, (0, 0, 0), self.input_rect, 0)
        draw.rect(screen, (255, 255, 255), self.input_rect, 2)
        self.input_rect.w = self.text_surface.get_width() + 10
        screen.blit(self.text_surface, (self.input_rect.x + 5, self.input_rect.y + 5))


rect_1 = Rectangle(200, 200)

rect_2 = Rectangle(200, 400)

while True:
    mx, my = mouse.get_pos()

    events = event.get()
    for e in events:
        if e.type == QUIT:
            quit()

    screen.fill((0, 0, 0))
    rect_1.naming(name_1)
    rect_1.draw(screen)

    rect_2.naming(name_2)
    rect_2.draw(screen)

    display.update()
    time.delay(1)

I think it has something to do with the placement of the name_1 and name_2 variables but I'm not entirely sure.


Solution

  • Pyhton has not concept of in-out parameters. Use the self.name attribute, instead of an argument:

    from pygame import *
    
    screen_width = 1400
    screen_height = 800
    
    init()
    screen = display.set_mode((screen_width, screen_height))
    
    name_font = font.Font(None, 32)
    name_1 = ""
    name_2 = ""
    
    class Rectangle:
    
        def __init__(self, x, y):
            self.name = ""
            self.active = False
            self.x = x
            self.y = y
    
            self.text_surface = name_font.render(self.name, True, (255, 255, 255))
            self.rect_width = max(140, 10 + self.text_surface.get_width())
            self.input_rect = Rect(x, y, self.rect_width, 32)
            self.input_rect.w = self.text_surface.get_width() + 10
            self.click_value = 10
    
        def naming(self):
    
            for e in events:
                if e.type == MOUSEBUTTONDOWN:
                    if self.input_rect.x + self.click_value >= mx >= self.input_rect.x - 10 and self.input_rect.y + 26 >= my >= self.input_rect.y - 10:
                        self.active = True
                    else:
                        self.active = False
    
                if e.type == KEYDOWN:
                    if self.active:
                        if e.key == K_BACKSPACE:
                            self.name = self.name[:-1]
                            screen.fill((0, 0, 0))
                        else:
                            self.name += e.unicode
                            self.click_value += 7
    
                        self.text_surface = name_font.render(self.name, True, (255, 255, 255))
            return self.name
    
        def draw(self, screen):
            draw.rect(screen, (0, 0, 0), self.input_rect, 0)
            draw.rect(screen, (255, 255, 255), self.input_rect, 2)
            self.input_rect.w = self.text_surface.get_width() + 10
            screen.blit(self.text_surface, (self.input_rect.x + 5, self.input_rect.y + 5))
    
    
    rect_1 = Rectangle(200, 200)
    
    rect_2 = Rectangle(200, 400)
    
    while True:
        mx, my = mouse.get_pos()
    
        events = event.get()
        for e in events:
            if e.type == QUIT:
                quit()
    
        screen.fill((0, 0, 0))
        name_1 = rect_1.naming()
        rect_1.draw(screen)
    
        name_2 = rect_2.naming()
        rect_2.draw(screen)
    
        display.update()
        time.delay(1)