[Solucionado]Crear libreria

Hola,

Estoy inmerso en un proyecto con una pantalla tft, la idea es tener varios menús con botones visuales estilo windows, de esos que al pulsarlos da el efecto de que se hunde, el tema esta que tengo una clase botón que me gustaría convertirla en librería, pero la verdad no se como hacerlo, ademas tengo el inconveniente de que la clase en cuestión depende de las librerías Adafruit_TFTLCD.h y TouchScreen.h
no se si tengo que incluir esas librerías en mi librería o por el contrario hacer que la clase botón herede de las librerías, conoces algún tutorial que lo esplique bien preferible en español o si alguien me quiere echar una mano.

Comparto el código, la gracia del botón que estoy diseñando aparte de que se hunde al pulsarlo es que le paso un método por referencia para que se ejecute cuando se pulsa el botón, como si fuera un evento.

Gracias

Pruebas_TFT_LCD.ino (9.3 KB)

Y las librerias que parece ser que tienen alguna modificación respecto a las originales

Adafruit_GFX.zip (10.5 KB)

Adafruit_TFTLCD.zip (154 KB)

TouchScreen.zip (4.75 KB)

Aunque no tiene que ver con tu consulta revisa el hilo de TFTLCDCyg Algunos consejos para usar TFT´s.

Tiene diría el mejor compendio de ideas/sugerencias al respecto.
Creo a riesgo de equivocarme que ese tema esta tratado.

Revisa no pierdes nada.

El problema puntual que consultas lo dejo para los expertos en C++.

Gracias surbyte por el enlace, ya le había hecho un vistazo, seguiré echándole un vistazo ya que hay mucha información 12 páginas.
Realmente aplico mucho de lo que dice, ya que el propio botón analiza si la pulsación está dentro de él, luego en lugar de usar un if para llamar a un método si el botón está pulsado, el propio botón contiene el puntero del método que tienen que ejecutar, este puntero se lo pasó en el constructor o en la propiedad click, con lo que consigo algo similar a lo que sucede en un evento en visual c# o un evento de Java y por último la estructuración en métodos de los distintos menús y funciones. De momento solo tengo el menú principal y un método que lo único que hace es cambiar la pantalla de color durante unos segundos cuando pulsas el primer botón.
Lo único que no he aplicado es lo de usar char en lugar de String, mi lenguaje de referencia es visual c# y ahí usar String es lo más normal del mundo.
La verdad que mi primera duda es con que ide hago la librería, ¿ el propio de arduino? O necesito otro, yo uso visual studio.
Como tú, de c++ poca idea, realmente esto lo uso para aprender, normalmente con tutoriales, pero en este caso lo que hay es tan básico que no me aclara nada, el tema es que quizás esté equivocado y en lugar de buscar librerías arduino tengo que buscar librerías c++, será mi siguiente paso.

Hola de nuevo,
Yo he aprovechado este código. Funciona con las librerias Elegoo_GFX.h
Elegoo_TFTLCD.h TouchScreen.h> y las de Adafruit. Supongo que esto depende de la marca de tu TFT.
Si entiendes como funcionan los botones, los puedes modificar. Y convertirlo en un menu o botones individuales. Són botones que al pulsarlos da el efecto de que se hunden. Lo adjunto, y así te haces una idea.

phonecal_adafruit.zip (1020 KB)

Muchas gracias, les echo un vistazo.

Esta para pantallas Elegoo

phonecal_elegoo.zip (1020 KB)

No sé si te servirá de ayuda, en las respuestas de alarma temporizada en un mismo led al presionar un botón explico un poco cómo crear una clase y convertirla después en una "supuesta librería".

Gracias IgnoranteAbsoluto.

Un hilo muy interesante y como siempre muy bien explicado, necesitare leerlo un par de veces mas pero creo que estoy en el comino correcto.

Pero 2 cosas,

Vamos a crear nuestra pequeña librería. Para ello vamos a dividir el programa en tres ficheros. Uno seguirá el .ino que teníamos hasta ahora. Y los otros dos serán un .h y un .cpp con la "librería". (He de confesar que no sé cómo se crean estos ficheros con el IDE de Arduino ya que utilizo otras herramientas).

¿que IDE usas? Yo tengo visual studio comunity y para arduino visual micro que es el complemento de arduino para visual studio.

En una clase se pueden declarar variables de los "tipos básicos" así como de otras clases. Por ejemplo la clase Alarma podría tener un objeto de la clase Servo si fuera necesario (sí, Servo es una clase que tiene variables y funciones propias).

Entonces tendría que incluir en mi clase las librerías del tft ¿no?, y esto se haría en el miclase.h pero no en miclase.cpp

Gracias chicarduino

Ahora resulta que la propia librería Adafruit_GFX.h tiene botones, pero los míos son mas chulos jajajajaja, tendré que investigar mas a ver que mas cosas tiene.

Bueno,
Al final he optado por pasar el objeto de la tft por referencia, para así poder utilizar sus métodos en mi clase.

Ahora con los botones listos a por los textbox. :slight_smile:

Dejo los ficheros por si le interesa a alguien o queréis darme algún consejo de como seria mejor.

Boton.cpp (5.01 KB)

Boton.h (1.33 KB)

Pruebas_TFT_LCD.ino (4.36 KB)

He visto lo que has hecho y me parece un buen trabajo. Aún así, a modo de sugerencia y a ver qué te parecen, le he hecho algunas modificaciones, según mi criterio, que paso a detallar.

No utilizo el IDE de Arduino y mi compilador es un poco puntilloso por lo que no permite usar una función sin haber sido declarado antes. Es por ello he declarado la existencia de algunas de ellas antes de la implementación de las funciones en Pruebas_TFT_LCD.ino. Declararlas es decir que existe una función con un nombre y características determinadas, sin poner el cuerpo de la función, y ya con ello el compilador sabe de su existencia y cómo se ha de invocar, sin necesidad de tener su definición. Definirla es poner la función completa, con su cuerpo.

También he tenido que poner "#include <Adafruit_GFX.h>" en Pruebas_TFT_LCD.ino porque mi compilador es un poco quisquilloso.

Por cuestión de gustos y porque normalmente te encuentras con que sólo empiezan en mayúsculas el nombre de las clases, no el de las variables y funciones, es por lo que me he tomado la licencia de renombrar variables y funciones poniendo en minúscula la primera letra y dejando el resto de la "camellización" de los nombres de la clase (las de Pruebas_TFT_LCD.ino no las he tocado).

El puntero this está disponible en todas las funciones no estáticas de la clase. Apunta al objeto al que pertenece la función que se ha llamado. No es obligatorio (salvo en el caso de ambigüedad por tener una variable local con el mismo nombre). He añadido ese puntero this-> delante de todo uso de funciones o variables de la clase dentro de las funciones de la clase. Así "se ve claro" que es de la clase. Esto permite, aunque no es aconsejable, el uso de parámetros con el mismo nombre que una variable de la clase (sería el que no tiene el this->). También he quitado el guión bajo al inicio de las variables _Pulsado y _tft, ya con el this-> "se ve" que es de la clase (insisto, es cuestión de gustos). Aunque _Pulsado la he renombrado a estaPulsado para que no entre en conflicto con la funcíón pulsado. En el caso de _tft no hay problema en llamarla tft ya que, en el constructor, cuando se utiliza el parámetro tft se diferencian uno de otro porque el parámetro de la función es tft y la variable de la clase es this->tft. Si aún así se prefiere usar el guión bajo, mejor usarlo para todas las variables (por lo menos para las privadas, que deberían ser todas privadas) y no para unas sí y para otras no. Ya cuesta acordarse del nombre, como para encima tener que recordar si llevan guión o no.

DibujarBoton y DibujarBotonPresionado no solo "pierden" la "B" mayúscula, sino que tanbién pierden "Boton". Pasan a llamarse dibujar y dibujarPresionado, no hace falta resaltar que se trata de un botón. Si en lugar de un boton se trata de un icono, las llamaría igual: dibujar o dibujarPresionado. Esto es bastante útil sobre todo si fueras a usar herencia.

Una vez renombradas las funciones y variables de la clase he hecho los siguiente cambios.

El puntero ptrClick pasa a ser una variable privada de la clase. En principio no tiene porqué ser accesible desde fuera de la clase.

Veo que inicializas ptrClick con un NULL en el constructor por defecto y verificas que ptrClick no sea NULL antes de usarlo. En caso de ser NULL no llamas a la función. Pues si acertadamente haces esto con ptrClick deberías de hacer lo mismo con tft. Eso es lo que he hecho, inicializar a NULL tft en el constructor por defecto y verificar que tft no es NULL para no usarlo si lo es. Esto hace que el programa sea más robusto a fallos de programación de quienes usamos la librería.

En lugar de pasar al constructor un puntero a un objeto de la clase Adafruit_TFTLCD (el parámetro tft) lo pasamos por referencia (no es posible en C pero sí en C++) y luego obtenemos su dirección y lo guardamos en la variable tft de la clase (this->tft).

Antes:

Boton::Boton(Adafruit_TFTLCD *tft... // <-- Recibimos un puntero
{
	this->tft = tft;    // Guardamos ese puntero en la variable de la clase

Ahora:

Boton::Boton(Adafruit_TFTLCD &tft... // <-- Cambiamos el * por un & para indicar que lo recibimos por referencia, y no un puntero
{
	this->tft = &tft;   // <-- Como es una referencia lo que recibimos, debemos obtener su dirección con el operador & y guardar el puntero

Con lo que para usar el constructor no hay que pasar la dirección del objeto Adafruit_TFTLCD, sino el objeto diréctamente. Como ejemplo vemos que la definición que antes era:

	botones[0] = Boton(&tft,20, 50, 30, 200, F("SIMULAR CELULA"),NULL);

Ahora "pierde" el & y queda así:

	botones[0] = Boton(tft,20, 50, 30, 200, F("SIMULAR CELULA"),NULL);

Nota: si se pasa por referencia (el & al definir el parámetro de la función) no se puede pasar un NULL. Si se quiere poder pasar un NULL de ha de pasar un puntero (el * al definir el parámetro de la función).

He añadido a la clase las funciones setTft y setClick para poder asignar valores a tft y ptrClick si se ha creado el objeto mediante el constructor por defecto.

En lugar de definir dos veces "los colores" lo he pasado a Boton.h con lo que sólo hay que definirlo una única vez. También he cambiado la forma de definirlos, en lugar de usar el #define lo defino como constantes de tipo uint16_t (he visto que las librerías de Adafruit utilizan ese tipo para el color). A la vez las he creado dentro de un "espacio de nombres" para evitar posibles conflictos por si se utilizan esos mismos nombres para otras constantes con diferentes valores. Para más información, como siempre, buscar en Google. Esto no consume ni más ni menos recursos, debería de generar exactamente el mismo binario.

Tras todas las modificaciones sólo he podido verificar que me compila sin errores. Pero no sé si realmente funciona bien, ya que no dispongo del hardware para probarlo.

Como ves, casi todas las modificaciones son "estéticas". No he mirado "más a fondo". Pero si te funciona es que lo más importante ha de estar correcto.

Adjunto ficheros con las modificaciones.

Boton.cpp (5.8 KB)

Boton.h (2.2 KB)

Pruebas_TFT_LCD.ino (4.58 KB)

Muchas gracias por tus opiniones y consejos son bien recibidos.

Pues si acertadamente haces esto con ptrClick deberías de hacer lo mismo con tft

Pues no lo puse ya que en un principio en el planteamiento de la clase no se contempla que eso pueda ser NULL, es mas puse el constructor por defecto que había pensado quitarlo ya que sin objeto tft no habría sitio donde pintar el botón, pero tienes razón mejor protegerlo. Y además ahora con tu modificación en el que se puede pasar el tft después, pues ya lo dejo.

Por cuestión de gustos y porque normalmente te encuentras con que sólo empiezan en mayúsculas el nombre de las clases, no el de las variables y funciones, es por lo que me he tomado la licencia de renombrar variables y funciones poniendo en minúscula la primera letra

Me parece bien, conozco las normas no escritas de cómo hacerlo, se que como lo hago no es lo más correcto pero como programo para mí y como hobby. Se que tendría que cambiar pero son muchos años.

El puntero ptrClick pasa a ser una variable privada de la clase

En principio era privada, no se ahora mismo exactamente en qué prueba lo puse como publica y ya se quedo ahí.

En lugar de pasar al constructor un puntero a un objeto de la clase Adafruit_TFTLCD (el parámetro tft) lo pasamos por referencia (no es posible en C pero sí en C++) y luego obtenemos su dirección y lo guardamos en la variable tft de la clase (this->tft).

¿Cuál es la diferencia? De momento no controlo mucho el concepto puntero, referencia en C++ ya que para mí me parecen casi lo mismo, uno pasa la posición en memoria y el otro el objeto en sí que al final es la posición en memoria ¿o estoy equivocado?.