Simple way to display text on screen in Python?

2019-02-20 06:11发布

问题:

I've been googling and looking through StackOverflow but no luck...

What I would like is to display text to the screen (not console) for an art project I am developing. The string will be displayed in a full screen--edge to edge "window" with no menubar, etc. The string will update rapidly (imagine a string of random letters displaying and redrawing as fast as the computer will allow). Choice of font and color (on a letter-by-letter basis) would be great bonuses.

The string will be centered on the screen (not scrolling).

I'm new-ish to programming. Displaying text to the screen seems much more involved than I expected. :)

I've come across solutions using pygame but the sample code doesn't work. Here's a typical example:

https://www.daniweb.com/programming/software-development/code/244474/pygame-text-python

What I see on my Mac is a window opening with no text, with the code continuing to run, indefinitely. Similar experiences with other code and other libraries I've encountered.

Is pygame my best choice (ease of programming in Python, high speed) for my needs or are there other libraries better suited to what I am after?

If pygame is the right direction can anyone suggest sample code that will get me going?

Thanks,

--Darin

回答1:

Here's a pygame solution. Just pass the random letters and color to Font.render and then blit the returned surface. To center it I call the get_rect method of the txt surface and pass the center of the screen_rect as the center argument. Note that you can't choose a different color for each letter. To do that you would probably have to render several "one letter" surfaces and then combine them.

Epilepsy warning - The text was getting changed really quickly (each frame (30 fps)) and I wasn't sure if that could cause epileptic seizures, so I added a timer to update the text only every 10 frames. Be careful if you want to increase the update speed.

import sys
from random import choice, randrange
from string import ascii_letters

import pygame as pg


def random_letters(n):
    """Pick n random letters."""
    return ''.join(choice(ascii_letters) for _ in range(n))


def main():
    info = pg.display.Info()
    screen = pg.display.set_mode((info.current_w, info.current_h), pg.FULLSCREEN)
    screen_rect = screen.get_rect()
    font = pg.font.Font(None, 45)
    clock = pg.time.Clock()
    color = (randrange(256), randrange(256), randrange(256))
    txt = font.render(random_letters(randrange(5, 21)), True, color)
    timer = 10
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    done = True

        timer -= 1
        # Update the text surface and color every 10 frames.
        if timer <= 0:
            timer = 10
            color = (randrange(256), randrange(256), randrange(256))
            txt = font.render(random_letters(randrange(5, 21)), True, color)

        screen.fill((30, 30, 30))
        screen.blit(txt, txt.get_rect(center=screen_rect.center))

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()


回答2:

You can easily do this sort of thing with Tkinter, which is included in most modern Python installations. Eg,

import tkinter as tk
from random import seed, choice
from string import ascii_letters

seed(42)

colors = ('red', 'yellow', 'green', 'cyan', 'blue', 'magenta')
def do_stuff():
    s = ''.join([choice(ascii_letters) for i in range(10)])
    color = choice(colors)
    l.config(text=s, fg=color)
    root.after(100, do_stuff)

root = tk.Tk()
root.wm_overrideredirect(True)
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))
root.bind("<Button-1>", lambda evt: root.destroy())

l = tk.Label(text='', font=("Helvetica", 60))
l.pack(expand=True)

do_stuff()
root.mainloop()

Click with the left mouse button to exit.

This is just a proof of concept. To control color &/or font on a letter-by-letter basis you'll need to do something a little more complicated. You could use a row of Label widgets (one for each letter), or you could use a Text widget.


However, if you try this on a Mac, the window may not receive focus, as mentioned here. The answers here show an alternative way to get a fullscreen window, but I suspect it could suffer from the same defect.

root.attributes("-fullscreen", True)

One advantage of this approach is that it doesn't require the root.geometry call.