Writing Centered Text

I am using an ESP32 uProcessor to drive an MSP2807, ILI9341, 240 x 320 display using the Adafruit_GFX and Adafruit_ILI9341 libraries. I want to print a text line, centered horizontally, on the ILI9341 display.

I thought that I have a function which will calculate the cursor position required to print the text centered horizontally.

My simple sketch, which does not work, is attached below.

// ########################################################
// ########################################################
// #
// #              Sketch:  Draw_Centered_String
// #
// #                Date:  1-22-24 
// #      
// #  This sketch is draws a centered text string on the 
// #                MSP2807 ILI9341 TFT Display
// #
// # This sketch uses an ILI9341 Constructor of the form:
// #
// # Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);
// #
// #   TFT_MISO and TFT_SCK pin connections must also be defined and
// #      connected to the ESP32 for this sketch to work    
// #
// #      Microprocessor:  ESP32 Dev Module
// #                       30-Pin, ESP32 DEVKIT V1
// #                       www.doit.am
// #
// #           Tool Kit:  Board Model:  ESP32 Dev Module
// #                      Serial Port:  COM4
// #
// #             Display:  MSP2807
// #                       TFT LCD, 320 x 240 Pixels
// #          Control IC:  ILI9341
// #
// #    Silicon Labs CP210X Driver is used to connect ESP32 to COM4  
// #
// ####################################################################

// ####################################################################
// #
// #     Define standard boilerplate Bodmer pin connections between the 
// #     ILI9341 display and the ESP32 uP driving it.
// #
// #     This is the same boilerplate pin mapping as used in the User_Setup
// #     Setup1_ILI9341 in the TFT_eSPI Library
// #
// ####################################################################

    #define TFT_CS    15     // TFT CS  pin conn to ESP32 uP pin 15  Brown
    #define TFT_RST    4     // TFT RST pin conn to ESP32 uP pin  4  Red
    #define TFT_DC     2     // TFT DC  pin conn to ESP32 uP pin  2  Orange
    
// ####################################################################
// #
// #    Other standard, additional boilerplate Bodmer pin connections
// #    between the ILI9341 display and the ESP32 uP are listed below
// #
// ####################################################################

    #define TFT_MOSI 23    // TFT MOSI pin conn to ESP32 uP pin 23  Yellow
    #define TFT_SCK  18    // TFT SCK pin conn to ESP32 uP pin 18   Green
     
    #define TFT_MISO 19    // TFT MISO pin conn to ESP32 uP pin 19 Gray - Used
     
//  #define TFT_LED  3.3V     // TFT LED conn to ESP32 uP pin 3.3V

// ####################################################################
// ####################################################################

  #include <SPI.h>

  #include <Adafruit_GFX.h>       // include Adafruit graphics library
  #include <Adafruit_ILI9341.h>   // include Adafruit ILI9341 TFT library

  // initialize the ILI9341 TFT library

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);

// ####################################################################
// ####################################################################

void setup(void) {
  Serial.begin(9600);
  tft.begin();
  
  tft.setRotation(1);
  
  tft.fillScreen(ILI9341_BLACK);
 
}

void loop() {
    
    tft.setTextColor(ILI9341_WHITE); 
    tft.setCursor (0, 75);  
    tft.setTextSize(2);
    
    tft.print("Original Text Line");  

     //  Try to print the "Centered Text Line" with a call to
     //  drawMyCenterString 

     drawMyCenterString("Centered Text Line", 0, 100);

 void drawMyCenterString(const String &buf, int x, int y)
{
    int16_t x1, y1;
    uint16_t w, h;
    display.getTextBounds(buf, x, y, &x1, &y1, &w, &h); //  calc width of new string
    display.setCursor(x - w / 2, y);
    display.print(buf);
}

}

How can I fix my sketch?

Try

   display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h);
   display.setCursor( (display.width() - w)/2, y);
   display.print(buf);

your function drawMyCenterString()takes an x and y

is that the point where the text should be center around or as you say in your introduction

you want it centered against to the display bounds ?

➜ what are x and y?

van_der_decken: Thank you for getting back with me and your commenyss to make this sketch work. I changed the lines in the sketch, following your suggestions.

Now the sketch "tells" me that:

display.getTextBounds("Centered Text Line", 0, 0, &x1, &y1, &w, &h);
    display.setCursor( (display.width() - w)/2, y);
    display.print(buf);

results in the error message:

'display' was not declared in this scope


Your screen’s variable is not called display but tft so just replace the variable’s name.

J-M-L Jackson: Thank you for your help.

In this sketch, x and y are display coordinates in pixels, with 0,0 being the pixel in the upper left hand corner of the display

The question still holds - are you centering the text at (x,y) or you want it to be centered at the physical center of the display ?

J-M-L: I'm sorry to have missed your question. The text is to be centered horizontally, at the physical center of the display.

Ok so what’s the need for the X parameter?

The x coordinate is required in the

"display.getTextBounds(buf, x, y, &x1, &y1, &w, &h);" statement along with the y coordinate to tell this statement what the initial cursor location is before the "getTextBounds" computes where to place the input text string, as a centered string on the display. The input text string is located in the "buf" variable entered in "getTextBounds.

It's really not.

tft.getTextBounds("Centered Text Line", 0, 0, &x1, &y1, &w, &h);

van_der_deckan: I'm afraid that the x coordinate must be included in the tft.getTextBounds:

In the " ```
tft.getTextBounds("Centered Text Line", 0, 0, &x1, &y1, &w, &h);

statement, the first two numerical inputs after the "Centered Text Line" string are the 0,0 x,y coordinate pair, required by the getTextBounds function for its computations. 

This coordinate pair tells the function what the cursor position is at the start of its computation.  The pair can be 0,0 as shown.

Read what I wrote.

Try the code.

See for yourself.

I'm sorry for this disconnect. Here is an updated version of the sketch. It still doesn't work and the code "jumps" on the use of the word, "display" before the getTextBounds statement:


// ########################################################
// ########################################################
// #
// #              Sketch:  Draw_Centered_String
// #
// #                Date:  1-22-24 
// #      
// #  This sketch is draws a centered text string on the 
// #                MSP2807 ILI9341 TFT Display
// #
// # This sketch uses an ILI9341 Constructor of the form:
// #
// # Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);
// #
// #   TFT_MISO and TFT_SCK pin connections must also be defined and
// #      connected to the ESP32 for this sketch to work    
// #
// #      Microprocessor:  ESP32 Dev Module
// #                       30-Pin, ESP32 DEVKIT V1
// #                       www.doit.am
// #
// #           Tool Kit:  Board Model:  ESP32 Dev Module
// #                      Serial Port:  COM4
// #
// #             Display:  MSP2807
// #                       TFT LCD, 320 x 240 Pixels
// #          Control IC:  ILI9341
// #
// #    Silicon Labs CP210X Driver is used to connect ESP32 to COM4  
// #
// ####################################################################

// ####################################################################
// #
// #     Define standard boilerplate Bodmer pin connections between the 
// #     ILI9341 display and the ESP32 uP driving it.
// #
// #     This is the same boilerplate pin mapping as used in the User_Setup
// #     Setup1_ILI9341 in the TFT_eSPI Library
// #
// ####################################################################

    #define TFT_CS    15     // TFT CS  pin conn to ESP32 uP pin 15  Brown
    #define TFT_RST    4     // TFT RST pin conn to ESP32 uP pin  4  Red
    #define TFT_DC     2     // TFT DC  pin conn to ESP32 uP pin  2  Orange
    
// ####################################################################
// #
// #    Other standard, additional boilerplate Bodmer pin connections
// #    between the ILI9341 display and the ESP32 uP are listed below
// #
// ####################################################################

    #define TFT_MOSI 23    // TFT MOSI pin conn to ESP32 uP pin 23  Yellow
    #define TFT_SCK  18    // TFT SCK pin conn to ESP32 uP pin 18   Green
     
    #define TFT_MISO 19    // TFT MISO pin conn to ESP32 uP pin 19 Gray - Used
     
//  #define TFT_LED  3.3V     // TFT LED conn to ESP32 uP pin 3.3V

// ####################################################################
// ####################################################################

  #include <SPI.h>

  #include <Adafruit_GFX.h>       // include Adafruit graphics library
  #include <Adafruit_ILI9341.h>   // include Adafruit ILI9341 TFT library

  // initialize the ILI9341 TFT library

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);

// ####################################################################
// ####################################################################

int  x1;
// int  y1;
int  w;
int  h;

void setup(void) {
  Serial.begin(9600);
  tft.begin();
  
  tft.setRotation(1);
  
  tft.fillScreen(ILI9341_BLACK);
 
}

void loop() {
    
    tft.setTextColor(ILI9341_WHITE); 
    tft.setCursor (0, 75);  
    tft.setTextSize(2);
    
    tft.print("Original Text Line");  


    //  Direct use of getTextBounds without any call to a function
    
    display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h);
    display.setCursor( (display.width() - w)/2, y);
    display.print(buf);
}

}

I get the following error message when i run this code:

exit status 1
'display' was not declared in this scope; did you mean 'delay'?

Did you check my previous answer on this? (See post 5)

What I was coming to is that The actual x is irrelevant for the math since the text width is independent on where you will print it. You need an x variable for the bounding box calculation for sure but it’s not useful to make that part of your function’s interface.

If screen width is SW pixels
If text width is TW pixels
Then you have to (SW-TW) pixels of free space. If you want to center, you’ll put half the pixels on one side and the other half on the other side meaning you start painting your text at horizontal position (SW - TW) / 2 hence the code

tft.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); // only care about w
tft.setCursor( (tft.width() - w)/2, y);
tft.print(buf);

J-M-L Thank you for your response. I incorporated this advice into my sketch:

tft.getTextBounds("Centered Text Line", 0, 100, &x1, &y1, &w, &h);

 tft.setCursor( (display.width() - w)/2, y);
 
 tft.print(buf);

and generated the following error message, related to the statement,
"tft.getTextBounds("Centered Text Line", 0, 100, &x1, &y1, &w, &h);":

no matching function for call to 'Adafruit_ILI9341::getTextBounds(const char [19], int, int, int*, double ()(double), int, int*)'

I don't know how to get past this problem.

I attach my complete sketch for your inspection.

// ########################################################
// ########################################################
// #
// #              Sketch:  Direct Draw_Centered_String, 1-25-24
// #
// #                Date:  1-25-24 
// #      
// #  This sketch is draws a centered text string on the 
// #                MSP2807 ILI9341 TFT Display
// #
// # This sketch uses an ILI9341 Constructor of the form:
// #
// # Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);
// #
// #   TFT_MISO and TFT_SCK pin connections must also be defined and
// #      connected to the ESP32 for this sketch to work    
// #
// #      Microprocessor:  ESP32 Dev Module
// #                       30-Pin, ESP32 DEVKIT V1
// #                       www.doit.am
// #
// #           Tool Kit:  Board Model:  ESP32 Dev Module
// #                      Serial Port:  COM4
// #
// #             Display:  MSP2807
// #                       TFT LCD, 320 x 240 Pixels
// #          Control IC:  ILI9341
// #
// #    Silicon Labs CP210X Driver is used to connect ESP32 to COM4  
// #
// ####################################################################

// ####################################################################
// #
// #     Define standard boilerplate Bodmer pin connections between the 
// #     ILI9341 display and the ESP32 uP driving it.
// #
// #     This is the same boilerplate pin mapping as used in the User_Setup
// #     Setup1_ILI9341 in the TFT_eSPI Library
// #
// ####################################################################

    #define TFT_CS    15     // TFT CS  pin conn to ESP32 uP pin 15  Brown
    #define TFT_RST    4     // TFT RST pin conn to ESP32 uP pin  4  Red
    #define TFT_DC     2     // TFT DC  pin conn to ESP32 uP pin  2  Orange
    
// ####################################################################
// #
// #    Other standard, additional boilerplate Bodmer pin connections
// #    between the ILI9341 display and the ESP32 uP are listed below
// #
// ####################################################################

    #define TFT_MOSI 23    // TFT MOSI pin conn to ESP32 uP pin 23  Yellow
    #define TFT_SCK  18    // TFT SCK pin conn to ESP32 uP pin 18   Green
     
    #define TFT_MISO 19    // TFT MISO pin conn to ESP32 uP pin 19 Gray - Used
     
//  #define TFT_LED  3.3V     // TFT LED conn to ESP32 uP pin 3.3V

// ####################################################################
// ####################################################################

  #include <SPI.h>

  #include <Adafruit_GFX.h>       // include Adafruit graphics library
  #include <Adafruit_ILI9341.h>   // include Adafruit ILI9341 TFT library

  // initialize the ILI9341 TFT library

  Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);

// ####################################################################
// ####################################################################

  int x1, w, h;

void setup(void) {
  Serial.begin(9600);
  tft.begin();
  
  tft.setRotation(1);
  
  tft.fillScreen(ILI9341_BLACK);

   tft.setTextColor(ILI9341_WHITE); 
   tft.setCursor (0, 75);  
   tft.setTextSize(2);
    
    tft.print("Original Text Line"); // Print initial text line to display screen 

     //  Try to print the string "Centered Text Line" with a 
     //  direct statement call   

     tft.getTextBounds("Centered Text Line", 0, 100, &x1, &y1, &w, &h);
    
     tft.setCursor( (tft.width() - w)/2, y);
     
     tft.print(buf);
 
}

void loop() {
    
  
}

Best wishes

Perhaps it would help if you read what @J-M-L wrote and compared it to what you wrote:

What @J-M-L wrote

tft.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); // only care about w
tft.setCursor( (tft.width() - w)/2, y);
tft.print(buf);

What you wrote

tft.getTextBounds("Centered Text Line", 0, 100, &x1, &y1, &w, &h);
tft.setCursor( (display.width() - w)/2, y);
tft.print(buf);

The two are not the same. Examine the setCursor line closely.

Actually my mistake as I likely edited the code after he copied it (to replace one more display variable that I had forgotten - typing this on my iPhone)

van_der_decken: Thank you for pointing out the differences in the code. I changed the code to agree with what J-M-L wrote, including the String definition of buf. Unfortunately running the sketch resulted in the error message definition:

no matching function for call to 'Adafruit_ILI9341::getTextBounds(String&, int, int, int*, double (*)(double), int*, int*)'

when the sketch hit the line:

tft.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); // only care about w

Best wishes

Check the doc and parameters types

void getTextBounds (const __FlashStringHelper *s, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H. More...
void getTextBounds (const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H. More...

➜ don’t use floating point