Python/Pygame 在离开窗口时使 Pygame 中的文本换行

问题描述 投票:0回答:3

我有一个渲染文本的文本函数。该函数如下

def textFunc(font,msg,color,x,y,center):
    text_render = font.render(msg,True,color)
    text_rect = text_render.get_rect()
    
    #If center is true, then the X,Y will be used as the center
    if center == True:
        text_rect.center = (x,y)
    else:
        text_rect = (x,y)
    game_display.blit(text_render,text_rect)

但是我的消息字符串太长,它会呈现在窗口之外。

有没有办法让我的文本注册对于我的窗口来说太长,因此在文本开头下方继续?与计算机如何自动完成类似

有点像这样:Text

python text pygame word-wrap
3个回答
1
投票

没有自动解决方案。你必须自己实现文本换行并逐行逐字绘制文本。
幸运的是 PyGame wiki 提供了一个用于此任务的函数。请参阅 PyGame wiki pygame 的简单文本换行

我扩展了该函数并添加了一个附加参数,它提供了 leftright 对齐文本、centered 文本甚至 block 模式:

textAlignLeft = 0
textAlignRight = 1
textAlignCenter = 2
textAlignBlock = 3

def drawText(surface, text, color, rect, font, align=textAlignLeft, aa=False, bkg=None):
    lineSpacing = -2
    spaceWidth, fontHeight = font.size(" ")[0], font.size("Tg")[1]

    listOfWords = text.split(" ")
    if bkg:
        imageList = [font.render(word, 1, color, bkg) for word in listOfWords]
        for image in imageList: image.set_colorkey(bkg)
    else:
        imageList = [font.render(word, aa, color) for word in listOfWords]

    maxLen = rect[2]
    lineLenList = [0]
    lineList = [[]]
    for image in imageList:
        width = image.get_width()
        lineLen = lineLenList[-1] + len(lineList[-1]) * spaceWidth + width
        if len(lineList[-1]) == 0 or lineLen <= maxLen:
            lineLenList[-1] += width
            lineList[-1].append(image)
        else:
            lineLenList.append(width)
            lineList.append([image])

    lineBottom = rect[1]
    lastLine = 0
    for lineLen, lineImages in zip(lineLenList, lineList):
        lineLeft = rect[0]
        if align == textAlignRight:
            lineLeft += + rect[2] - lineLen - spaceWidth * (len(lineImages)-1)
        elif align == textAlignCenter:
            lineLeft += (rect[2] - lineLen - spaceWidth * (len(lineImages)-1)) // 2
        elif align == textAlignBlock and len(lineImages) > 1:
            spaceWidth = (rect[2] - lineLen) // (len(lineImages)-1)
        if lineBottom + fontHeight > rect[1] + rect[3]:
            break
        lastLine += 1
        for i, image in enumerate(lineImages):
            x, y = lineLeft + i*spaceWidth, lineBottom
            surface.blit(image, (round(x), y))
            lineLeft += image.get_width() 
        lineBottom += fontHeight + lineSpacing

    if lastLine < len(lineList):
        drawWords = sum([len(lineList[i]) for i in range(lastLine)])
        remainingText = ""
        for text in listOfWords[drawWords:]: remainingText += text + " "
        return remainingText
    return ""

最小示例: repl.it/@Rabbid76/PyGame-TextWrap

import pygame

pygame.init()
font = pygame.font.SysFont(None, 40)

msg = "Simple function that will draw text and wrap it to fit the rect passed.  If there is any text that will not fit into the box, the remaining text will be returned."
textRect = pygame.Rect(100, 100, 300, 300)

window = pygame.display.set_mode((500, 500))
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill((255, 255, 255))
    pygame.draw.rect(window, (0, 0, 0), textRect, 1)
    drawTextRect = textRect.inflate(-5, -5)
    drawText(window, msg, (0, 0, 0), drawTextRect, font, textAlignBlock, True)
    pygame.display.flip()

0
投票

pygame-ce
pygame
的现代分支)版本
2.1.4
开始,
pygame.Font.render
现在具有换行符(
"\n"
)和wraplength(换行到新行之前的像素宽度)支持。

因此,您只需将想要的文本传递给

pygame.Font.render
并将窗口宽度指定为最后一个参数,以便一旦文本达到窗口宽度,它就会换行。由于此方法尚不接受关键字参数,因此您还必须提供背景颜色参数,它可以是
None
,或者您可以提供 alpha 值为 0 的颜色值。

这是一个简短的代码示例:

import pygame


WIDTH, HEIGHT = 640, 360
FPS = 60

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

font = pygame.Font(None, 32)
text_surf = font.render(
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
    "In feugiat imperdiet velit, et dictum arcu malesuada in.",
    True,
    "black",
    None,  # or (0, 0, 0, 0) for example
    WIDTH,
)

running = True
while running:
    clock.tick(FPS)
    screen.fill("white")

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

    screen.blit(text_surf, (0, 0))

    pygame.display.flip()

结果:

此外,要安装最新版本的

pygame-ce
,只需按照以下步骤操作:

  1. pip uninstall pygame
    (为了避免冲突,只有当您已经安装了
    pygame
    时才必须这样做)
  2. pip install pygame-ce
  3. 享受新的闪亮功能

有关分叉的更多信息可以在这里找到:Pygame:社区版公告 您还可以加入 pygame(-ce) 的官方 Discord 服务器:https://discord.gg/pygame


0
投票

我不喜欢把非常简单的事情变得非常复杂,就像我发现的每一个解决方案一样。最好的解决方案在文档中,顺便说一句,文档中说

pygame.freetype
模块是
pygame.font
的替代品。

import pygame.freetype as ft

def render_text(surface, text, size, color):
    font = ft.SysFont('consolas', size)
    words = text.split(' ')
    w, h = surface.get_size()
    line_spacing = font.get_sized_height() + 2
    x, y = 0, line_spacing
    space = font.get_rect(' ')

    for word in words:
        bounds = font.get_rect(word)
        if x + bounds.width + bounds.x >= w:
            x, y = 0, y + line_spacing
        font.render_to(surface, (x, y - bounds.y), None, color)
        x += bounds.width + space.width

就是这样。例如:

import pygame as pg

ORANGE = (253, 156, 0)

surface = pg.Surface((400, 200))
render_text(surface, ("This is a test -.,\` 09 ") * 1000, 14, ORANGE)

通过导入

pygame.freetype
pg.init()
将负责初始化,否则你也需要初始化ft,所以只需导入它即可。您可能还想知道当 text = None 时文本是如何呈现的。那是因为我们重新渲染了传递给
bounds = self.font.get_rect(word)

的文本
© www.soinside.com 2019 - 2024. All rights reserved.