Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Centre text string on TFTFeatherwing
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Centre text string on TFTFeatherwing

by wildestpixel on Sun Aug 02, 2020 9:55 am

HI there,

Been trying to get around this, but not as easy as with Raspberry Pi code (even though still using circuitpython)

I have a lovely Pi clock which is at https://github.com/wildestpixel/DPS310_ ... ITAL-Clock ; it simply centres text doing the following :

Code: Select all | TOGGLE FULL SIZE
(font_width, font_height) = font3.getsize(strDate)
draw.text((width//2 - font_width//2, top + 0), strDate, font=font3, fill=255)


However over on Circuitpython with a Bluefruit Sense, DS3231 RTC and a 2.4" TFT Featherwing, my code as follows :

Code: Select all | TOGGLE FULL SIZE
import board
import time
import busio
import adafruit_bmp280
import displayio
import terminalio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import adafruit_ili9341
import adafruit_sht31d
import adafruit_ds3231

# Release any resources currently in use for the displays
displayio.release_displays()

spi = board.SPI()
tft_cs = board.D9
tft_dc = board.D10

display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D6)
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240, rotation=0)



# Create library object using our Bus I2C port
i2c = board.I2C()
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)
sht31d = adafruit_sht31d.SHT31D(i2c)
rtc = adafruit_ds3231.DS3231(i2c)

# Change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

# Lookup table for names of days (nicer printing).
t = rtc.datetime
days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")


# pylint: disable-msg=bad-whitespace
# pylint: disable-msg=using-constant-test
if False:  # change to True if you want to set the time!
    #                     year, mon, date, hour, min, sec, wday, yday, isdst
    t = time.struct_time((2020, 08, 02, 07, 26, 0, 0, -1, -1))
    # you must set year, mon, date, hour, min, sec and weekday
    # yearday is not supported, isdst can be set but we don't do anything with it at this time
    print("Setting time to:", t)  # uncomment for debugging
    rtc.datetime = t
    print()

font = bitmap_font.load_font("/helvB24.bdf")

text_group = displayio.Group(max_size=100)

# Create the text labels
text_area = label.Label(font, text="Temperature: %0.1f C" % bmp280.temperature, color=0xFF0000)
text_area1 = label.Label(font, text="Humidity: %0.1f %%" % sht31d.relative_humidity, color=0xF0FF00)
text_area2 = label.Label(font, text="Pressure: %0.1f hPa" % bmp280.pressure, color=0x00FF00)
text_area3 = label.Label(font, text="Alt: %0.2f meters" % bmp280.altitude, color =0x0036FF)
text_area4 = label.Label(font, text="{:02}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec), color =0xFFFFFF)
text_area5 = label.Label(font, text="{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year), color =0xFFFFFF)

# Set the locations
text_area.x = 0
text_area.y = 70
text_area1.x = 0
text_area1.y = 100
text_area2.x = 0
text_area2.y = 130
text_area3.x = 0
text_area3.y = 160
text_area4.x = 0
text_area4.y = 40
text_area5.x = 0
text_area5.y = 10

# append the labels to a group
text_group.append(text_area)
text_group.append(text_area1)
text_group.append(text_area2)
text_group.append(text_area3)
text_group.append(text_area4)
text_group.append(text_area5)
display.show(text_group)

while True:
    text_area.text = "Temperature: %0.1f C" % (bmp280.temperature - 6.3)
    text_area1.text = "Humidity: %0.1f %%" % sht31d.relative_humidity
    text_area2.text ="Pressure: %0.1f hPa" % bmp280.pressure
    text_area3.text = "Alt: %0.2f meters" % bmp280.altitude
    text_area4.text = "{:02}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec)
    text_area5.text = "{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year)
    t = rtc.datetime
    time.sleep(0.5)
    pass


What I want to achieve is to centre the text in text_area5 ; namely the day and date.

Would anyone be able to help ?

Many thanks in advance,

wildestpixel
 
Posts: 47
Joined: Wed Oct 23, 2019 1:14 am

Re: Centre text string on TFTFeatherwing

by kevinjwalters on Mon Aug 03, 2020 8:12 am

I haven't tested this so it might need some minor syntax corrections but the approach is the same, use the width of the screen, calculate the size of the text based on the font and set the x value making sure it's an integer value.

Code: Select all | TOGGLE FULL SIZE
font_width, font_height = font.get_bounding_box()
display_width, display_height = display.width, display.height

while True:
...
    text_area5.text = "{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year)
    text_area5.x = (display_width - (len(text_area5.text) * font_width)) // 2
...


Thinking about it there is a minor flaw here if the font is proportionally spaced. That type of font needs a method to calculate width based on the actual string of characters rather just the length due to i being narrower than m, for example.

kevinjwalters
 
Posts: 745
Joined: Sun Oct 01, 2017 3:15 pm

Re: Centre text string on TFTFeatherwing

by wildestpixel on Mon Aug 03, 2020 2:45 pm

The output in REPL as follows :

Code: Select all | TOGGLE FULL SIZE
code.py output:
Traceback (most recent call last):
  File "code.py", line 92, in <module>
ValueError: too many values to unpack (expected 2)


from the line :
Code: Select all | TOGGLE FULL SIZE
font_width, font_height = font.get_bounding_box()


When using the bdf fonts, however this runs fine using terminalio.FONT.

So needs to be a different solution for the proportional font to get the length or more like width all together. I see your other post on the subject - I will watch that closely.

Many thanks Kevin

wildestpixel
 
Posts: 47
Joined: Wed Oct 23, 2019 1:14 am

Re: Centre text string on TFTFeatherwing

by wildestpixel on Mon Aug 03, 2020 3:10 pm

70C7BB7C-A8AB-4557-A796-5154D2961A19.jpeg
70C7BB7C-A8AB-4557-A796-5154D2961A19.jpeg (108.87 KiB) Viewed 34 times

wildestpixel
 
Posts: 47
Joined: Wed Oct 23, 2019 1:14 am

Re: Centre text string on TFTFeatherwing

by kevinjwalters on Mon Aug 03, 2020 3:25 pm

I'd almost forgotten that there's another way of doing this based on some relatively new functionality added to Label. You can position text by not using x and y but rather setting anchor_point to (0.5, 0.0) and then setting anchored_position to (display_width // 2, 0). The library then takes care of text width calculations for you.

I just looked at how it's doing it and it has its own summation logic in there using each character's glyph and that includes line breaks for multi-line text: https://github.com/adafruit/Adafruit_Ci ... #L233-L303

Oh, the docs say:

font (Font) – A font class that has get_bounding_box and get_glyph. Must include a capital M for measuring character size.


And it looks like get_bounding_box needs to be used very carefully as it could give you back a 2-tuple, a 4-tuple or None!

kevinjwalters
 
Posts: 745
Joined: Sun Oct 01, 2017 3:15 pm

Re: Centre text string on TFTFeatherwing

by wildestpixel on Mon Aug 03, 2020 3:52 pm

D85C799B-2DD0-4401-BD12-50539637BBAD.jpeg
D85C799B-2DD0-4401-BD12-50539637BBAD.jpeg (49.48 KiB) Viewed 33 times


Kevin you are a star, bitmap font centred with anchoring and actually so easy. And of course no get bounding box required for the anchoring as it calculates the glyphs independent and doesn’t require the tuple that was errant in my attempt which might be 0, 2 or 4 array length depending on the font.

wildestpixel
 
Posts: 47
Joined: Wed Oct 23, 2019 1:14 am

Re: Centre text string on TFTFeatherwing

by wildestpixel on Tue Aug 04, 2020 1:02 am

Lets bring this into context for the next person that reads with the whole working code example :

Code: Select all | TOGGLE FULL SIZE
import board
import time
import busio
import adafruit_bmp280
import displayio
import terminalio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import adafruit_ili9341
import adafruit_sht31d
import adafruit_ds3231

# Release any resources currently in use for the displays
displayio.release_displays()

spi = board.SPI()
tft_cs = board.D9
tft_dc = board.D10

display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D6)
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240, rotation=0)



# Create library object using our Bus I2C port
i2c = board.I2C()
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)
sht31d = adafruit_sht31d.SHT31D(i2c)
rtc = adafruit_ds3231.DS3231(i2c)

# Change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

# Lookup table for names of days (nicer printing).
t = rtc.datetime
days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")


# pylint: disable-msg=bad-whitespace
# pylint: disable-msg=using-constant-test
if False:  # change to True if you want to set the time!
    #                     year, mon, date, hour, min, sec, wday, yday, isdst
    t = time.struct_time((2020, 08, 02, 07, 26, 0, 0, -1, -1))
    # you must set year, mon, date, hour, min, sec and weekday
    # yearday is not supported, isdst can be set but we don't do anything with it at this time
    print("Setting time to:", t)  # uncomment for debugging
    rtc.datetime = t
    print()

font = bitmap_font.load_font("/helvB24.bdf")
#font = terminalio.FONT

text_group = displayio.Group(max_size=100, scale = 1)

display_width, display_height = display.width, display.height

# Create the text labels
text_area = label.Label(font, text="Temperature: %0.1f C" % bmp280.temperature, color=0xFF0000)
text_area1 = label.Label(font, text="Humidity: %0.1f %%" % sht31d.relative_humidity, color=0xF0FF00)
text_area2 = label.Label(font, text="Pressure: %0.1f hPa" % bmp280.pressure, color=0x00FF00)
text_area3 = label.Label(font, text="Alt: %0.2f meters" % bmp280.altitude, color =0x0036FF)
text_area4 = label.Label(font, anchor_point=(0.5, 0.5), anchored_position=(display_width // 2,0), text="{:02}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec), color =0xFFFFFF)
text_area5 = label.Label(font, anchor_point=(0.5, 0.5), anchored_position=(display_width // 2,0), text="{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year), color =0xFFFFFF)

# Set the locations
text_area.x = 0
text_area.y = 90
text_area1.x = 0
text_area1.y = 120
text_area2.x = 0
text_area2.y = 150
text_area3.x = 0
text_area3.y = 180
text_area4.y = 40
text_area5.y = 10

# append the labels to a group
text_group.append(text_area)
text_group.append(text_area1)
text_group.append(text_area2)
text_group.append(text_area3)
text_group.append(text_area4)
text_group.append(text_area5)
display.show(text_group)



while True:
    text_area.text = "Temperature: %0.1f C" % (bmp280.temperature - 6.3)
    text_area1.text = "Humidity: %0.1f %%" % sht31d.relative_humidity
    text_area2.text ="Pressure: %0.1f hPa" % bmp280.pressure
    text_area3.text = "Alt: %0.2f meters" % bmp280.altitude
    text_area4.text = "{:02}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec)
    text_area5.text = "{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year)
    t = rtc.datetime
    time.sleep(0.5)
    pass


The key parts being

Code: Select all | TOGGLE FULL SIZE
display_width, display_height = display.width, display.height

text_area5 = label.Label(font, anchor_point=(0.5, 0.5), anchored_position=(display_width // 2,0), text="{} {:02}/{:02}/{}".format(days[int(t.tm_wday)], t.tm_mday, t.tm_mon, t.tm_year), color =0xFFFFFF)

text_area5.y = 10


The problem however as documented is when there is no plain text added to the string.

So after the day changed from Monday to Tuesday, there is a rounding or something in the internal calc or the bounding box so that over a short period of time in a while True loop the text gradually scrolls to the left until x = 0 effectively. If I add a text character, the display doesn't shift to the left ???

Suffice to say I am growing ever fonder of terminalio.FONT

wildestpixel
 
Posts: 47
Joined: Wed Oct 23, 2019 1:14 am

Re: Centre text string on TFTFeatherwing

by Foamyguy on Sat Aug 15, 2020 12:37 pm

wildestpixel

The text gradually scrolling to the left sounds like maybe you uncovered an issue that we have just recently had reported separately and I attempted to create a fix for it last night.

If you have a moment and you're interested in giving it a try you could try using the code from the PR here: https://github.com/adafruit/Adafruit_Ci ... xt/pull/83 and see if your text has stopped moving to the left over time.

Foamyguy
 
Posts: 39
Joined: Mon May 26, 2014 4:24 pm

Please be positive and constructive with your questions and comments.