[Solucionado]Problemas al crear librería

Hola a todos, a ver si alguien me puede ayudar o aconsejar.
Estoy realizando un proyecto donde uso una pantalla TFT táctil, ya la hago funcionar, dibujar botones y detectar su pulsación, sé que hay librerías para esto pero quiero hacer la mía, el código es el siguiente.

// Librerías Incluidas
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include "TouchScreen.h"

////Clase encarga de dibujar botones////

// Estructuras de los Menus


// Definiciones

// Pines de conexión del LCD 
#define LCD_CS A3 // Chip Select - Pin Analógico 3
#define LCD_DC A2 // Command/Data - Pin Analógico 2
#define LCD_WR A1 // LCD Write - Pin Analógico 1
#define LCD_RD A0 // LCD Read - Pin Analógico 0
#define LCD_RESET A4 // LCD Reset - Pin Analógico 4
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

// Definimos los colores para poder referirnos a ellos con su nombre en lugar de usar el código hexadecimal de cada uno.
#define NEGRO 0x0000 
#define ROJO 0xF800 
#define VERDE 0x07E0 
#define BLANCO 0xFFFF 
#define AZUL 0x001F 
#define AZULC 0x07FF
#define AMARILLO 0xFFE0
#define ROSA 0xF81F
#define GRIS 0xC618
#define GRISOSCURO 0x7BEF

// Objetos globales
Adafruit_TFTLCD tft= Adafruit_TFTLCD(LCD_CS,LCD_DC,LCD_WR,LCD_RD,LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 365);
class Boton
{
public:
  Boton(int posicionx, int posiciony, int alto, int ancho, String texto);
  ~Boton();
  void DibujarBoton(void);
  void DibujarBotonPesionado(void);
  void SetPosicionX(int posx);
  void SetPosicionY(int posy);
  void SetAlto(int alto);
  void SetAncho(int ancho);
  void SetTexto(String texto);
  int GetPosicionX(void);
  int GetPosicionY(void);
  int GetAlto(void);
  int GetAncho(void);
  String GetTexto(void);
  bool Pulsado(int pulx, int puly, int pult);

private:
  int PosicionX, PosicionY, Alto, Ancho;
  String Texto="";
  bool _Pulsado = false;
  void ColocarTexto();

};

Boton::Boton(int posicionx = 20, int posiciony = 0, int alto = 30, int ancho = 200, String texto = "PULSAME")
{
  PosicionX = posicionx;
  PosicionY = posiciony;
  Ancho = ancho;
  Alto = alto;
  Texto = texto;
  _Pulsado = false;
  DibujarBoton();
}

Boton::~Boton()
{
}

void Boton::DibujarBoton(void)
{
  tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, BLANCO);
  tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, NEGRO);
  tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, BLANCO);
  tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, NEGRO);
  tft.setTextColor(ROJO);
  ColocarTexto();
}

void Boton::DibujarBotonPesionado(void)
{
  tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, NEGRO);
  tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, NEGRO);
  tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  tft.setTextColor(AZUL);
  ColocarTexto();
}

void Boton::SetPosicionX(int posx)
{
  PosicionX = posx;
}

void Boton::SetPosicionY(int posy)
{
  PosicionY = posy;
}

void Boton::SetAlto(int alto)
{
  Alto = alto;
}

void Boton::SetAncho(int ancho)
{
  Ancho = ancho;
}

void Boton::SetTexto(String texto)
{
  Texto = texto;
}

int Boton::GetPosicionX(void)
{
  return PosicionX;
}

int Boton::GetPosicionY(void)
{
  return PosicionY;
}

int Boton::GetAlto(void)
{
  return Alto;
}

int Boton::GetAncho(void)
{
  return Ancho;
}

String Boton::GetTexto(void)
{
  return Texto;
}

bool Boton::Pulsado(int pulx, int puly, int pult)
{
  if (pulx > PosicionX && pulx < (PosicionX + Ancho) && puly > PosicionY && (puly < PosicionY + Alto) && pult >10)
  {
    DibujarBotonPesionado();
    delay(500);
    _Pulsado = true;
  }
  else
  {
    DibujarBoton();
    _Pulsado = false;
  }
  return _Pulsado;
}

void Boton::ColocarTexto(void)
{
  int centrox = (Ancho / 2 - (Texto.length() * 6)); // Multiplicamos el número de letras por lo que ocupa cada una
  //int centrox = Ancho / 2;
  int centroy = Alto / 2 - 6; // restamos lo que ocupa una letra
  tft.setCursor(PosicionX + centrox, PosicionY + centroy);
  tft.setTextSize(2); // 6 pix alto x 4 pix ancho
  tft.print(Texto);
}

Boton boton1(20,50,30,200,"SIMULAR CELULA");
Boton boton2(20,90,30,200,"LEER CELULA");
Boton boton3(20, 130, 30, 200, "LEER TERMOPAR");
Boton boton4(20, 170, 30, 200, "LEER TEMPERATURA");
Boton boton5(20, 210, 30, 200, "CONFIGURACION");
Boton boton6(20, 250, 30, 200, "PULSAME");

// Configuración de Arduino, solo se ejecuta una vez
void setup()
{
  Serial.begin(115200);
  tft.begin(0x9341);
  tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
  tft.setRotation(0); // Establecemos la posición de la pantalla Vertical u Horizontal
  //pinMode(XM, OUTPUT);
  //pinMode(YP, OUTPUT);
}

// Bucle principal del programa
void loop()
{
  TSPoint ps = ts.getPoint();
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  ps.x = map(ps.x, 150, 900, tft.width(),0); // Para rotación 0
  ps.y = map(ps.y, 110, 900, tft.height(),0); // Para rotación 0
  //ps.x = map(ps.x, 150, 900, 0, tft.width()); // Para rotación 1
  //ps.y = map(ps.y, 110, 900, 0, tft.height()); // Para rotación 1
  boton1.Pulsado(ps.x,ps.y,ps.z);
  boton2.Pulsado(ps.x,ps.y,ps.z);
  boton3.Pulsado(ps.x,ps.y,ps.z);
  boton4.Pulsado(ps.x,ps.y,ps.z);
  boton5.Pulsado(ps.x,ps.y,ps.z);
  if (boton6.Pulsado(ps.x,ps.y,ps.z))
  {
    tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
    delay(2000);
  }
  // Serial.print(ps.z); // Comprobar la pulsación en la pantalla tactil
}

Como veis, creo una clase y a partir de ahí los botones que necesito, esto funciona correctamente. Ahora lo que quiero es socar la parte donde creo la clase a una librería, para ello he creado los ficheros .cpp y .h
El fichero boton.h contiene lo siguiente:

#ifndef Boton_h
#define Boton_h

#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include <TouchScreen.h>

class Boton
{
public:
  //Boton();
  Boton(int posicionx, int posiciony, int alto, int ancho, String texto);
  //~Boton();
  void DibujarBoton(void);
  void DibujarBotonPesionado(void);
  void SetPosicionX(int posx);
  void SetPosicionY(int posy);
  void SetAlto(int alto);
  void SetAncho(int ancho);
  void SetTexto(String texto);
  int GetPosicionX(void);
  int GetPosicionY(void);
  int GetAlto(void);
  int GetAncho(void);
  String GetTexto(void);
  bool Pulsado(int pulx, int puly, int pult);

private:
  int PosicionX, PosicionY, Alto, Ancho;
  String Texto="";
  bool _Pulsado = false;
  void ColocarTexto();
  // Definimos los colores para poder referirnos a ellos con su nombre en lugar de usar el código hexadecimal de cada uno.
  #define NEGRO 0x0000 
  #define ROJO 0xF800 
  #define VERDE 0x07E0 
  #define BLANCO 0xFFFF 
  #define AZUL 0x001F 
  #define CELESTE 0x07FF
  #define AMARILLO 0xFFE0
  #define MAGENTA 0xF81F
  #define GRIS 0xC618
  #define GRISOSCURO 0x7BEF
};

#endif

y el fichero boton.cpp

#include "Boton.h"

// Boton::Boton()
// {
//   PosicionX = 0;
//   PosicionY = 0;
//   Alto = 30;
//   Ancho = 60;
//   Texto = "Boton";
//   _Pulsado = false;
// }

Boton::Boton(int posicionx = 20, int posiciony = 0, int alto = 30, int ancho = 200, String texto = "PULSAME")
{
  PosicionX = posicionx;
  PosicionY = posiciony;
  Ancho = ancho;
  Alto = alto;
  Texto = texto;
  _Pulsado = false;
  DibujarBoton();
}

//Boton::~Boton()
//{
//}

void Boton::DibujarBoton(void)
{
  tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, BLANCO);
  tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, GRIS);
  tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, BLANCO);
  tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, GRIS);
  tft.setTextColor(ROJO);
  ColocarTexto();
}

void Boton::DibujarBotonPesionado(void)
{
  tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, GRIS);
  tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, GRIS);
  tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  tft.setTextColor(AZUL);
  ColocarTexto();
}

void Boton::SetPosicionX(int posx)
{
  PosicionX = posx;
}

void Boton::SetPosicionY(int posy)
{
  PosicionY = posy;
}

void Boton::SetAlto(int alto)
{
  Alto = alto;
}

void Boton::SetAncho(int ancho)
{
  Ancho = ancho;
}

void Boton::SetTexto(String texto)
{
  Texto = texto;
}

int Boton::GetPosicionX(void)
{
  return PosicionX;
}

int Boton::GetPosicionY(void)
{
  return PosicionY;
}

int Boton::GetAlto(void)
{
  return Alto;
}

int Boton::GetAncho(void)
{
  return Ancho;
}

String Boton::GetTexto(void)
{
  return Texto;
}

bool Boton::Pulsado(int pulx, int puly, int pult)
{
  if (pulx > PosicionX && pulx < (PosicionX + Ancho) && puly > PosicionY && (puly < PosicionY + Alto) && pult >10)
  {
    DibujarBotonPesionado();
    delay(500);
    _Pulsado = true;
  }
  else
  {
    DibujarBoton();
    _Pulsado = false;
  }
  return _Pulsado;
}

void Boton::ColocarTexto(void)
{
  int centrox = (Ancho / 2 - (Texto.length() * 6)); // Multiplicamos el número de letras por lo que ocupa cada una
  //int centrox = Ancho / 2;
  int centroy = Alto / 2 - 6; // restamos lo que ocupa una letra
  tft.setCursor(PosicionX + centrox, PosicionY + centroy);
  tft.setTextSize(2); // 6 pix alto x 4 pix ancho
  tft.print(Texto);
}

Los dos ficheros están en una carpeta llamada boton que a su vez la pongo en la carpeta del proyecto de arduino, el fichero .ino contiene lo siguiente

// Librerías Incluidas
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include "TouchScreen.h"
#include "Boton/Boton.h"

////Clase encarga de dibujar botones////

// Estructuras de los Menus


// Definiciones

// Pines de conexión del LCD 
#define LCD_CS A3 // Chip Select - Pin Analógico 3
#define LCD_DC A2 // Command/Data - Pin Analógico 2
#define LCD_WR A1 // LCD Write - Pin Analógico 1
#define LCD_RD A0 // LCD Read - Pin Analógico 0
#define LCD_RESET A4 // LCD Reset - Pin Analógico 4
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

// Objetos globales
Adafruit_TFTLCD tft= Adafruit_TFTLCD(LCD_CS,LCD_DC,LCD_WR,LCD_RD,LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 365);

Boton boton1(20,50,30,200,"SIMULAR CELULA");
Boton boton2(20,90,30,200,"LEER CELULA");
Boton boton3(20, 130, 30, 200, "LEER TERMOPAR");
Boton boton4(20, 170, 30, 200, "LEER TEMPERATURA");
Boton boton5(20, 210, 30, 200, "CONFIGURACION");
Boton boton6(20, 250, 30, 200, "PULSAME");

// Configuración de Arduino, solo se ejecuta una vez
void setup()
{
  Serial.begin(115200);
  tft.begin(0x9341);
  tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
  tft.setRotation(0); // Establecemos la posición de la pantalla Vertical u Horizontal
}

// Bucle principal del programa
void loop()
{
  TSPoint ps = ts.getPoint();
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  ps.x = map(ps.x, 150, 900, tft.width(),0); // Para rotación 0
  ps.y = map(ps.y, 110, 900, tft.height(),0); // Para rotación 0
  //ps.x = map(ps.x, 150, 900, 0, tft.width()); // Para rotación 2
  //ps.y = map(ps.y, 110, 900, 0, tft.height()); // Para rotación 2
  boton1.Pulsado(ps.x,ps.y,ps.z);
  boton2.Pulsado(ps.x,ps.y,ps.z);
  boton3.Pulsado(ps.x,ps.y,ps.z);
  boton4.Pulsado(ps.x,ps.y,ps.z);
  boton5.Pulsado(ps.x,ps.y,ps.z);
  if (boton6.Pulsado(ps.x,ps.y,ps.z))
  {
    tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
    delay(2000);
  }
}

Cuando compilo recibo los siguientes mensajes de erro:

C:\Users\rodri\AppData\Local\Temp\ccc506Wd.ltrans0.ltrans.o: In function `global constructors keyed to 65535_0_PruebasPantallaTFT2.ino.cpp.o.3648':
<artificial>:(.text.startup+0x3fe): undefined reference to `Boton::Boton(int, int, int, int, String)'
<artificial>:(.text.startup+0x422): undefined reference to `Boton::Boton(int, int, int, int, String)'
<artificial>:(.text.startup+0x446): undefined reference to `Boton::Boton(int, int, int, int, String)'
<artificial>:(.text.startup+0x46a): undefined reference to `Boton::Boton(int, int, int, int, String)'
<artificial>:(.text.startup+0x48e): undefined reference to `Boton::Boton(int, int, int, int, String)'
C:\Users\rodri\AppData\Local\Temp\ccc506Wd.ltrans0.ltrans.o:<artificial>:(.text.startup+0x4b2): more undefined references to `Boton::Boton(int, int, int, int, String)' follow
C:\Users\rodri\AppData\Local\Temp\ccc506Wd.ltrans0.ltrans.o: In function `loop':
C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:61: undefined reference to `Boton::Pulsado(int, int, int)'
C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:62: undefined reference to `Boton::Pulsado(int, int, int)'
C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:63: undefined reference to `Boton::Pulsado(int, int, int)'
C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:64: undefined reference to `Boton::Pulsado(int, int, int)'
C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:65: undefined reference to `Boton::Pulsado(int, int, int)'
C:\Users\rodri\AppData\Local\Temp\ccc506Wd.ltrans0.ltrans.o:C:\Users\rodri\OneDrive\Documentos\Programacion\Proyectos Arduino\PruebasPantallaTFT2/PruebasPantallaTFT2.ino:66: more undefined references to `Boton::Pulsado(int, int, int)' follow
collect2.exe: error: ld returned 1 exit status
exit status 1

y la verdad, no sé que me falta o que esto haciendo mal. Por favor, ¿alguien me puede ayudar a ver que me falla?
Gracias

No estoy absolutamente seguro pero creo que los archivos de la librería (.h y .cpp) tienen que estar en la misma carpeta que el sketch (.ino), no en una subcarpeta.

¿cómo tienes exactamente la estructura de tus carpetas?

Por ejemplo, cuando tú descargas una librería a través del IDE de arduino, ¿esa librería en dónde se guarda?
Por ejemplo, en mi caso los proyectos de Arduino los guardo en Documentos/Arduino


Y dentro de esa carpeta de Arduino, cuando descargo una librería, ésta se guarda Documento/Arduino/libraries, allí deberían estar tus librerías de Adafruit_GFX y TFTLCD, y allí mismo deberías de colocar la librería que tú hiciste


imagen

y ya en tu ejemplo, en tu archivo .ino, mandar a llamarla
imagen

Pero justamente el PO no la quiere instalar "global" sino en la carpeta del proyecto, digamos "local".

Gracias, ya la había puesto en la carpeta de librerías, también lo había probado en la carpeta del proyecto y finalmente en una carpeta dentro del proyecto. En todos los casos el error es el mismo.

Gracias, ya he probado de todas las formas posibles, en la carpeta de libreáis, en una carpeta en el proyecto y con los ficheros en el proyecto. El resultado es el mismo en todos los casos.

Según estaba contestando a @MaximoEsfuerzo y @belmont1591 para agradecerle su ayuda me he dado cuenta de lo que hacia mal, no hay como hacer una pregunta para que se te ocurra la solución y mira que llevo tiempo dándole vueltas a este asunto.
El problema está en el objeto
Adafruit_TFTLCD tft= Adafruit_TFTLCD(LCD_CS,LCD_DC,LCD_WR,LCD_RD,LCD_RESET);
en el programa original donde creo la clase en el mismo .ino el objeto existe, ya que es declarado al principio, pero claro, en la librería no existe, por lo tanto al copiar esto directamente en la libraría.

`void Boton::DibujarBoton(void)
{
  tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, BLANCO);
  tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, NEGRO);
  tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, BLANCO);
  tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, NEGRO);
  tft.setTextColor(ROJO);
  ColocarTexto();
}`

, el objeto tft no existe y por lo tanto da error de compilación.
He probado varias soluciones, heredar de Adafruit_GFX y heredar de Adafruit_TFTLCD, pero ninguna me ha funcionado por diversos motivos, entre ellos que me pedían completar una función abstracta, para la cual no dispongo de los conocimientos suficientes. Por lo que la solución definitiva ha sido pasar el objeto tft por referencia a mi clase, una vez hecho esto ya me ha funcionado perfectamente, tanto poniendo la libreria en la carpeta de librerias, como poniendo los archivos .h y .cpp en la carpeta de mi proyecto, ha seguido sin funcionar si ponía la librería en una carpeta dentro de la carpeta del proyecto. A continuación expongo como ha quedado el código, pero si alguien sabe una mejor forma, estaré encantado de leerlo y aprender.
Código en .ino

// Librerías Incluidas
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include "TouchScreen.h"
#include <Boton.h>

////Clase encarga de dibujar botones////

// Estructuras de los Menus


// Definiciones

// Pines de conexión del LCD 
#define LCD_CS A3 // Chip Select - Pin Analógico 3
#define LCD_DC A2 // Command/Data - Pin Analógico 2
#define LCD_WR A1 // LCD Write - Pin Analógico 1
#define LCD_RD A0 // LCD Read - Pin Analógico 0
#define LCD_RESET A4 // LCD Reset - Pin Analógico 4
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

// Objetos globales
Adafruit_TFTLCD tft= Adafruit_TFTLCD(LCD_CS,LCD_DC,LCD_WR,LCD_RD,LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 365);

Boton boton1(tft,20,50,30,200,"SIMULAR CELULA");
Boton boton2(tft,20,90,30,200,"LEER CELULA");
Boton boton3(tft,20, 130, 30, 200, "LEER TERMOPAR");
Boton boton4(tft,20, 170, 30, 200, "LEER TEMPERATURA");
Boton boton5(tft,20, 210, 30, 200, "CONFIGURACION");
Boton boton6(tft,20, 250, 30, 200, "PULSAME");

// Configuración de Arduino, solo se ejecuta una vez
void setup()
{
  Serial.begin(115200);
  tft.begin(0x9341);
  tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
  tft.setRotation(0); // Establecemos la posición de la pantalla Vertical u Horizontal
}

// Bucle principal del programa
void loop()
{
  TSPoint ps = ts.getPoint();
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  ps.x = map(ps.x, 150, 900, tft.width(),0); // Para rotación 0
  ps.y = map(ps.y, 110, 900, tft.height(),0); // Para rotación 0
  //ps.x = map(ps.x, 150, 900, 0, tft.width()); // Para rotación 2
  //ps.y = map(ps.y, 110, 900, 0, tft.height()); // Para rotación 2
  boton1.Pulsado(ps.x,ps.y,ps.z);
  boton2.Pulsado(ps.x,ps.y,ps.z);
  boton3.Pulsado(ps.x,ps.y,ps.z);
  boton4.Pulsado(ps.x,ps.y,ps.z);
  boton5.Pulsado(ps.x,ps.y,ps.z);
  if (boton6.Pulsado(ps.x,ps.y,ps.z))
  {
    tft.fillScreen(GRIS); // Colocamos el fondo del LCD en Negro y borra la pantalla
    delay(2000);
  }
}

Código en .h

#ifndef Boton_h
#define Boton_h

#include <Arduino.h>
#include <Adafruit_TFTLCD.h>

class Boton
{
public:
  Boton(Adafruit_TFTLCD &tft, int posicionx = 20, int posiciony = 0, int alto = 30, int ancho = 200, String texto = "PULSAME");
  void DibujarBoton(void);
  void DibujarBotonPesionado(void);
  void SetPosicionX(int posx);
  void SetPosicionY(int posy);
  void SetAlto(int alto);
  void SetAncho(int ancho);
  void SetTexto(String texto);
  int GetPosicionX(void);
  int GetPosicionY(void);
  int GetAlto(void);
  int GetAncho(void);
  String GetTexto(void);
  bool Pulsado(int pulx, int puly, int pult);

private:
  int PosicionX, PosicionY, Alto, Ancho;
  String Texto="";
  bool _Pulsado = false;
  void ColocarTexto();
  Adafruit_TFTLCD &_tft;
  // Definimos los colores para poder referirnos a ellos con su nombre en lugar de usar el código hexadecimal de cada uno.
  #define NEGRO 0x0000 
  #define ROJO 0xF800 
  #define VERDE 0x07E0 
  #define BLANCO 0xFFFF 
  #define AZUL 0x001F 
  #define CELESTE 0x07FF
  #define AMARILLO 0xFFE0
  #define MAGENTA 0xF81F
  #define GRIS 0xC618
  #define GRISOSCURO 0x7BEF
};

#endif

Código en .cpp

#include "Boton.h"
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
//#include <TouchScreen.h>

Boton::Boton(Adafruit_TFTLCD &tft, int posicionx, int posiciony, int alto, int ancho, String texto) : _tft(tft)
{
  PosicionX = posicionx;
  PosicionY = posiciony;
  Ancho = ancho;
  Alto = alto;
  Texto = texto;
  _Pulsado = false;
  DibujarBoton();
  
}

void Boton::DibujarBoton(void)
{
  _tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, BLANCO);
  _tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, GRIS);
  _tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, BLANCO);
  _tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, GRIS);
  _tft.setTextColor(ROJO);
  ColocarTexto();
}

void Boton::DibujarBotonPesionado(void)
{
  _tft.drawLine(PosicionX, PosicionY, PosicionX + Ancho, PosicionY, GRIS);
  _tft.drawLine(PosicionX, PosicionY + Alto, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  _tft.drawLine(PosicionX, PosicionY, PosicionX, PosicionY + Alto, GRIS);
  _tft.drawLine(PosicionX + Ancho, PosicionY, PosicionX + Ancho, PosicionY + Alto, BLANCO);
  _tft.setTextColor(AZUL);
  ColocarTexto();
}

void Boton::SetPosicionX(int posx)
{
  PosicionX = posx;
}

void Boton::SetPosicionY(int posy)
{
  PosicionY = posy;
}

void Boton::SetAlto(int alto)
{
  Alto = alto;
}

void Boton::SetAncho(int ancho)
{
  Ancho = ancho;
}

void Boton::SetTexto(String texto)
{
  Texto = texto;
}

int Boton::GetPosicionX(void)
{
  return PosicionX;
}

int Boton::GetPosicionY(void)
{
  return PosicionY;
}

int Boton::GetAlto(void)
{
  return Alto;
}

int Boton::GetAncho(void)
{
  return Ancho;
}

String Boton::GetTexto(void)
{
  return Texto;
}

bool Boton::Pulsado(int pulx, int puly, int pult)
{
  if (pulx > PosicionX && pulx < (PosicionX + Ancho) && puly > PosicionY && (puly < PosicionY + Alto) && pult >10)
  {
    DibujarBotonPesionado();
    delay(500);
    _Pulsado = true;
  }
  else
  {
    DibujarBoton();
    _Pulsado = false;
  }
  return _Pulsado;
}

void Boton::ColocarTexto(void)
{
  int centrox = (Ancho / 2 - (Texto.length() * 6)); // Multiplicamos el número de letras por lo que ocupa cada una
  int centroy = Alto / 2 - 6; // restamos lo que ocupa una letra
  _tft.setCursor(PosicionX + centrox, PosicionY + centroy);
  _tft.setTextSize(2); // 6 pix alto x 4 pix ancho
  _tft.print(Texto);
}

Con esto ya tengo mi propia librería funcional para dibujar botones en una pantalla TFT
Gracias a todos.

Tu código muestra una buena base para gestionar botones en pantallas táctiles, pero hay áreas clave que podrían optimizarse. Como señala Astudillo Torres (2016) en su trabajo sobre TIC en entornos educativos, "la eficiencia en el diseño de interfaces depende de la modularidad y la capacidad de adaptación a distintos escenarios" (p. 38). Aplicando esto a tu proyecto:

  1. Evita bloqueos con delay():
    El uso de delay(500) en el método Pulsado() detiene toda la ejecución del programa. Según Bruna et al. (2022), en sistemas interactivos, "la no linealidad y la capacidad de respuesta en tiempo real son críticas para la experiencia del usuario" (p. 480). Reemplázalo con una máquina de estados basada en millis() para mantener la reactividad.
  2. Validación de texto y dimensiones:
    Actualmente, ColocarTexto() no verifica si el texto excede el ancho del botón. Esto podría causar solapamientos visuales. Como sugiere Soto Ortiz y Torres Gastelú (2016), "la robustez de una interfaz se mide por su manejo elegante de casos límite" (p. 5). Implementa un recorte o ajuste automático del texto.
  3. Arquitectura modular con callbacks:
    Tu clase Boton maneja la lógica de dibujo y detección, pero acopla la acción al presionar. Cazevieille (2015) recomienda "desacoplar la interacción de la acción mediante patrones de diseño como callbacks" (p. 60). Usa punteros a funciones o lambdas para definir comportamientos dinámicos al crear cada botón.
class Boton {
public:
    typedef std::function<void()> Callback; // Tipo para función de callback
    Boton(..., Callback onClick = nullptr) : _onClick(onClick) {...}
    bool Pulsado(int x, int y, int z) {
        if (dentroRango(x, y, z)) {
            if (_onClick) _onClick(); // Ejecuta callback si existe
            return true;
        }
        return false;
    }
private:
    Callback _onClick;
};

// Uso: 
Boton botonSimular(..., []() { 
    Serial.println("Botón SIMULAR presionado"); 
});

Muchas gracias por tus recomendaciones.
El delay esta puesto a propósito, la verdad es que no quiero que ocurra nada en ese tiempo, simplemente quiero que se vea el efecto de pulsación y como los botones son para menús en principio para el uso que le voy a dar no sería problemático.
Sobre proteger el texto, me parece una observación muy correcta y como practica esta muy bien, por lo que implementare un método para ello.
Y sobre la llamada en callback, me parece muy interesante, así que me pondré a investigar y seguro que lo implemento.
Muchas gracias.