Python Forum
[PyGame] Returning information from textbox?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] Returning information from textbox?
#1
Hey!

I'm doing my A-Level computing project and have come across a problem. My program has a login system in which there is a database with usernames/passwords and entering your username/password into a textbox will then check to see if that is in the database and let you log in if it is. My issue is that I can't find a way to return information from the textbox function to be able to use it in my database search. Can anyone help, please?

Here is my textbox code.

def textbox():                                  # creating the textbox
    inputBox = pygame.Rect(50, 185, 500, 80)
    inactiveColour = BLUE
    activeColour = LIGHTBLUE
    colour = inactiveColour
    active = False
    done = False
    text = ' '

    while not done:
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN:    # change textbox colour when clicked
                if inputBox.collidepoint(event.pos):
                    active = not active                 # changes from whatever the state currently is
                else:
                    active = False

            if active:
                colour = activeColour
            else:
                colour = inactiveColour

            if event.type == pygame.KEYDOWN:        
                if active:
                    if event.key == pygame.K_RETURN:    # information will be returned when enter key is pressed
                        print(text)
                        text = ' '
                        done = True
                    elif event.key == pygame.K_BACKSPACE:   # a letter will be removed if backspace is pressed
                        text = text[:-1]
                    else:
                        text = text + event.unicode         # otherwise, text will be added to the textbox

        text_surface = buttonText.render(text, True, colour)
        width = max(500, text_surface.get_width() + 10)         # width of textbox increases if there is not enough space
        inputBox.w = width

        screen.blit(text_surface, (inputBox.x+5, inputBox.y+5))     # blit textbox onto screen
        pygame.draw.rect(screen, colour, inputBox, 2)

        pygame.display.flip()   # update game display

    return text
Here is the code where I am attempting to retrieve the information put into the textbox.
def loginScreen():
    screen.fill(WHITE)
    usernameSurface = lettersTitle.render('Please enter your username:', False, BLACK)
    screen.blit(usernameSurface, (50, 50))
    username = textbox()
    print("username is " + username)
The username prints in the textbox function, but when the last print statement in the loginScreen function is reached, it simply prints "username is " with nothing afterwards.
Reply
#2
Textbox should be redone to work with mainloop.

Line 27 always assign text a space.
So it will always return a space.
99 percent of computer problems exists between chair and keyboard.
Reply
#3
the problem is you are expecting your function to return the value, but you also have the main loop in the function that is expected to return it. Its not going to work in any sensible method and i would suggest to redo it.

Here is an example of a textbox class.
import pygame as pg
import string

class TextBox(object):
    def __init__(self,rect,**kwargs):
        '''
        Optional kwargs and their defaults:
            "id" : None,
            "command" : None,
                function to execute upon enter key
                Callback for command takes 2 args, id and final (the string in the textbox)
            "active" : True,
                textbox active on opening of window
            "color" : pg.Color("white"),
                background color
            "font_color" : pg.Color("black"),
            "outline_color" : pg.Color("black"),
            "outline_width" : 2,
            "active_color" : pg.Color("blue"),
            "font" : pg.font.Font(None, self.rect.height+4),
            "clear_on_enter" : False,
                remove text upon enter
            "inactive_on_enter" : True
            "blink_speed": 500
                prompt blink time in milliseconds
            "delete_speed": 500
                backspace held clear speed in milliseconds
            
        Values:
            self.rect = pg.Rect(rect)
            self.buffer = []
            self.final = None
            self.rendered = None
            self.render_rect = None
            self.render_area = None
            self.blink = True
            self.blink_timer = 0.0
            self.delete_timer = 0.0
            self.accepted = string.ascii_letters+string.digits+string.punctuation+" "
        '''
        self.rect = pg.Rect(rect)
        self.buffer = []
        self.final = None
        self.rendered = None
        self.render_rect = None
        self.render_area = None
        self.blink = True
        self.blink_timer = 0.0
        self.delete_timer = 0.0
        self.accepted = string.ascii_letters+string.digits+string.punctuation+" "
        self.process_kwargs(kwargs)

    def process_kwargs(self,kwargs):
        defaults = {"id" : None,
                    "command" : None,
                    "active" : True,
                    "color" : pg.Color("white"),
                    "font_color" : pg.Color("black"),
                    "outline_color" : pg.Color("black"),
                    "outline_width" : 2,
                    "active_color" : pg.Color("blue"),
                    "font" : pg.font.Font(None, self.rect.height+4),
                    "clear_on_enter" : False,
                    "inactive_on_enter" : True,
                    "blink_speed": 500,
                    "delete_speed": 75}
        for kwarg in kwargs:
            if kwarg in defaults:
                defaults[kwarg] = kwargs[kwarg]
            else:
                raise KeyError("TextBox accepts no keyword {}.".format(kwarg))
        self.__dict__.update(defaults)

    def get_event(self,event, mouse_pos=None):
        ''' Call this on your event loop
        
            for event in pg.event.get():
                TextBox.get_event(event)
        '''
        if event.type == pg.KEYDOWN and self.active:
            if event.key in (pg.K_RETURN,pg.K_KP_ENTER):
                self.execute()
            elif event.key == pg.K_BACKSPACE:
                if self.buffer:
                    self.buffer.pop()
            elif event.unicode in self.accepted:
                self.buffer.append(event.unicode)
        elif event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
            if not mouse_pos:
                mouse_pos = pg.mouse.get_pos()
            self.active = self.rect.collidepoint(mouse_pos)

    def execute(self):
        if self.command:
            self.command(self.id,self.final)
        self.active = not self.inactive_on_enter
        if self.clear_on_enter:
            self.buffer = []
            
    def switch_blink(self):
        if pg.time.get_ticks()-self.blink_timer > self.blink_speed:
            self.blink = not self.blink
            self.blink_timer = pg.time.get_ticks()

    def update(self):
        '''
        Call once on your main game loop
        '''
        new = "".join(self.buffer)
        if new != self.final:
            self.final = new
            self.rendered = self.font.render(self.final, True, self.font_color)
            self.render_rect = self.rendered.get_rect(x=self.rect.x+2,
                                                      centery=self.rect.centery)
            if self.render_rect.width > self.rect.width-6:
                offset = self.render_rect.width-(self.rect.width-6)
                self.render_area = pg.Rect(offset,0,self.rect.width-6,
                                           self.render_rect.height)
            else:
                self.render_area = self.rendered.get_rect(topleft=(0,0))
        self.switch_blink()
        self.handle_held_backspace()
        
    def handle_held_backspace(self):
        if pg.time.get_ticks()-self.delete_timer > self.delete_speed:
            self.delete_timer = pg.time.get_ticks()
            keys = pg.key.get_pressed()
            if keys[pg.K_BACKSPACE]:
                if self.buffer:
                    self.buffer.pop()

    def draw(self,surface):
        '''
        Call once on your main game loop
        '''
        outline_color = self.active_color if self.active else self.outline_color
        outline = self.rect.inflate(self.outline_width*2,self.outline_width*2)
        surface.fill(outline_color,outline)
        surface.fill(self.color,self.rect)
        if self.rendered:
            surface.blit(self.rendered,self.render_rect,self.render_area)
        if self.blink and self.active:
            curse = self.render_area.copy()
            curse.topleft = self.render_rect.topleft
            surface.fill(self.font_color,(curse.right+1,curse.y,2,curse.h))
and here is an example of roughly what you want with that class
pg.init()
screen = pg.display.set_mode((600,400))
done = False

def name_on_enter(id, final):
    print('enter pressed, username is "{}"'.format(final))
    
def pass_on_enter(id, final):
    print('enter pressed, password is "{}"'.format(final))

username_settings = {
    "command" : name_on_enter,
    "inactive_on_enter" : False,
}
password_settings = {
    "command" : pass_on_enter,
    "inactive_on_enter" : False,
}

name_entry = TextBox(rect=(70,100,150,30), **username_settings)
pass_entry = TextBox(rect=(70,200,150,30), **password_settings)

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        name_entry.get_event(event)
        pass_entry.get_event(event)
    name_entry.update()
    pass_entry.update()
    name_entry.draw(screen)
    pass_entry.draw(screen)
    pg.display.update()
It functions and acts like a text box. When you hit enter, it executes the function assigned via the command and passes the content of the textbox at that time to that function. So the callback function will have an ID and content as args like:
Quote:
def print_on_enter(id, final):
    print('enter pressed, textbox contains "{}"'.format(final))

If you had more than one textbox requirement
Recommended Tutorials:
Reply
#4
What do you mean by get it to work with mainloop? (sorry this is quite a dumb question haha)

Also, text is later set to whatever is entered into the textbox though? When I get it to print directly from the textbox function it works, but it doesn't work when I try to print it from the login function
Reply
#5
Quote:
def textbox():                                  # creating the textbox
 ...
    while not done:
Your main loop is in your textbox function. It will never leave that function. Thus it will never return. Unless you are using multiple game loops? Then you have even more problems than you think. If so see here on why on #8.
Recommended Tutorials:
Reply
#6
UPDATE: I feel really stupid, I thought I'd already gotten rid of the second 'text = ' '' bit lol. It now lets me print it but I feel like it shouldn't because of what you're saying (so now I'm even more confused haha)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Photo Textbox is being overdrawn G_rizzle 2 2,543 Apr-15-2021, 04:43 PM
Last Post: metulburr
  [Pygame] Problems with my textbox SheeppOSU 1 3,038 May-27-2019, 12:03 AM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020