python - 将文本添加到可以调整大小的矩形,并在 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)
另外,如果可能的话,任何人都可以帮助我处理矩形,他们似乎能够从屏幕上移开,如何使屏幕大小成为边框并使矩形从它上面反弹?
解决方案
这是一个基本的解决方案。我首先将文本拆分为单独的单词。然后,为了创建这些行,我将一个单词一个接一个地添加到中间列表 ( 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
方法来更新表面。
推荐阅读
- google-apps-script - 谷歌表格两个 onEdits,第二个 onEdit 与第一个冲突
- spring-boot - 如何在topredacte方法中使用jpa中的两个连接
- python - 蟒蛇。有什么方法可以获取文件对话框?
- c# - 重写规则不适用于从 http 到 https 的重定向
- java - 如何在 log4j2.xml 中动态设置日志文件路径
- jenkins - Jenkins Pipeline 中的 StreamingTemplateEngine 与普通 groovy 中的 StreamingTemplateEngine
- yii2 - Yii2:覆盖第 3 方邮件视图
- haskell - Haskell - 查找节点值的路径
- javascript - 启用/禁用动态引导工具提示
- docker - 带有网络核心的 Docker Healcheck