使用两个实例的Python_textinput问题

时间:2019-01-11 13:57:19

标签: python python-3.x pygame

我正在使用python开发基于选择的冒险游戏,并且我正在使用pygame为游戏创建一些图形。

当我试图创建一个屏幕以便玩家可以输入他的真实姓名和主要角色名称时,我遇到了一个问题:当我尝试在同一屏幕上创建两个文本输入(使用pygame_textinput module)时,它只是克隆了我在其中之一中写的内容。

我以为可以通过将其他输入放在新屏幕上来解决此问题,但是当我在第一个屏幕上按Enter键时,它只是通过其余代码,而第二个输入则保持空白。

我该如何解决这个问题?

#Imports
import contextlib
with contextlib.redirect_stdout(None):
    import pygame
import pickle
import time
import random
import pygame_textinput.pygame_textinput as textinput

#Really messy, I know#

#Save Stuff
Choices = {}

def save(to_save, save_filepath):
    pickle.dump(to_save, open(save_filepath, "wb"))

def load(save_filepath):
    return pickle.load(open(save_filepath, "rb"))

#Initializations
pygame.init()

#Screen
scrWidth = 640
scrHeight = 480
screen = pygame.display.set_mode((scrWidth, scrHeight))
pygame.display.set_caption('Something')

#Images
startscreenbg = pygame.image.load('assets/Images/startscreen.jpg').convert()

#Text Input
real_nametxtinput = textinput.TextInput(text_color=(255,255,255))
char_nametxtinput = textinput.TextInput(text_color=(255,255,255))

#Clock
clock = pygame.time.Clock()

#Game Constants
next = False
real_name = ''
char_name = ''
real_name_done = False
char_name_done = False

##### Global Functions #####

#Buttons stuff
buttonTextFont = pygame.font.SysFont("comicsansms", 20)
def createButton(msg, msgcolor,x,y,width,height,color1,color2,action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    if x+width > mouse[0] > x and y+height > mouse[1] > y:
        pygame.draw.rect(screen, color2,(x,y,width,height))

        if click[0] == 1 and action != None:
            action()
    else:
        pygame.draw.rect(screen, color1,(x,y,width,height))

    buttontext = buttonTextFont.render(msg, 1, msgcolor)
    screen.blit(buttontext, (x + (width//2) - (buttontext.get_width()//2), (y + (height//2) - (buttontext.get_height()//2))))



##### Screens/Chapters #####
def update_next1():
    global next
    next = True

def start_screen():
    screen.blit(startscreenbg, (0, 0))
    new_game = createButton('New Game',(255,255,255), 80, 100, 200, 50, (0,180,0), (0,255,0), update_next1)
    load_game = createButton('Load Game', (255,255,255), 360, 100, 200, 50, (0,0,180), (0,0,255))

#Names
def real_name_screen():
    global real_name, real_name_done
    screen.blit(startscreenbg, (0,0))
    pygame.draw.rect(screen, (102, 255, 102), (150, 90, 200, 50))
    screen.blit(real_nametxtinput.get_surface(), (150,100))
    if real_nametxtinput.update(events):
        real_name = real_nametxtinput.get_text()
        real_name_done = True


def char_name_screen():
    global char_name, char_name_done
    screen.blit(startscreenbg, (0, 0))
    pygame.draw.rect(screen, (255, 102, 255), (150, 90, 200, 50))
    screen.blit(char_nametxtinput.get_surface(), (150, 100))
    if char_nametxtinput.update(events):
        char_name = char_nametxtinput.get_text()
        if char_name != '':
            char_name_done = True



run = True
while run:

    clock.tick(27)

    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            run = False

    if not next:
        start_screen()
    if next:
        real_name_screen()
        if real_name_done:
            char_name_screen()
            if char_name_done:
                #This is just so I could test it
                print(real_name, char_name)
                run = False



    pygame.display.update()

pygame.quit()
quit()

1 个答案:

答案 0 :(得分:0)

您需要一种方法来跟踪是否有一个文本输入窗口小部件处于活动状态,并且需要一种在所有窗口小部件之间切换的方法。

我整理了这个示例,根据需要进行调整(有很多可以改进的地方):

import os.path

import pygame
import pygame.locals as pl

pygame.font.init()

class WidgetManager:
    def __init__(self):
        self.widgets = []

    def update(self, events, dt):
        for e in events:
            if e.type == pygame.MOUSEBUTTONDOWN:
                for w in self.widgets:
                    w.active = False
                    if w.rect.collidepoint(e.pos):
                        w.active = True

        for w in self.widgets:
            w.update(events, dt)

    def draw(self, surface):
        for w in self.widgets:
            surface.blit(w.surface, w.rect)

class TextInput:
    """
    This class lets the user input a piece of text, e.g. a name or a message.
    This class let's the user input a short, one-lines piece of text at a blinking cursor
    that can be moved using the arrow-keys. Delete, home and end work as well.
    """
    def __init__(
            self,
            initial_string="",
            font_family="",
            font_size=35,
            antialias=True,
            active=False,
            text_color=(0, 0, 0),
            rect=pygame.Rect(0, 0, 10, 10),
            cursor_color=(0, 0, 1),
            repeat_keys_initial_ms=400,
            repeat_keys_interval_ms=35):
        """
        :param initial_string: Initial text to be displayed
        :param font_family: name or list of names for font (see pygame.font.match_font for precise format)
        :param font_size:  Size of font in pixels
        :param antialias: Determines if antialias is applied to font (uses more processing power)
        :param text_color: Color of text (duh)
        :param cursor_color: Color of cursor
        :param repeat_keys_initial_ms: Time in ms before keys are repeated when held
        :param repeat_keys_interval_ms: Interval between key press repetition when helpd
        """

        # Text related vars:
        self.antialias = antialias
        self.text_color = text_color
        self.font_size = font_size
        self.input_string = initial_string  # Inputted text
        self.active = active
        self.rect = rect

        if not os.path.isfile(font_family):
            font_family = pygame.font.match_font(font_family)

        self.font_object = pygame.font.Font(font_family, font_size)

        # Text-surface will be created during the first update call:
        self.surface = pygame.Surface((1, 1))
        self.surface.set_alpha(0)

        # Vars to make keydowns repeat after user pressed a key for some time:
        self.keyrepeat_counters = {}  # {event.key: (counter_int, event.unicode)} (look for "***")
        self.keyrepeat_intial_interval_ms = repeat_keys_initial_ms
        self.keyrepeat_interval_ms = repeat_keys_interval_ms

        # Things cursor:
        self.cursor_surface = pygame.Surface((int(self.font_size/20+1), self.font_size))
        self.cursor_surface.fill(cursor_color)
        self.cursor_position = len(initial_string)  # Inside text
        self.cursor_visible = True  # Switches every self.cursor_switch_ms ms
        self.cursor_switch_ms = 500  # /|\
        self.cursor_ms_counter = 0

    def update(self, events, dt):
        for event in events:
            if event.type == pygame.KEYDOWN and self.active:
                self.cursor_visible = True  # So the user sees where he writes

                # If none exist, create counter for that key:
                if event.key not in self.keyrepeat_counters:
                    self.keyrepeat_counters[event.key] = [0, event.unicode]

                if event.key == pl.K_BACKSPACE:
                    self.input_string = (
                        self.input_string[:max(self.cursor_position - 1, 0)]
                        + self.input_string[self.cursor_position:]
                    )

                    # Subtract one from cursor_pos, but do not go below zero:
                    self.cursor_position = max(self.cursor_position - 1, 0)
                elif event.key == pl.K_DELETE:
                    self.input_string = (
                        self.input_string[:self.cursor_position]
                        + self.input_string[self.cursor_position + 1:]
                    )

                elif event.key == pl.K_RETURN:
                    return True

                elif event.key == pl.K_RIGHT:
                    # Add one to cursor_pos, but do not exceed len(input_string)
                    self.cursor_position = min(self.cursor_position + 1, len(self.input_string))

                elif event.key == pl.K_LEFT:
                    # Subtract one from cursor_pos, but do not go below zero:
                    self.cursor_position = max(self.cursor_position - 1, 0)

                elif event.key == pl.K_END:
                    self.cursor_position = len(self.input_string)

                elif event.key == pl.K_HOME:
                    self.cursor_position = 0

                else:
                    # If no special key is pressed, add unicode of key to input_string
                    self.input_string = (
                        self.input_string[:self.cursor_position]
                        + event.unicode
                        + self.input_string[self.cursor_position:]
                    )
                    self.cursor_position += len(event.unicode)  # Some are empty, e.g. K_UP

            elif event.type == pl.KEYUP:
                # *** Because KEYUP doesn't include event.unicode, this dict is stored in such a weird way
                if event.key in self.keyrepeat_counters:
                    del self.keyrepeat_counters[event.key]

        # Update key counters:
        for key in self.keyrepeat_counters:
            self.keyrepeat_counters[key][0] += dt  # Update clock

            # Generate new key events if enough time has passed:
            if self.keyrepeat_counters[key][0] >= self.keyrepeat_intial_interval_ms:
                self.keyrepeat_counters[key][0] = (
                    self.keyrepeat_intial_interval_ms
                    - self.keyrepeat_interval_ms
                )

                event_key, event_unicode = key, self.keyrepeat_counters[key][1]
                pygame.event.post(pygame.event.Event(pl.KEYDOWN, key=event_key, unicode=event_unicode))

        # Re-render text surface:
        self.surface = pygame.Surface(self.rect.size)
        self.surface.blit(self.font_object.render(self.input_string, self.antialias, self.text_color), (0, 0))
        pygame.draw.rect(self.surface, self.text_color, (0, 0, *self.rect.size), 1)

        # Update self.cursor_visible
        self.cursor_ms_counter += dt
        if self.cursor_ms_counter >= self.cursor_switch_ms:
            self.cursor_ms_counter %= self.cursor_switch_ms
            self.cursor_visible = not self.cursor_visible

        if self.cursor_visible and self.active:
            cursor_y_pos = self.font_object.size(self.input_string[:self.cursor_position])[0]
            # Without this, the cursor is invisible when self.cursor_position > 0:
            if self.cursor_position > 0:
                cursor_y_pos -= self.cursor_surface.get_width()
            self.surface.blit(self.cursor_surface, (cursor_y_pos, 0))

        return False

    def get_surface(self):
        return self.surface

    def get_text(self):
        return self.input_string

    def get_cursor_position(self):
        return self.cursor_position

    def set_text_color(self, color):
        self.text_color = color

    def set_cursor_color(self, color):
        self.cursor_surface.fill(color)

    def clear_text(self):
        self.input_string = ""
        self.cursor_position = 0

def main():
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    manager = WidgetManager()
    manager.widgets.append(TextInput(text_color=pygame.Color('grey'), cursor_color=pygame.Color('grey'), rect=pygame.Rect(5, 5, 790, 35)))
    manager.widgets.append(TextInput(text_color=pygame.Color('orange'), cursor_color=pygame.Color('orange'), rect=pygame.Rect(5, 55, 790, 35), active=True))
    dt = 0
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        screen.fill((30, 30, 30))
        manager.draw(screen)
        manager.update(events, dt)
        dt = clock.tick()
        pygame.display.update()

if __name__ == '__main__':
    main()

您看到TextInput现在有一个active标志。如果未设置,则忽略键输入。另外,我们将TextInput的位置和大小存储在新属性rect中,因此新类WidgetManager可以通过用鼠标单击一个在小部件之间进行切换。

我还从Clock类中删除了TextInput,因为调用self.clock.tick()是主循环应该做的事情。

enter image description here

相关问题