Pygame--解决中文问题(三)

本文介绍如何在Pygame中使用输入法并控制键盘输入,通过`SDL_IME_SHOW_UI`环境变量显示输入法,以及利用`pygame.key`函数处理文本输入事件,包括文本框的绘制和鼠标交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用输入法进行输入

在代码内加入os.environ["SDL_IME_SHOW_UI"] = "1"使用输入法,调用pygame.key.start_text_input()可以控制是否接收键盘输入事件,与之对应的为pygame.key.stop_text_input(),pygame.key.set_text_input_rect(rect: RectValue)这个函数为渲染输入文字的位置。

代码示例:

from rectangle import rectangle
from border import border
import pygame
import os


def find_closest_number(num, lst):
    if len(lst):
        closest_num = lst[0]  # 将第一个数字设为初始的最接近数字

        for n in lst:
            if abs(num - n) < abs(num - closest_num):
                closest_num = n

        return closest_num
    return -1


class textinput:
    os.environ["SDL_IME_SHOW_UI"] = "1"

    def __init__(self, screen, width, height, x, y, font=None):
        self.screen = screen
        self.text = ""
        self.buf_text = ""
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.rect = rectangle(screen, width + 5, height, x, y, background_color=(255, 255, 255),
                              rect_border=border(1, (0, 0, 0)))
        self.font = font if font is not None else pygame.font.SysFont("simhei", 20)
        self.active = False
        point = self.rect.get_coordinate()
        pygame.key.set_text_input_rect((point.left, point.top + 10, point.width, point.height))
        pygame.key.stop_text_input()
        self.cursor = -1

    def draw(self):
        self.rect.draw()
        if self.active:
            font_range = self.font.size(self.text)
            if font_range[0] <= self.width:
                rect = self.rect.get_coordinate()
                self.buf_text = self.text
                self.screen.blit(self.font.render(self.text, True, (0, 0, 0)),
                                 (rect.x, rect.y + (self.height / 2 - self.font.get_height() / 2)))
            else:
                res = 0
                while True:
                    if self.font.size(self.text[res::])[0] <= self.width:
                        rect = self.rect.get_coordinate()
                        self.buf_text = self.text[res::]
                        self.screen.blit(self.font.render(self.text[res::], True, (0, 0, 0)),
                                         (rect.x, rect.y + (self.height / 2 - self.font.get_height() / 2)))
                        break
                    res += 1
            if self.cursor == -1:
                font_size = self.font.size(self.text)
                y_start = self.y + 3
                y_end = self.y + self.height - 3
                if font_size[0] <= self.width:
                    x = self.x + font_size[0] + 2
                    pygame.draw.line(self.screen, (0, 0, 0), (x, y_start), (x, y_end))
                else:
                    x = self.width + 2 + self.x
                    pygame.draw.line(self.screen, (0, 0, 0), (x, y_start), (x, y_end))
            else:
                y_start = self.y + 3
                y_end = self.y + self.height - 3
                x = self.font.size(self.buf_text[0:self.cursor])[0] + self.x
                pygame.draw.line(self.screen, (0, 0, 0), (x, y_start), (x, y_end))
        else:
            font_range = self.font.size(self.text)
            if font_range[0] <= self.width:
                rect = self.rect.get_coordinate()
                self.buf_text = self.text
                self.screen.blit(self.font.render(self.text, True, (0, 0, 0)),
                                 (rect.x, rect.y + (self.height / 2 - self.font.get_height() / 2)))
            else:
                res = 0
                while True:
                    if self.font.size(self.text[res::])[0] <= self.width:
                        rect = self.rect.get_coordinate()
                        self.buf_text = self.text[res::]
                        self.screen.blit(self.font.render(self.text[res::], True, (0, 0, 0)),
                                         (rect.x, rect.y + (self.height / 2 - self.font.get_height() / 2)))
                        break
                    res += 1

    def handel(self, event):
        self.rect.handel(event)
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                if self.rect.is_clicked(pygame.mouse.get_pos()):
                    self.active = True
                    pygame.key.start_text_input()
                    self.rect.border.color = self.rect.click_border_color
                    point = pygame.mouse.get_pos()
                    x_point = point[0] - self.x
                    x = [self.font.size(self.buf_text[:x])[0] for x in range(len(self.buf_text))]
                    n = find_closest_number(x_point, x)
                    try:
                        if x_point > max(x):
                            self.cursor = -1
                        else:
                            self.cursor = x.index(n)
                    except ValueError:
                        self.cursor = -1
                else:
                    self.active = False
                    self.rect.border.color = (0, 0, 0)
        if self.active:
            if event.type == pygame.TEXTINPUT:
                if self.cursor == -1:
                    self.text += event.text
                    point = self.rect.get_coordinate()
                    pygame.key.set_text_input_rect((point.left, point.top + 10, point.width, point.height))
                else:
                    self.text = self.text[0:self.cursor] + event.text + self.text[self.cursor:]
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_BACKSPACE:  # 退格键
                    if self.cursor == -1:
                        self.text = self.text[:-1]
                    elif self.cursor == 0:
                        return
                    else:
                        self.text = self.text[:self.cursor-1] + self.text[self.cursor:]
                        self.cursor -= 1

    def get_text(self):
        return self.text

if __name__ == '__main__':
    pygame.init()
    width = 800
    height = 600
    screen = pygame.display.set_mode((width, height))
    running = True
    inp = textinput(screen, 200, 30, 20, 100)
    inp2 = textinput(screen, 200, 30, 20, 200)
    while running:
        screen.fill((0, 0, 0))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            inp.handel(event)
            inp2.handel(event)

        screen.fill((255, 255, 255))
        inp.draw()
        inp2.draw()
        pygame.display.flip()

rectangle类代码

import pygame
from border import border


class rectangle:
    def __init__(self, screen, width, height, x, y, background_color=None, rect_border=None, fix=False,
                 click_background_color=(255, 255, 255), click_border_color=(64, 160, 255)):
        self.width = width
        self.height = height
        self.screen = screen
        self.window_width = screen.get_width()
        self.window_height = screen.get_height()
        self.x = x
        self.y = y
        self.background_color = background_color if background_color is not None else (255, 255, 255)
        self.click_background_color = click_background_color
        self.click_border_color = click_border_color
        self.background = self.background_color
        self.border = rect_border if rect_border is not None else border(1, self.background_color)
        self.selected = False
        self.offset = False
        self.fix = fix

    def draw(self):
        pygame.draw.rect(self.screen, self.border.color, (self.x, self.y, self.width, self.height))
        pygame.draw.rect(self.screen, self.background,
                         (self.x+self.border.thickness, self.y+self.border.thickness,
                          self.width-(self.border.thickness*2), self.height-(self.border.thickness*2)))

    def get_coordinate(self):
        return pygame.Rect(self.x, self.y, self.width, self.height)

    def set_coordinate(self, x, y):
        self.x = x
        self.y = y
        if x <= 0:
            self.x = 0
        if x >= self.window_width-self.width:
            self.x = self.window_width-self.width
        if y <= 0:
            self.y = 0
        if y >= self.window_height-self.height:
            self.y = self.window_height-self.height

    def is_clicked(self, mouse_pos):
        are = self.get_coordinate()
        if are.collidepoint(mouse_pos):
            return True
        else:
            return False

    def handel(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1 and self.is_clicked(pygame.mouse.get_pos()):
                self.selected = True
                self.background = self.click_background_color
                self.border.color = self.click_border_color
                if self.fix:
                    point = pygame.mouse.get_pos()
                    self.offset = (point[0]-self.x, point[1]-self.y)

        if event.type == pygame.MOUSEMOTION:
            if self.selected and self.fix:
                point = pygame.mouse.get_pos()
                self.set_coordinate(point[0]-self.offset[0], point[1]-self.offset[1])

        if event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                self.selected = False
                self.background = self.background_color


if __name__ == '__main__':
    pygame.init()
    width = 800
    height = 600
    screen = pygame.display.set_mode((width, height))
    running = True
    rect = rectangle(screen, 100, 100, 0, 0, fix=True, rect_border=border(1, (0, 255, 0)),background_color=(255, 255, 255))
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            rect.handel(event)

        screen.fill((255,255,255))
        rect.draw()
        pygame.display.flip()

border类代码

class border:
    def __init__(self, thickness=1, color=(0, 0, 0)):
        self.thickness = thickness
        self.color = color

pygame版本 pygame 2.5.1 (SDL 2.28.2, Python 3.6.6)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值