首页 > 解决方案 > 将文本添加到可以调整大小的矩形,并在 Pygame 上移动而无需插件

问题描述

我想将文本粘贴到一个可以移动和重新调整其大小的矩形上。我正在考虑使矩形成为表面并只是在表面上粘贴文本,但我不知道该怎么做:(

可以移动并可以调整大小的矩形是:

import pygame as pg

pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect1 = pg.Rect(100, 100, 161, 100)
rect2 = pg.Rect(300, 200, 161, 100)
selected_rect = None

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        elif event.type == pg.MOUSEBUTTONDOWN:
            for rect in (rect1, rect2):
                if rect.collidepoint(event.pos):
                    selected_rect = rect  # Select the colliding rect.
        elif event.type == pg.MOUSEBUTTONUP:
            selected_rect = None  # De-select the rect.
        elif event.type == pg.MOUSEMOTION:
            if selected_rect is not None:  # If a rect is selected.
                if event.buttons[0]:  # Left mouse button is down.
                    # Move the rect.
                    selected_rect.x += event.rel[0]
                    selected_rect.y += event.rel[1]
                else:  # Right or middle mouse button.
                    # Scale the rect.
                    selected_rect.w += event.rel[0]
                    selected_rect.h += event.rel[1]
                    selected_rect.w = max(selected_rect.w, 10)
                    selected_rect.h = max(selected_rect.h, 10)

    screen.fill((30, 30, 30))
    pg.draw.rect(screen, (0, 100, 250), rect1)
    pg.draw.rect(screen, (0, 200, 120), rect2)
    pg.display.flip()
    clock.tick(30)

另外,如果可能的话,任何人都可以帮助我处理矩形,他们似乎能够从屏幕上移开,如何使屏幕大小成为边框并使矩形从它上面反弹?

标签: pythonpython-3.xpygame

解决方案


这是一个基本的解决方案。我首先将文本拆分为单独的单词。然后,为了创建这些行,我将一个单词一个接一个地添加到中间列表 ( line) 中,并使用该pygame.font.Font.size方法获取添加到line_width变量中的单词的大小。当line_width超过矩形宽度时,我使用行列表中的单词来呈现文本表面并将其附加到self.images列表中。

为了对文本表面进行 blit,我枚举了self.images,然后将索引乘以字体的高度来移动表面。

import pygame as pg


class TextBox:

    def __init__(self, text, pos, font, bg_color, text_color=(255, 255, 255)):
        self.font = font
        self.font_height = font.get_linesize()
        self.text = text.split()  # Single words.
        self.rect = pg.Rect(pos, (200, 200))
        self.bg_color = bg_color
        self.text_color = text_color
        self.render_text_surfaces()

    def render_text_surfaces(self):
        """Create a new text images list when the rect gets scaled."""
        self.images = []  # The text surfaces.
        line_width = 0
        line = []
        space_width = self.font.size(' ')[0]

        # Put the words one after the other into a list if they still
        # fit on the same line, otherwise render the line and append
        # the resulting surface to the self.images list.
        for word in self.text:
            line_width += self.font.size(word)[0] + space_width
            # Render a line if the line width is greater than the rect width.
            if line_width > self.rect.w:
                surf = self.font.render(' '.join(line), True, self.text_color)
                self.images.append(surf)
                line = []
                line_width = self.font.size(word)[0] + space_width

            line.append(word)

        # Need to render the last line as well.
        surf = self.font.render(' '.join(line), True, self.text_color)
        self.images.append(surf)

    def draw(self, screen):
        """Draw the rect and the separate text images."""
        pg.draw.rect(screen, self.bg_color, self.rect)

        for y, surf in enumerate(self.images):
            # Don't blit below the rect area.
            if y * self.font_height + self.font_height > self.rect.h:
                break
            screen.blit(surf, (self.rect.x, self.rect.y+y*self.font_height))

    def scale(self, rel):
        self.rect.w += rel[0]
        self.rect.h += rel[1]
        self.rect.w = max(self.rect.w, 30)  # 30 px is the minimum width.
        self.rect.h = max(self.rect.h, 30)
        self.render_text_surfaces()

    def move(self, rel):
        self.rect.move_ip(rel)
        self.rect.clamp_ip(screen.get_rect())


text = """Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum."""
pg.init()
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
FONT = pg.font.Font(None, 34)
selected_box = None
textbox = TextBox(text, (50, 50), FONT, (20, 50, 120))
textbox2 = TextBox(text, (350, 100), pg.font.Font(None, 22), (20, 80, 60))

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        elif event.type == pg.MOUSEBUTTONDOWN:
            for box in (textbox, textbox2):
                if box.rect.collidepoint(event.pos):
                    selected_box = box  # Select the colliding box.
        elif event.type == pg.MOUSEBUTTONUP:
            selected_box = None  # De-select the box.
        elif event.type == pg.MOUSEMOTION:
            if selected_box is not None:  # If a box is selected.
                if event.buttons[0]:  # Left mouse button is down.
                    selected_box.move(event.rel)
                else:
                    selected_box.scale(event.rel)

    screen.fill((30, 30, 30))
    textbox.draw(screen)
    textbox2.draw(screen)
    pg.display.flip()
    clock.tick(60)

还有一些地方需要改进,但我把它留给你。例如:

  • 比矩形宽度宽的单词会突出。
  • 段落被忽略。
  • 我只是省略了矩形下方的行。
  • 如果您想更改文本,您应该添加一个 getter 和一个 setter 方法或属性,您可以在其中调用该render_text_surfaces方法来更新表面。

推荐阅读