[CONSEILS] Texte réactif (cliquable) sur écran TFT 4"3 pouces + Arduino Uno

Bonjour à tous,

Je me heurte à une problématique de code sur la configuration Hardware suivante :

Arduino UNO Rev3
Shield Ecran tactile 4"3 pouces

En fait, j'ai un écran tactile monté sur un Arduino, et je souhaiterais :
Pouvoir avoir un texte qui s'affiche sur l'écran quand je clique sur un autre texte, déjà affiché sur l'écran.
Une sorte de texte-bouton réactif.

J'utilise la librairie FT801 relative à la puce vidéo qui porte le même nom.

Pour le moment, je parviens, grâce à la fonction suivante, et aux exemples fournis avec la librairie, à afficher mes textes :

FTImpl.Cmd_Text(FT_DISPLAYWIDTH/10, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string);//display "Hello World at the center of the screen using inbuilt font handle 29 "

Ma question est la suivante :

Comment puis-je rendre ces textes cliquables et y associer une action (afficher un autre texte) ?
Par exemple : un texte "Animal" qui affiche "Chat" ailleurs sur l'écran quand on clique dessus.

Merci beaucoup par avance,
T_T29

Tu dois repérer le rectangle qui englobe ton texte et vérifier que les coordonnées du point où tu cliques sont à l'intérieur du rectangle

Merci beaucoup pour ton explication !

Pardon,

Je crois que ce n'est pas si simple que cela pour moi, comment fais-tu pour détecter la zone qui englobe un texte ?

J'aurai bien une idée, c'est à dire que j'ai réussi à afficher les coordonnées du point cliqué sur l'écran, du coup, il faudrait dessiner la zone à englober "à la main" en notant les coordonnées des limites en même temps, mais je ne trouve pas cela très précis.

Existe t-il un autre moyen ?

Merci beaucoup
t_t29

J'utilise la librairie FT801 relative à la puce vidéo qui porte le même nom.

Ca dépend de la bibliothèque graphique que tu utilises : certaines ont des méthodes pour ça (exemple u8glib : getStrWidth), d'autres non et il faut le faire soi-même.

Tu places ton texte à un endroit de coordonnées x0, y0 :

FTImpl.Cmd_Text(FT_DISPLAYWIDTH/10, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string);

Dans cet exemple, je pense que x0 vaut FT_DISPLAYWIDTH/10 et y0 vaut FT_DISPLAYHEIGHT/10.
Je ne connais pas ta bibliothèque, donc les autres paramètres, je ne sais pas ce qu'ils font, surtout le 29...

EDIT : en cherchant, je trouve ceci, où il est dit page 18 que le 29 est la taille de la police.

Ce point est souvent le point en haut à gauche de ton texte, mais vu l'option FT_OPT_CENTER, ça peut aussi bien être le point central.
Il te faut évaluer le nombre de pixels en largeur et en hauteur de ton texte : disons dx, dy. Ces nombres dépendent du texte et de la police utilisée. Si tu as une police taille 29, il est probable que dy vaudra 29. dx, ça dépend du texte (nombre de caractères, espaces, etc). Un peu de lecture intéressante.

Une fois que tu as évalué dx et dy, il te reste à tester si le point cliqué est dans le rectangle. Si les coordonnées du point sont x, y, il faut faire un test du genre (pour le cas où le texte est centré sur x0, y0) :

int xmin = x0 - dx/2;
int xmax = xmin + dx;
int ymin = y0 - dy/2;
int ymax = ymin + dy;
if (xmin < x && x < xmax && ymin < y && y < ymax) {
  // bravo : tu as cliqué dans le rectangle !!
}

Merci beaucoup pour ta réponse très précise et documentée.

J'ai l'impression de ne pas pouvoir faire ce que je souhaite :
L'idée, c'est d'avoir un menu en haut de l'écran, de ce type :

Animal - Véhicule - Taille - Couleur - ...

Lorsque je clique sur "Véhicule", par exemple, le programme affiche, au milieu de l'écran : "Land Rover", et "Land Rover" reste affiché jusqu'à ce que je clique sur un autre item du menu.

Je ne comprends pas la structure du programme pour arriver à un résultat tel que celui-ci. Pour le moment, j'ai quelque-chose de ce type :

while(1)
Afficher le menu en haut de l'écran (OK)
Récupérer les coordonnées du point cliqué (OK)
Vérifier où tombent les coordonnées, et en fonction, afficher la "réponse" ("Land Rover") (OK)

Le problème résiduel est que quand je retire le doigt de l'écran, la réponse disparait.

J'ai essayé de rajouter un delay(2000), par exemple, pour que le texte reste affiché, mais cela ne semble pas fonctionner (sorte de bug : je dois rester appuyé 2000ms sur l'item du menu pour qu'il affiche la réponse).

Comment faire pour que quand je clique sur un item, la réponse reste, jusqu'à ce que j'appuie sur un autre item, avec une autre réponse, etc...

Merci par avance,
t_t29

Bonsoir
il faut lire un tuto sur les menus pour te permettre de mieux comprendre et débroussailler le terrain.

Oui. Dans ton cas, il s'agit par exempte de repérer un clic dans un espace en haut de l'écran. Je te suggère de faire des cases de dimensions égales, dans lesquelles tu mets tes textes.

Si les cases sont entre 0 et 30 en y et de largeur 50 (par exemple) en x, il est facile de repérer un clic et de savoir dans quelle case il était.

Merci bien.

Il y a donc obligation de passer par les menus pour réaliser ce que je souhaite faire ?

Aucune solution "directe" ?
Je suis proche de mon objectif, le seul soucis étant que le texte disparait à la relâche du clic sur le texte.

D'autres avis ?
Merci beaucoup,

t_t29

Il faut voir le code pour pouvoir te répondre

Hello,

Voici à quoi ressemble le code, je me suis inspiré des exemples "Touch" et "HelloWorld" de la librairie :

/* Arduino standard includes */
#include "SPI.h"
#include "Wire.h"

/* Platform specific includes */
#include "FT_NHD_43CTP_SHIELD.h"

/* Global object for FT801 Implementation */
FT801IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

/* Api to bootup FT801, verify FT801 hardware and configure display/audio pins */
/* Returns 0 in case of success and 1 in case of failure */
int16_t BootupConfigure()
{
  uint32_t chipid = 0;
  FTImpl.Init(FT_DISPLAY_RESOLUTION);//configure the display to the WQVGA

  delay(20);//for safer side
  chipid = FTImpl.Read32(FT_ROM_CHIPID);
  
  /* Identify the chip */
  if(FT801_CHIPID != chipid)
  {
    Serial.print("Error in chip id read ");
    Serial.println(chipid,HEX);
    return 1;
  }
  
  /* Set the Display & audio pins */
  FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);
  FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN); 
      FTImpl.DisplayOn();   
  FTImpl.AudioOn();     
  return 0;
}

/* Helper API to convert decimal to ascii - pSrc shall contain NULL terminated string */
int32_t Dec2Ascii(char *pSrc,int32_t value)
{
  int16_t Length;
  char *pdst,charval;
  int32_t CurrVal = value,tmpval,i;
  char tmparray[16],idx = 0;//assumed that output string will not exceed 16 characters including null terminated character

  //get the length of the string
  Length = strlen(pSrc);
  pdst = pSrc + Length;
  
  //cross check whether 0 is sent
  if(0 == value)
  {
    *pdst++ = '0';
    *pdst++ = '\0';
    return 0;
  }
  
  //handling of -ve number
  if(CurrVal < 0)
  {
    *pdst++ = '-';
    CurrVal = - CurrVal;
  }
  /* insert the digits */
  while(CurrVal > 0){
    tmpval = CurrVal;
    CurrVal /= 10;
    tmpval = tmpval - CurrVal*10;
    charval = '0' + tmpval;
    tmparray[idx++] = charval;
  }

  //flip the digits for the normal order
  for(i=0;i<idx;i++)
  {
    *pdst++ = tmparray[idx - i - 1];
  }
  *pdst++ = '\0';

  return 0;
}

/* API to display Hello World string on the screen */
void Slide()
{  
  int32_t  wbutton,hbutton,tagval,tagoption;
  char StringArray[100],StringArray1[100];
  uint32_t ReadWord;
  int16_t xvalue,yvalue,pendown;
  sCTouchXY cTouchXY;

  wbutton = FT_DISPLAYWIDTH/8;
  hbutton = FT_DISPLAYHEIGHT/8;
  FTImpl.SetCTouchMode(FT_CTOUCH_MODE_EXTENDED);  //set mode to extended for FT801

  /* Change the below string for experimentation */
  const char Display_string[12] = "Animal";
  const char Display_string1[12] = "Véhicule";
  const char Display_string2[12] = "Taille";
 
  while(1)
  {
    /* Read the touch screen xy and tag from GetCTouchXY API */
    FTImpl.GetCTouchXY(cTouchXY);
    /* Construct a screen shot with grey color as background, check constantly the touch registers,
       form the infromative string for the coordinates of the touch, check for tag */      
//    FTImpl.DLStart(); //start the display list. Note DLStart and DLEnd are helper apis, Cmd_DLStart() and Display() can also be utilized.
//    FTImpl.ClearColorRGB(64,64,64);  
//    FTImpl.Clear(1,1,1);    //clear color component
//    FTImpl.ColorRGB(0xff,0xff,0xff);
    FTImpl.TagMask(0);

/* Display list to display "Hello World" at the centre of display area */
    FTImpl.DLStart();//start the display list. Note DLStart and DLEnd are helper apis, Cmd_DLStart() and Display() can also be utilized.
    FTImpl.ColorRGB(0x33,0xFF,0x00);//set the color of the string to yellow/green color
  
    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/10, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string);//display "Hello World at the center of the screen using inbuilt font handle 29 "
    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/9.5, FT_DISPLAYHEIGHT/4, 29, FT_OPT_CENTER, Display_string1);//display "Hello World at the center of the screen using inbuilt font handle 29 "
    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/3.6, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string2);//display "Hello World at the center of the screen using inbuilt font handle 29 "
    
    yvalue = cTouchXY.y0;
    xvalue = cTouchXY.x0;

    if (xvalue > 300 && (yvalue > 60 && yvalue < 90)){
      FTImpl.Cmd_Text(FT_DISPLAYWIDTH/2, FT_DISPLAYHEIGHT/1.7, 31, FT_OPT_CENTER, "Chat");
    }
    if (xvalue > 310 && (yvalue > 0 && yvalue < 60)){
      FTImpl.Cmd_Text(FT_DISPLAYWIDTH/2, FT_DISPLAYHEIGHT/1.7, 31, FT_OPT_CENTER, « Land Rover");
    }
    if ((xvalue > 120 && xvalue < 300) && (yvalue > 60 && yvalue < 90)){
      FTImpl.Cmd_Text(FT_DISPLAYWIDTH/2, FT_DISPLAYHEIGHT/1.7, 31, FT_OPT_CENTER, "182cm");
    }

    FTImpl.DLEnd();
    FTImpl.Finish();
  } 
}

void setup()
{
  /* Initialize serial print related functionality */
  Serial.begin(9600);
  
  /* Set the Display Enable pin*/   
  Serial.println("--Start Application--");
  if(BootupConfigure())
  {
    //error case - do not do any thing
  }
    else
  {
    Slide();
  }
  Serial.println("--End Application--");
}

/* Nothing in loop api */
void loop()
{
}

Le comportement est le suivant :

Lorsque j'appuie sur la zone "Véhicule", le texte "Land Rover" s'affiche à l'écran, mais disparaît si je relâche, alors que j'aimerai qu'il reste en place, jusqu'à ce que j'appuie sur un autre item (par exemple "Taille", qui devra afficher "182cm").

pourquoi n'affichez vous pas une fois pour toute dans le setup les 3 textes et ensuite dans la loop vous vérifiez s'il y a un hit sur l'écran ? on dirait qu'il y a des tonnes de code inutile dans ce que vous avez posté...

La fonction Dec2Ascii en effet ne sert pas dans ce code.

Mais je ne comprends pas la différence entre votre proposition et ce que j'ai fait.
J'ai essayé votre méthode, sans succès pour le moment, je me trompe certainement.

Bien à vous,
t_t29

t_t29:
Mais je ne comprends pas la différence entre votre proposition et ce que j'ai fait.

vous affichez constamment le menu

    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/10, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string);//display "Hello World at the center of the screen using inbuilt font handle 29 "
    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/9.5, FT_DISPLAYHEIGHT/4, 29, FT_OPT_CENTER, Display_string1);//display "Hello World at the center of the screen using inbuilt font handle 29 "
    FTImpl.Cmd_Text(FT_DISPLAYWIDTH/3.6, FT_DISPLAYHEIGHT/10, 29, FT_OPT_CENTER, Display_string2);//display "Hello World at the center of the screen using inbuilt font handle 29 "

Si vous n'effacez pas l'écran il n'y a aucune raison de le faire en permanence.

donc dans le setup() vous affichez ces 3 lignes
dans la loop vous testez si un point a été touché dans une des 3 zones active et si oui vous effacez l'ancien texte au centre de l'écran (pas tout l'écran) et affichez le nouveau texte

ça sert à quoi ce truc ? FTImpl.TagMask(0);

Cette bibliothèque graphique est très peu documentée, donc pas facile d'aider. :confused:

Je pense que ton problème vient de ces lignes :

   FTImpl.DLEnd();
   FTImpl.Finish();

L'une d'elles doit effacer l'écran. Essaye en commentant l'une, puis l'autre, puis les deux...

j'ai l'impression que la bibliothèque est capable des gérer des widgets directement et a sa propre boucle d'interaction peut être.... Ne disposant pas de cet écran j'ai eu la flemme de lire les 50 pages de cette doc qui semble très mal faite....

Si je commente la première ligne, plus rien ne s'affiche à l'écran, à aucun moment.
Si je commente la deuxième ligne, l'écran est "moins réactif", le texte met plus de temps à s'afficher quand je clique, et à disparaitre quand je relâche.

Si je commente les deux lignes, plus rien ne s'affiche non plus.

Merci beaucoup,
t_t29

Bonjour,

j'ai effectué plusieurs essais en déplaçant les fonctions FTImpl.DLEnd() et FTImpl.Finish() à différents endroits du code, mais sans succès.
J'ai également essayé de rajouter une temporisation de 4s grâce à la fonction delay() après avoir affiché le texte suite au clic sur le bouton, mais sans succès non plus.

Je sèche.
Quelqu'un aurait-il utilisé cette librairie auparavant et aurait une idée ?
Merci d'avance,
t_t29

Désolé - je n'ai pas ce genre d'écran... vous l'avez acheté où ?

Écran acheté chez Mou*er, mais il y a -beaucoup- de références compatibles un peu partout, dans toutes les tailles, de 1 pouce et quelques à plus de 7 pouces...