Pygame includes a fairly rich collection of drawing objects and functions, making it easy to draw basic shapes, render text, display images, etc. The best way to learn the API is to start exploring it, look at examples on the web, and read the documentation, but the following sets of functions are probably the most useful if you're just getting started:
- pygame.draw (basic drawing primitives)
- pygame.font (text rendering)
- pygame.image (load and display .gifs, .jpgs, .pngs, etc.)
Drawing a Graticule
As an example, we'll use some basic drawing primitives to render something resembling a graticule on an oscilloscope. Add the following function to your pyscope class (with proper indentation to align with the rest of the class):def drawGraticule(self): "Renders an empty graticule" # The graticule is divided into 10 columns x 8 rows # Each cell is 50x40 pixels large, with 5 subdivisions per # cell, meaning 10x8 pixels each. Subdivision lines are # displayed on the central X and Y axis # Active area = 10,30 to 510,350 (500x320 pixels) borderColor = (255, 255, 255) lineColor = (64, 64, 64) subDividerColor = (128, 128, 128) # Outer border: 2 pixels wide pygame.draw.rect(self.screen, borderColor, (8,28,504,324), 2) # Horizontal lines (40 pixels apart) for i in range(0, 7): y = 70+i*40 pygame.draw.line(self.screen, lineColor, (10, y), (510, y)) # Vertical lines (50 pixels apart) for i in range(0, 9): x = 60+i*50 pygame.draw.line(self.screen, lineColor, (x, 30), (x, 350)) # Vertical sub-divisions (8 pixels apart) for i in range(1, 40): y = 30+i*8 pygame.draw.line(self.screen, subDividerColor, (258, y), (262, y)) # Horizontal sub-divisions (10 pixels apart) for i in range(1, 50): x = 10+i*10 pygame.draw.line(self.screen, subDividerColor, (x, 188), (x, 192))
This will draw a 500x320 pixel graticule, with an outer 2 pixel border, and divisions for 10 columns, and 8 rows. You can render the graticule with the following code at the bottom of your class:
# Create an instance of the PyScope class scope = pyscope() # Add the graticule scope.drawGraticule() # Update the display pygame.display.update() # Wait 10 seconds time.sleep(10)
That you give you something similar to the following (you may need to tweek the colors, etc., depending on the display you are using):
Adding Text
Adding text is relatively straight-forward using the pygame.font functions/objects. If you wish to load specific fonts (you can load fonts from files, etc.) you should consult the documentation, but as a basic example of using the default system font you simply need to entering something similar to the following code:# Create an instance of the PyScope class scope = pyscope() # Get a refernce to the system font, size 30 font = pygame.font.Font(None, 30) # Render some white text (pyScope 0.1) onto text_surface text_surface = font.render('pyScope (%s)' % "0.1", True, (255, 255, 255)) # White text # Blit the text at 10, 0 scope.screen.blit(text_surface, (10, 0)) # Update the display pygame.display.update() # Wait 10 seconds time.sleep(10)
Note: In order to use the font functions and objects, you need to call 'pygame.font.init()' somewhere in your code. This was already added to the init sequence of the class we created earlier, but it worth mentioning here.
Adding Images
It's just as easy to add images using the pygame.image functions/objects.To test this out, upload an image via the WebIDE using the 'Upload File' button on the left-hand menu, and upload the following image:
Select the appropriate image with the popup file dialogue ...
... and the image should show up in your file explorer with whatever name you gave it:
Now you simply need to reference the local file name with the following code:
# Create an instance of the PyScope class scope = pyscope() # Render the Adafruit logo at 10,360 logo = pygame.image.load('adafruit_logo.gif').convert() scope.screen.blit(logo, (10, 10)) pygame.display.update() # Wait 10 seconds time.sleep(10)
Wrapping it all Up + Animation
If you need to animate anything, the secret is simply to call 'pygame.display.update()' at the appropriate moment.An example using all of the above techniques can be seen in the following complete class that you can simply copy and paste into your pyscope.py file:
import os import pygame import time import random class pyscope: screen = None; def __init__(self): "Ininitializes a new pygame screen using the framebuffer" # Based on "Python GUI in Linux frame buffer" # http://www.karoltomala.com/blog/?p=679 # Allow running from ssh os.putenv("DISPLAY", ":0") disp_no = os.getenv("DISPLAY") if disp_no: print("I'm running under X display = {0}".format(disp_no)) # Check which frame buffer drivers are available # Start with fbcon since directfb hangs with composite output drivers = ['x11', 'fbcon', 'directfb', 'svgalib'] found = False for driver in drivers: # Make sure that SDL_VIDEODRIVER is set if not os.getenv('SDL_VIDEODRIVER'): os.putenv('SDL_VIDEODRIVER', driver) try: pygame.display.init() except pygame.error: print('Driver: {0} failed.'.format(driver)) continue found = True break if not found: raise Exception('No suitable video driver found!') size = (pygame.display.Info().current_w, pygame.display.Info().current_h) print("Framebuffer size: %d x %d" % (size[0], size[1])) self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN) # Clear the screen to start self.screen.fill((0, 0, 0)) # Initialise font support pygame.font.init() # Render the screen pygame.display.update() def __del__(self): "Destructor to make sure pygame shuts down, etc." def drawGraticule(self): "Renders an empty graticule" # The graticule is divided into 10 columns x 8 rows # Each cell is 50x40 pixels large, with 5 subdivisions per # cell, meaning 10x8 pixels each. Subdivision lines are # displayed on the central X and Y axis # Active area = 10,30 to 510,350 (500x320 pixels) borderColor = (255, 255, 255) lineColor = (64, 64, 64) subDividerColor = (128, 128, 128) # Outer border: 2 pixels wide pygame.draw.rect(self.screen, borderColor, (8,28,504,324), 2) # Horizontal lines (40 pixels apart) for i in range(0, 7): y = 70+i*40 pygame.draw.line(self.screen, lineColor, (10, y), (510, y)) # Vertical lines (50 pixels apart) for i in range(0, 9): x = 60+i*50 pygame.draw.line(self.screen, lineColor, (x, 30), (x, 350)) # Vertical sub-divisions (8 pixels apart) for i in range(1, 40): y = 30+i*8 pygame.draw.line(self.screen, subDividerColor, (258, y), (262, y)) # Horizontal sub-divisions (10 pixels apart) for i in range(1, 50): x = 10+i*10 pygame.draw.line(self.screen, subDividerColor, (x, 188), (x, 192)) def test(self): "Test method to make sure the display is configured correctly" adcColor = (255, 255, 0) # Yellow self.drawGraticule() # Render the Adafruit logo at 10,360 logo = pygame.image.load('adafruit_logo.gif').convert() self.screen.blit(logo, (10, 335)) # Get a font and use it render some text on a Surface. font = pygame.font.Font(None, 30) text_surface = font.render('pyScope (%s)' % "0.1", True, (255, 255, 255)) # White text # Blit the text at 10, 0 self.screen.blit(text_surface, (10, 0)) # Render some text with a background color text_surface = font.render('Channel 0', True, (0, 0, 0), (255, 255, 0)) # Black text with yellow BG # Blit the text self.screen.blit(text_surface, (540, 30)) # Update the display pygame.display.update() # Random adc data yLast = 260 for x in range(10, 509): y = random.randrange(30, 350, 2) # Even number from 30 to 350 pygame.draw.line(self.screen, adcColor, (x, yLast), (x+1, y)) yLast = y pygame.display.update() # Create an instance of the PyScope class scope = pyscope() scope.test() # Wait 10 seconds time.sleep(10)
This should give you something similar to the following (depending on your display):
Page last edited April 09, 2024
Text editor powered by tinymce.