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
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()
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.