Having successfully hooked my small TFT up to the Raspberry Pi, I now wanted to use it! As it was a touch screen version what I wanted was buttons.
This is the end result;
The code is to be found in this gist:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
import pygame # Needs this to get the event types from pygame.locals import * import os import logging from time import sleep log_format = '%(asctime)-6s: %(name)s - %(levelname)s - %(message)s' console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter(log_format)) logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(console_handler) #Colours red = (255,0,0) green = (0,255,0) blue = (0,0,255) black = (0,0,0) display_width = 320 display_height = 240 # Assume all buttons of equal size (allow for a 5mm border all round to be added button_dim = (0,0,120,80) # define the centres for the buttons rather than top left button_ctrs =[(85,65),(85,175),(235,65),(235,175)] # I'm going to save the state of each button button_state = [False , False, False, False] # functions from https://pythonprogramming.net/displaying-text-pygame-screen/ # create a text object def text_objects(text, font): textSurface = font.render(text, True, black) return textSurface, textSurface.get_rect() # display text def message_display(text,button): largeText = pygame.font.Font('freesansbold.ttf',75) TextSurf, TextRect = text_objects(text, largeText) TextRect.center = (button_ctrs[button]) lcd.blit(TextSurf, TextRect) # work out which quarter of the screen was pressed def which_button (): pos = pygame.mouse.get_pos() #Find which quarter of the screen we're in x,y = pos button = 5 if x < 160: if y < 120: button = 0 else: button = 1 else: if y < 120: button = 2 else: button = 3 return button ######################### # Start doing things ######################### # setup LCD screen os.putenv('SDL_FBDEV', '/dev/fb1') os.putenv('SDL_MOUSEDRV', 'TSLIB') os.putenv('SDL_MOUSEDEV', '/dev/input/by-path/platform-20204000.spi-event') #os.putenv('SDL_MOUSEDEV', '/dev/input/event0') pygame.init() pygame.mouse.set_visible(False) # create a screen lcd = pygame.display.set_mode((display_width, display_height)) # set up the initial screen # Add a background lcd.fill(red) # build the array of rects with centers defined buttons = [] for button in range (0,4): buttons.append(pygame.Rect(button_dim)) buttons[button].center = button_ctrs[button] #draw the buttons with a border for button in buttons: # make the border by drawing a bigger rect first pygame.draw.rect(lcd, black, button.inflate(5,5), 0) pygame.draw.rect(lcd, blue, button, 0) message_display("off",buttons.index(button)) # update the whole screen as the borders are outside of the rects defined # so if we just updated those, the borders do not show. pygame.display.flip() # enclose loop in a try - catch to give a clean exit try: print ("Press CTRL+C to exit") while True: # Scan touchscreen events for event in pygame.event.get(): # Just use a button down event. if(event.type is MOUSEBUTTONDOWN): # which button was pressed but_pressed = which_button() # update the buttons state button_state[but_pressed] = not button_state[but_pressed] # update the display based on the state if button_state[but_pressed]: pygame.draw.rect(lcd, green, buttons[but_pressed], 0) message_display("on",but_pressed) else: pygame.draw.rect(lcd, blue, buttons[but_pressed], 0) message_display("off",but_pressed) # just update the pressed button rect pygame.display.update(buttons[but_pressed]) # put a sleep here to de-bounce sleep(0.2) # clear the queue of events that may have happened while we were sleeping pygame.event.clear() except KeyboardInterrupt: # graceful exit (running interactively) print ("Goodbye.") |
A few comments on the false starts and things I learned (code is well commented I think):
- I tried to install pygameUI but this failed because of the way I had implemented the TFT itself.
- pygame is structured in a way I was unfamiliar with (fairly new to python). Key concepts are:
- The screen (the area you update)
- Rect – an object that defines a rectangular area of the screen. I created an array of Rect objects then gave each a centre. Once defined they will always display at that location unless you change it.
- You output various layers then update the display.
- Updating the display is best done on the rects that have changed although in this case, frame rate is not an issue.
- I used centres as I found that trying to create a border using a top left reference did not result in a constant thickness of the border all round.
I now need to find a way to mount the TFT permanently. I also really would like an enclosure – I’m going to hunt down a 3D one or pay a visit to my local hacklab.
I also need to expand my code to pull instructions off and send instructions to the main IOT server I have to control the heating.
HTH
by