【问题标题】:How can I create a text input box with Pygame?如何使用 Pygame 创建文本输入框?
【发布时间】:2016-09-08 17:28:15
【问题描述】:

我想在 Python 中从用户那里获取一些文本输入,并在文本框中显示他们正在输入的内容,当他们按下回车键时,它会存储在一个字符串中。

我到处找,但我什么也找不到。我正在使用 Pygame。

【问题讨论】:

    标签: python text pygame textinput


    【解决方案1】:

    您可以将rect 定义为输入框的区域。如果发生pygame.MOUSEBUTTONDOWN 事件,请使用input_box rect 的colliderect 方法检查它是否与event.pos 冲突,然后通过将active 变量设置为True 来激活它。

    如果该框处于活动状态,您可以输入一些内容,Pygame 将生成具有 unicode 属性的 pygame.KEYDOWN 事件,您可以简单地将其添加到字符串中,例如text += event.unicode。如果用户按下回车键,您可以对text 字符串执行一些操作(在示例中我只是打印它)并将其重置为''

    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()
    

    这是一个面向对象的变体,可让您轻松创建多个输入框:

    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()
    

    还有第三方模块可用,例如pygame_textinput

    【讨论】:

      【解决方案2】:

      使用KEYDOWN 事件从键盘获取输入(请参阅pygame.event)。按下的键可以从pygame.event.Event 对象的key 属性中获取。 unicode 包含一个字符串,它是完全翻译的字符。按下某个键时将字符添加到文本中。
      需要处理两个特殊键。如果按下RETURN,则输入完成。如果按下 BACKSPACE,则必须删除输入文本的最后一个字符:

      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()
      

      pygame.sprite.Sprite 类中使用算法。在update方法中处理事件。用collidepoint判断鼠标是否在文本输入栏点击(见How to detect when a rectangular object, image or sprite is clicked)并激活文本输入框:

      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()
      

      将事件列表传递给包含 SpriteGroupupdate 方法:

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

      最小示例: 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()
      

      【讨论】:

        【解决方案3】:

        你可以找到一个很棒的 Pygame 文本输入模块here

        我已经使用了一段时间,我真的很喜欢它。描述中包含如何使用它的教程。

        不过,我通过在 *_ 中添加 rectrect_color 参数,增加了在文本周围绘制(彩色)矩形的可能性。 init_() 函数及添加

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

        update(self, events) 函数。

        【讨论】:

          【解决方案4】:

          pygame_gui 模块允许您通过创建UITextEntryLine 实例来从用户创建文本输入框。您需要在quick start guide 中设置一个实例。

          创建文本输入:

          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)
          

          如果点击输入则获取文本:

          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 = event.text
          

          【讨论】:

          • 如果您可以添加对pygame_gui 的依赖,这是一个非常简单易用的解决方案。请注意,在示例中,最后一行实际上应该是 entered_text = event.text
          【解决方案5】:

          我写了一个可以处理文本输入的类

          小例子:

          import pygame as pg
          from pgtextbox import pgtextbox
          pg.init()
          
          screen=pg.display.set_mode((1000,500))
          textbox=pgtextbox(200,20)
          textbox.insertAtCurser('Hallo')
          
          while True:
              e = pg.event.wait(30000)
              if e.type == pg.QUIT:
                  raise StopIteration
          
              textbox.addPgEvent(e)#uses keydown events
              
              print(textbox.text)
          
              screen.fill((0,0,0))
              screen.blit(textbox.render(),(10,0))
              pg.display.flip()
          pg.display.quit()
          

          pgtextbox 类:

          import pygame as pg
          
          class pgtextbox:#By K1521
              def __init__(self,width=100,height=10,fontname=None):
                  self.surface=pg.Surface((width,height))
                  self.text=""
                  self.width=width
                  self.height=height
                  self.font=pg.font.Font(fontname,pgtextbox.getMaxFontSize(fontname,lineheight=height))
                  self.curserindex=0
                  self.cursersurface=pg.Surface((self.font.size("|")[0]//2,self.font.size("|")[1]))
                  self.cursersurface.fill((255,255,255))
                  #self.cursersurface=self.font.render("|",False,(255,255,255),(0,0,0))
                  self.offsety=int((height-self.font.get_linesize())/2)
                  self.offsetx=0
          
          
              def curserpos(self):
                  return self.font.size(self.text[:self.curserindex])[0]
          
              def addPgEvent(self,event):
                  if event.type==pg.KEYDOWN:
                      if event.key==pg.K_BACKSPACE:
                          self.deleteAtCurser()
                      elif event.key==pg.K_RIGHT:
                          self.offsetCurser(1)
                      elif event.key==pg.K_LEFT:
                          self.offsetCurser(-1)
                      else:
                          self.insertAtCurser(event.unicode)
          
              def render(self):
                  self.surface.fill((0,0,0))
          
                  width=self.width-self.cursersurface.get_width()
                  text=self.font.render(self.text,False,(255,255,255),(0,0,0))
          
          
                  if self.curserindex>=0:
                      curserpos=self.curserpos()+self.offsetx
          
                      curserposnew=max(0,min(curserpos,width))
                      self.offsetx+=curserposnew-curserpos
                      curserpos=curserposnew
                      #if curserpos<0:
                          #self.offsetx-=curserpos
                          #curserpos=0
                      #if curserpos>width:
                          #curserpos=curserpos-width
                          #self.offsetx-=curserpos
                  else:
                      #self.offsetx=min(width-text.get_width(),0)
                      self.offsetx=0
          
                  self.surface.blit(text,(self.offsetx,self.offsety))
                  if self.curserindex>=0:
                      self.surface.blit(self.cursersurface,(curserpos,self.offsety))
                      #print((curserpos,self.offsety))
                  return self.surface
          
              def insertAtCurser(self,t):
                  if self.curserindex<0:
                      self.curserindex=len(self.text)
                  self.text=self.text[:self.curserindex]+t+self.text[self.curserindex:]
                  self.curserindex+=len(t)
          
              def deleteAtCurser(self,length=1):
                  if self.curserindex<0:
                      self.curserindex=len(self.text)
          
                  newcurserindex=max(0,self.curserindex-length)
                  self.text=self.text[:newcurserindex]+self.text[self.curserindex:]
                  self.curserindex=newcurserindex
          
              def offsetCurser(self,i):
                  self.curserindex=max(min(self.curserindex+i,len(self.text)),0)
          
          
              @staticmethod
              def longestline(self,fontname,lines):
                  size=pg.font.Font(fontname,1000)
                  return max(lines,key=lambda t:size(t)[0])
          
              @staticmethod
              def getMaxFontSize(fontname,width=None,lineheight=None,line=None):
                  def font(size):
                      return pg.font.Font(fontname,size)
                  fontsize=float("inf")# inf
          
                  if width:
                      aproxsize=width*1000//font(1000).size(line)[0]
                      while font(aproxsize).size(line)[0]<width:
                          aproxsize+=1
                      while font(aproxsize).size(line)[0]>width:
                          aproxsize-=1
                      fontsize=min(aproxsize,fontsize)
          
                  if lineheight:
                      aproxsize=lineheight*4//3
                      while font(aproxsize).get_linesize()<lineheight:
                          aproxsize+=1
                      while font(aproxsize).get_linesize()>lineheight:
                          aproxsize-=1
                      fontsize=min(aproxsize,fontsize)
                  return fontsize
          
              @staticmethod
              def rendermultilinetext(text,width=None,height=10,fontname=None,antialias=False,color=(255,255,255),background=None):
                  if(len(text)-text.count("\n")==0):
                      return pg.Surface((0,0))
                  def font(size):
                      return pg.font.Font(fontname,size)
          
                  text=text.split("\n")
                  fontsize=1000000000# inf
          
                  longestline=None
                  if height:
                      longestline=pgtextbox.longestline(fontname,lines)
                  fontsize=pgtextbox.getMaxFontSize(fontname,width,lineheight,longestline)
          
                  font=font(fontsize)
                  width=font.size(longestline)[0]
                  lineheight=font.get_linesize()
                  heigth=len(text)*lineheight
                  textsurface=pg.Surface((width,heigth))
                  if background:
                      textsurface.fill(background)
                  for i,line in enumerate(text):
                      textsurface.blit(font.render(line,antialias,color,background),(0,i*lineheight))
                  return textsurface
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-04-28
            • 1970-01-01
            • 2013-07-01
            相关资源
            最近更新 更多