[Pygame] Input box

[Pygame] Input box

Postby metulburr » Fri May 24, 2013 8:36 pm

Well the input box works, its just after passing the box the input goes off out of the box. The natural way and expectancy of an input box is for the box to follow along if the text gets to the end of the box. I am just not sure a solution on how to implement this.

This code was found and i modified it a little to handle @, and shifting, I didnt think any other special characters would be needed

Code: Select all

import pygame

pygame.init()

class Input:
   def __init__(self):
      self.shift = False
      self.white = (255,255,255)
      self.red = (255,10,10)
      self.black = (0,0,0)
      
   def get_key(self):
      while True:
         event = pygame.event.poll()
         if event.type == pygame.KEYDOWN:
            #print(event.key)
            if event.key in [pygame.K_LSHIFT, pygame.K_RSHIFT]:
               self.shift = True
               continue
               
            if self.shift:
               #return ascii code
               if event.key >= 97 and event.key <= 122:
                  return event.key - 32
               elif event.key == 50:
                  return 64 #return @
               elif event.key == 32:
                  return 32 #return space even if shifted
                  
            elif not self.shift:
               return event.key
         elif event.type == pygame.KEYUP:
            if event.key in [pygame.K_LSHIFT, pygame.K_RSHIFT]:
               self.shift = False
         else:
            pass

   def display_box(self, screen, message):
      fontobject = pygame.font.Font(None, 18)
      pygame.draw.rect(screen, self.white,
         ((screen.get_width() / 2) - 102, (screen.get_height() / 2) - 15, 204,24)) #if border add 1 for transp
      if len(message) != 0:
         screen.blit(fontobject.render(message, 1 , self.black),
            ((screen.get_width() / 2) - 100, (screen.get_height() / 2) - 10))
      pygame.display.update()
      
   def ask(self, screen, question):
      current_string = []
      self.display_box(screen, question + ': ' + ''.join(current_string))
      while True:
         inkey = self.get_key()
         if inkey == pygame.K_BACKSPACE:
            current_string = current_string[0:-1]
         elif inkey == pygame.K_RETURN:
            break
         else:
            current_string.append(chr(inkey))
         self.display_box(screen, question + ': ' + ''.join(current_string))
      return ''.join(current_string)

input_box = Input()
screen = pygame.display.set_mode((600,400))
var = input_box.ask(screen, 'Name')
print(var + ' was entered')

var = input_box.ask(screen, 'Address')
print(var + ' was entered')

var = input_box.ask(screen, 'Email')
print(var + ' was entered')
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1470
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] Input box

Postby DrakeMagi » Fri May 24, 2013 10:31 pm

you can just use event.unicode to get letter
i use a mouse to select textbox
my textbox rolls
I didn't use arrow keys

here my rough example of a textbox
Code: Select all
import pygame
pygame.init()

# Page class is use as an inheritance
class Page(object):
   def Entrance(self):
      pass
     
   def OnExit(self):
      pass
   
   def Blit(self, surface):
      pass
     
   def Event(self, event):
      pass
     
   def Update(self, tick):
      pass

# made to interface with Page Class
class Handler(object):
   def __init__(self, caption, width, height, flags = 0, depth=0 ):
      self.Screen = pygame.display.set_mode( (width, height), flags, depth )
      pygame.display.set_caption( caption )

      self.Clock = pygame.time.Clock()
      self.Tick = pygame.time.get_ticks()
      self.Fps = 60
     
      self.Pages = {}
     
      self.__current = None
      self.__new_page = None
     
   def SetPage(self, name):
      self.__new_page = name

   def Loop(self):
      Run = True;
     
      while(Run):
         if self.__new_page is not None:
            if self.__current is not None:
               self.Pages[self.__current].OnExit()
            self.__current = self.__new_page
            self.Pages[self.__current].Entrance()
            self.__new_page = None
           
         for event in pygame.event.get():
            if event.type == pygame.QUIT:
               Run = False
            else:
               if self.__current is not None:
                  self.Pages[self.__current].Event(event)
                 
         if self.__current is not None:
            self.Pages[self.__current].Blit(self.Screen)
           
         self.Tick = pygame.time.get_ticks()
         if self.__current is not None:
            self.Pages[self.__current].Update(self.Tick)
               
         pygame.display.flip()
         self.Clock.tick( self.Fps )

class Textbox(object):
    def __init__(self, rect):
        self.rect = rect
        self.inner = pygame.Rect(rect.x + 2, rect.y + 2, rect.w - 4, rect.h - 4)
        self.text = ""
        self.font = pygame.font.Font(None, 30)
        self.image = self.font.render(self.text, 1, (255,255,255))
        self.focus = False

    def Blit(self, surface):
        if self.focus:
            pygame.draw.rect(surface, (0,100,200), self.rect)
        else:
            pygame.draw.rect(surface, (0,0,120), self.rect)
        pygame.draw.rect(surface, (0,0,0), self.inner)
                         
        surface.blit(self.image,  self.inner.topleft)

    def __render(self):
        if len(self.text) > 0:
            for n in range(len(self.text)):
                if self.font.size(self.text[n:])[0] < self.rect.w - 4:
                    self.image = self.font.render(self.text[n:], 1, (255,255,255))
                    break
        else:
             self.image = self.font.render(self.text, 1, (255,255,255))

    def Event(self, event):
        if event.type == pygame.KEYDOWN:
            if self.focus:
                if 32 <= event.key < 123:
                    self.text += str(event.unicode)
                elif event.key == pygame.K_BACKSPACE:
                    if len(self.text) > 1:
                        self.text = self.text[:-1]
                    else:
                        self.text = ""
                elif event.key == pygame.K_DELETE:
                    self.text = ""
                self.__render()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                if self.rect.collidepoint(event.pos):
                    self.focus = True
                else:
                    self.focus = False

class SamplePage( Page ):
    def __init__(self):
        self.name = Textbox(pygame.Rect(50,50,150,30))
        self.address = Textbox(pygame.Rect(50,100,150,30))

    def Blit(self, surface):
        self.name.Blit(surface)
        self.address.Blit(surface)

    def Event(self, event):
        self.name.Event(event)
        self.address.Event(event)

if __name__ == '__main__':
    screen = Handler('TextBox Example', 800, 600)
    screen.Pages['Sample'] = SamplePage()
    screen.SetPage('Sample')
    screen.Loop()
    pygame.quit()
Linux: won't find windows here.
Linux: the choice of a GNU generation.
https://github.com/DrakeMagi
DrakeMagi
 
Posts: 112
Joined: Sun May 12, 2013 8:36 pm

Re: [Pygame] Input box

Postby metulburr » Sat May 25, 2013 6:45 am

OK thanks DrakeMagi. It took me awhile to figure out your code, but was able to implement it into mine.

Code: Select all
import pygame

class TextBox:
    def __init__(self, rect, width=1):
        self.selected = False
        self.font_size = 15
        self.font = pygame.font.SysFont('Arial', self.font_size)
        self.str_list = []
        self.width = width
        self.color = (255,255,255)
        self.rect = rect
       
    def char_add(self, event):
        '''modify string list based on event.key'''
        if event.key == pygame.K_BACKSPACE:
            if self.str_list:
                self.str_list.pop()
        elif event.key == pygame.K_RETURN:
            return ''.join(self.str_list)
        elif event.key in [pygame.K_TAB, pygame.K_KP_ENTER]:#unwanted keys
            return False
        elif event.key == pygame.K_DELETE:
            self.str_list = []
            return False
        else:
            char = event.unicode
            if char: #stop emtpy space for shift key adding to list
                self.str_list.append(char)

    def update(self, scr):
        if self.selected:
            w = 2
        else:
            w = self.width
       
        s = ''.join(self.str_list)
        if len(s) > 0:
            for n, l in enumerate(s):
                if self.font.size(s[n:])[0] < self.rect.width:
                    label = self.font.render(s[n:], 1, self.color)
                    break
        else:
            label = self.font.render(s, 1, self.color)
       
        pygame.draw.rect(scr, self.color, self.rect, w)
        scr.blit(label, self.rect)

class Control:
    def __init__(self):
        pygame.init()
        self.screensize = (800,600)
        self.screen = pygame.display.set_mode(self.screensize)
        self.clock = pygame.time.Clock()
        self.gamestate = True
        self.input_entered = None
       
        self.textboxes = [
            TextBox(pygame.Rect(100,300, 300,25), 1),
            TextBox(pygame.Rect(100,500, 300,25), 1)
        ]
       
    def update(self):
        self.screen.fill((0,0,0))
        for box in self.textboxes:
            box.update(self.screen)
        pygame.display.flip()
        self.input_enetered = None
       
       
    def mainloop(self):
        while self.gamestate:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.gamestate = False
                elif event.type == pygame.KEYDOWN:
                    for box in self.textboxes:
                        if box.selected:
                            self.input_entered = box.char_add(event)
                            if self.input_entered:
                                print(self.input_entered)
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        for box in self.textboxes:
                            if box.rect.collidepoint(pygame.mouse.get_pos()):
                                box.selected = True
                            else:
                                box.selected = False
            self.update()
           

app = Control()
app.mainloop()
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1470
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] Input box

Postby metulburr » Sat May 25, 2013 5:38 pm

OK my end goal was to get a basic text box with enter submiting, and a button to link to the textbox and submit also. I think i have abasic template of what i was trying to do:

Code: Select all
import pygame

class TextBox:
    def __init__(self, rect, width=1):
        self.selected = False
        self.font_size = 15
        self.font = pygame.font.SysFont('Arial', self.font_size)
        self.str_list = []
        self.width = width
        self.color = (255,255,255)
        self.rect = rect
        self.string = ''.join(self.str_list)
       
    def char_add(self, event):
        '''modify string list based on event.key'''
        if event.key == pygame.K_BACKSPACE:
            if self.str_list:
                self.str_list.pop()
        elif event.key == pygame.K_RETURN:
            return ''.join(self.str_list)
        elif event.key in [pygame.K_TAB, pygame.K_KP_ENTER]:#unwanted keys
            return False
        elif event.key == pygame.K_DELETE:
            self.str_list = []
            return False
        else:
            char = event.unicode
            if char: #stop emtpy space for shift key adding to list
                self.str_list.append(char)

    def update(self, scr):
       
        if self.selected:
            width = 2
        else:
            width = self.width
       
        s = ''.join(self.str_list)
        if len(s) > 0:
            for n, l in enumerate(s):
                if self.font.size(s[n:])[0] < self.rect.width:
                    label = self.font.render(s[n:], 1, self.color)
                    break
        else:
            label = self.font.render(s, 1, self.color)
       
        self.string = ''.join(self.str_list)
        pygame.draw.rect(scr, self.color, self.rect, width)
        scr.blit(label, self.rect)
       
class Button:
    def __init__(self, text, rect):
        self.text = text
        self.is_hover = False
        self.default_color = (100,100,100)
        self.hover_color = (255,255,255)
        self.font_color = (0,0,0)
        self.rect = rect
       
    def label(self):
        '''button label font'''
        font = pygame.font.Font(None, 20)
        return font.render(self.text, 1, self.font_color)
       
    def color(self):
        '''change color when hovering'''
        if self.is_hover:
            return self.hover_color
        else:
            return self.default_color
           
    def update(self, screen):
        pygame.draw.rect(screen, self.color(), self.rect)
        screen.blit(self.label(), self.rect)
       
        #change color if mouse over button
        self.check_hover(pygame.mouse.get_pos())
       
    def check_hover(self, mouse):
        '''adjust is_hover value based on mouse over button - to change hover color'''
        if self.rect.collidepoint(mouse):
            self.is_hover = True
        else:
            self.is_hover = False

class Control:
    def __init__(self):
        pygame.init()
        self.screensize = (800,600)
        self.screen = pygame.display.set_mode(self.screensize)
        self.clock = pygame.time.Clock()
        self.gamestate = True
        self.input_entered = None
       
        self.textboxes = [
            TextBox(pygame.Rect(100,300, 300,25), 1),
            #TextBox(pygame.Rect(100,500, 300,25), 1)
        ]
        self.btn = Button('Submit', pygame.Rect(100,350, 100, 25))
       
    def update(self):
        self.screen.fill((0,0,0))
        for box in self.textboxes:
            box.update(self.screen)
        self.btn.update(self.screen)
        pygame.display.flip()
        #self.input_enetered = None
       
       
    def mainloop(self):
        while self.gamestate:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.gamestate = False
                elif event.type == pygame.KEYDOWN:
                    for box in self.textboxes:
                        if box.selected:
                            self.input_entered = box.char_add(event)
                            if self.input_entered:
                                print(self.input_entered)
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        for box in self.textboxes:
                            if box.rect.collidepoint(pygame.mouse.get_pos()):
                                box.selected = True
                            else:
                                box.selected = False
                            if self.btn.rect.collidepoint(pygame.mouse.get_pos()):
                                if box.string:
                                    print(box.string)
            self.update()




app = Control()
app.mainloop()
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1470
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY


Return to Game Development

Who is online

Users browsing this forum: Bing [Bot] and 2 guests