Return nothing with class method

Hello!

I was trying to write a method, inside of my class, called Display. I wanted it to return values, only if istouched() is true. I always get 0, if the boolean value is false though. Is there any way to only get my return values when istouched() == true?

int Display::getPoints()
{
  if (ts.touched())
  {
    TS_Point p = ts.getPoint(); // point getter function
    _x = map(p.x, 340, 3900, 0, 320);
    _y = map(p.y, 200, 3850, 240, 0);

    /*Serial.print("X:");
    Serial.print(_x);
    Serial.println();
    Serial.print("Y:");
    Serial.print(_y);
    Serial.println(); */
    return _x;
    // return _y;
  }

  else
  {
    
  }
}

You have no “return” in your else clause.

There is no such thing as a conditional return value in C++ (AFAIK). You can certainly return some value that indicates that the returned (or passed by pointer or reference) value is valid. Then you can handle it appropriately in the code that called the function, or ignore it. In "the old days" it was common to return -1 for an invalid result, a positive integer for a valid result. Some of those are still around.

Thank you for your fast answers! I just wanted to have a function which only returns values if ts.touched is true. It's for the ILI9341 TFT Touch Screen and if I get zeros all the time it throw backs my cursor to the coordinate 0 what I don't want..

There is nothing wrong with using the general method in the code in the original post. It is safe and versatile. But, you need to back the press check out of the method, it doesn't belong there. There is always some place where you must make the check. Returning it doesn't help, you still need to check it. What would you do if it "doesn't return a value"? It's the same as not asking for one. So it's a waste of time, and adds a layer of obfuscation. If you like, you can encapsulate 'ts.touched()' in a wrapper method of your class, which you would call before calling 'getPoints()', in the function that calls it.

Just my CAD$0.02.

Why not default to sending back a -1 as a flag to not moive the curser?

-jim lee

jimLee: Why not default to sending back a -1 as a flag to not moive the curser?

-jim lee

You can but it's futile. You have to either test for the return == -1, or test for 'ts.touched() == false'. There is no way to gain efficiency here, it's more about making intuitive and "obvious" code.

Encapsulation is to hide things you don't need to know about the object. This is an attempt to hide something you do need to know. Codifying the availability of data, is obfuscating it needlessly. It's misguided.

The main program presumably needs to know whether data is available or not. It's far cleaner to just have it test right there, instead of burying it in a method.

Consider how Serial.available() and Serial.read() work together...

Hey guys, thank you for your answers! aarg what exactly do you mean by " you need to back the press check out of the method, it doesn't belong there. " ? Could you maybe explain it to me by using my code snippet?

I guess something like this:

. . .
Display myDisplayObj ;
. . .
void loop() {
. . .
  if ( ts.touched ) {
     TS_Point touchedPoint = myDisplayObj.getPoints() ;  // or maybe some data type other than TS_Point
     // do something with the touched point
  } 

. . .
}

or similar where the function getPoints() is called only when the screen has been touched.

However, you have another problem. You are calculating 2 translated XY values in getPoints(). How are you going to "pack" these two values into one value returned to the calling routine ? You can use a struct etc. (compound data type) or you can pass references in the argument list which your routine uses to set values which are visible in the calling routine.

I can’t use my ts.touched in my main code though because its inside my class. Sorry, Im pretty new to OOP, so I am not sure how to do it yet.

Display.h

#ifndef Display_h
#define Display_h
#include "Arduino.h"
#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>

/* extern XPT2046_Touchscreen ts; // declare the existence of global variable
#define TIRQ_PIN 2
extern ILI9341_t3 tft; // declare the existence of global variable */

class Display
{
public:
    Display();
    int getPoints();
    void clear();
    void drawButtons();
    void start();
    boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH);

private:
    XPT2046_Touchscreen ts;
    ILI9341_t3 tft;
    boolean istouched;
    int _x;
    int _y;
    int _heightSquare = 20;
    int _widthSquare = 75;
};

#endif

Display.cpp

#include "Arduino.h"
#include "Display.h"

// XPT2046_Touchscreen ts(CS_PIN); // Instanziierung eines ts Objekts der Klasse XPT2046_Touchscreen
// ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
#define TIRQ_PIN 2
#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

Display::Display() : ts(CS_PIN), tft(TFT_CS, TFT_DC)
{

}

// Original raw minimum and maximum values:
// X --> 340 bis 3900 
// Y --> 200 bis 3850

int Display::getPoints()
{
  if (ts.touched())
  {
    TS_Point p = ts.getPoint(); // point getter function
    _x = map(p.x, 340, 3900, 320, 0);
    _y = map(p.y, 200, 3850, 240, 0);

    Serial.print("X:");
    Serial.print(_x);
    Serial.println();
    Serial.print("Y:");
    Serial.print(_y);
    Serial.println(); 
    return _x;
    // return _y;
  }

  else
  {
    
  }
}

void Display::drawButtons()
{
  tft.fillRoundRect(0, 220, _widthSquare, _heightSquare, 3, CL(255, 0, 0));
}

void Display::clear()
{
  tft.fillScreen(ILI9341_GREENYELLOW);
  drawButtons();
}

void Display::start()
{
  Serial.begin(38600);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_GREENYELLOW);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000))
    ; // weiß nicht was das ist
}

boolean Display::pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

Main Code (Taschenrechner)

#include "Arduino.h"
#include "Arithmetik.h"
#include "Display.h"

Arithmetik arithmetik(10, 2);
Display display;

void setup()
{
  display.start();
  display.clear();
  display.drawButtons();
  ts.touched();
}



void loop()
{
    display.getPoints();

}

You could move “istouched” to public, but (much) better would be to create a getter method for the variable.

Ultimately, you will have to have something in the loop() which reacts when a button has been pressed on the calculator. It has to identify the button and do something depending on the current state, say adding a new digit to the display. You'll have to reset it afterwards so you don't see it again on the next loop iteration. So you have to expose the variable somehow. The suggestions by @TheMemberFormerlyKnownAsAWOL seem good.

You may find, however, that you are burying the ts object too deeply and need anyway to have it as a global. You'll soon see anyway.

I tried to replace my boolean member variable istouched with the ts.touched() from the ts library. For some reason though, if I try to use it in my if statement inside the .cpp file, I don’t get any response from the touchscreen…

Main Code (taschenrechner)

#include "Arduino.h"
#include "Arithmetik.h"
#include "Display.h"

Arithmetik arithmetik(10, 2);
Display display;


void setup()
{
  display.start();
  display.clear();
  display.drawButtons();
}



void loop()
{
    display.getPoints();
   // Serial.println(display.istouched);


}

Display.cpp

#include "Arduino.h"
#include "Display.h"

// XPT2046_Touchscreen ts(CS_PIN); // Instanziierung eines ts Objekts der Klasse XPT2046_Touchscreen
// ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
#define TIRQ_PIN 2
#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

Display::Display() : ts(CS_PIN), tft(TFT_CS, TFT_DC)
{
}

// Original raw minimum and maximum values:
// X --> 340 bis 3900
// Y --> 200 bis 3850

int Display::getPoints()
{
  // istouched = ts.touched();
  if (istouched)
  {
    TS_Point p = ts.getPoint(); // point getter function
    _x = map(p.x, 340, 3900, 320, 0);
    _y = map(p.y, 200, 3850, 240, 0);

    Serial.print("X:");
    Serial.print(_x);
    Serial.println();
    Serial.print("Y:");
    Serial.print(_y);
    Serial.println();
    return _x;
    // return _y;
  }

  else
  {
  }
}

void Display::drawButtons()
{

  for (int i{0}; i < 4; ++i)
  {
    tft.fillRoundRect(_gap + (_gap + _widthSquare) * i, 220, _widthSquare, _heightSquare, 3, CL(150, 100, 70));
  }
}

void Display::clear()
{
  tft.fillScreen(ILI9341_BLACK);
  drawButtons();
}

void Display::start()
{
  Serial.begin(38600);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000))
    ; // weiß nicht was das ist
}

boolean Display::pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

Display.h

#ifndef Display_h
#define Display_h
#include "Arduino.h"
#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>

/* extern XPT2046_Touchscreen ts; // declare the existence of global variable
#define TIRQ_PIN 2
extern ILI9341_t3 tft; // declare the existence of global variable */

class Display
{
public:
    Display();
    int getPoints();
    void clear();
    void drawButtons();
    void start();
    boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH);
    boolean istouched = ts.touched();

private:
    XPT2046_Touchscreen ts;
    ILI9341_t3 tft;
    int _x;
    int _y;
    int _heightSquare = 20;
    int _widthSquare = 75;
    int _gap = 4;
};

#endif

The thing is, if I try to use:

  if (display.istouched)
  {
    display.getPoints();
  }

to get my screen values, it only works if display.istouched is already initialized before using display.getPoints. For some reason though, I cant initialize it outside the getPoints() method. :confused:

That's why 'istouched' should be a method, so it will be updated...

back in post #12 you have this in the initialisation of an instance variable in class Display (Display.h).

boolean istouched = ts.touched() ;

That is not going to work there. You have to, somehow, regularly call ts.touched() to set this variable istouched. You do this maybe indirectly from the loop() or, possibly, from an interrupt which the screen generates when it registers a touch.

That's what I did and it seems to work! Is it a "proper" way of doing it? If so, thank you for all the help guys, if not, correct me! :)

boolean Display::isTouched()
{
  touched = ts.touched();

}

And in the main code:

void loop()
{
  if ((millis() - lastMillis) > millisIntervall)
  {
    if (display.isTouched())
    {
      display.getPoints();
    }
    lastMillis = millis();
  }
}

Are we talking about class, or a function..method here. Just define the.......................

Well, it looks good and if it works, even better. Somewhere, now, on the basis if the coordinates returned, you have to identify which button was pressed.

Looks good to me.