Search code examples
pythontextpygamedrawing

How to allow the user to type only under certain conditions in pygame?


When you click the textbox I want the user to be able to type letters by setting self.active to True. When you click off the text box I want the player to lose that ability by setting self.active to False. However when I click the text box, self.active becomes true for a split second before becoming False again. How do I fix this?

from pygame import *

init()
screen = display.set_mode((800, 600))

name_font = font.Font(None, 32)
name_text = ''


class Rectangle:

    def __init__(self, x, y):
        self.active = False
        self.x = x
        self.y = y
        self.text_surface = name_font.render(name_text, 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)
        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))

    def naming(self):
        global rect_1
        global name_text

        if events.type == MOUSEBUTTONDOWN:
            if self.input_rect.x + 150 >= mx >= self.input_rect.x - 10:
                if self.input_rect.y + 40 >= my >= self.input_rect.y - 10:
                    self.active = True
            if not self.input_rect.x + 150 >= mx >= self.input_rect.x - 10:
                if not self.input_rect.y + 40 >= my >= self.input_rect.y - 10:
                    self.active = False

        if self.active:
            if events.type == KEYDOWN:
                if keys[K_BACKSPACE]:
                    name_text = name_text[:-1]
                    screen.fill((0, 0, 0))
                    rect_1 = Rectangle(200, 200)
                else:
                    name_text += events.unicode


while True:
    rect_1 = Rectangle(200, 200)
    mx, my = mouse.get_pos()
    for events in event.get():
        keys = key.get_pressed()
        rect_1.naming()
        if events.type == QUIT:
            quit()

    display.update()
    time.delay(1)

Solution

  • Create the instance of Rectangle before the application loop, but you have to pass the list of events to the method naming and to handle all the relevant events in the method. Add a draw method to the class and draw the object in every frame:

    class Rectangle:
        # [...]
    
        def naming(self, events):
            # [...]
    
            for event in evetnts:
                if e.type == KEYDOWN:
                    # [...]
    
            
                if e.type == # [...]
    
        def draw(self, screen):
            # [...]
    
    rect_1 = Rectangle(200, 200)
    
    run = True
    while run :
        
        events = event.get()
        for e in events:
            if e.type == QUIT:
                run = False
        
        rect_1.naming(events)
    
        # [...]
    
        rect_1.draw(screen)      
    

    Complete example:

    import pygame
    from pygame import *
    
    init()
    screen = display.set_mode((800, 600))
    
    name_font = font.Font(None, 32)
    name_text = ''
    
    
    class Rectangle:
    
        def __init__(self, x, y):
            self.active = False
            self.x = x
            self.y = y
            self.text_surface = name_font.render(name_text, 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)
            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))
    
        def naming(self, events):
            global rect_1
            global name_text
    
            for e in events:
                if e.type == MOUSEBUTTONDOWN:
                    mx, my = e.pos
                    if self.input_rect.x + 150 >= mx >= self.input_rect.x - 10:
                        if self.input_rect.y + 40 >= my >= self.input_rect.y - 10:
                            self.active = True
                    if not self.input_rect.x + 150 >= mx >= self.input_rect.x - 10:
                        if not self.input_rect.y + 40 >= my >= self.input_rect.y - 10:
                            self.active = False
    
                if e.type == KEYDOWN:
                    if self.active:
                        if e.key == K_BACKSPACE:
                            name_text = name_text[:-1]
                        else:
                            name_text += e.unicode
                        self.text_surface = name_font.render(name_text, 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)
    
    run = True
    while run :
        
        events = event.get()
        for e in events:
            if e.type == QUIT:
                run = False
        
        rect_1.naming(events)
    
        screen.fill(0)
        rect_1.draw(screen)  
        display.update()
        time.delay(1)