TFT_eSPI Issue with creating a class that does a "push to sprite" with a sprite outside the class

Hi everyone. I recently bought a T-Watch S3 and am currently trying to figure out how to program it. The idea is for it to display the time and date and communicate with a LoRa transceiver on my sailboat.

To do this I started with TFT_eSPI as I already have some experience with it.

I’m a novice in C++ and am currently writing my second class ever. I’d like to create a set of widgets classes that produce sprites for use in my watch.

To do this, I decided to start with a simple circle, just to see if I could get it to work. and I’m sorry to say I didn’t succeed.

main.ino:

#include "SPI.h"
#include "TFT_eSPI.h"
#include "widgettest.h"

TFT_eSPI tft = TFT_eSPI();

TFT_eSprite sprite = TFT_eSprite(&tft);
Testwidged widged = Testwidged(&sprite);

void setup(void) {
  tft.init();
  tft.setRotation(2);
  sprite.createSprite(240,240);
  sprite.fillScreen(TFT_BLACK);
  sprite.fillCircle(30,30,20,TFT_CYAN);
  widged.setsize(20,20);
  widged.setxy(60,60);
 
 

}

void loop() {
  widged.draw();

  sprite.pushSprite(0,0);

}

widgettest.h:

#ifndef WIDGETTEST_H
#define WIDGETTEST_H

#include "TFT_eSPI.h"


class Testwidged
{
    private:
    TFT_eSPI _tft;
    TFT_eSprite _widget ;
    TFT_eSprite *_basesprite;
    int _x;
    int _y;
    int _size_x;
    int _size_y;
    
    public:
    Testwidged(){}
    Testwidged( TFT_eSprite *basesprite);
    

    void init();
    void setxy(int x, int y);
    void setsize(int size_x, int size_y);
    void draw();
    
};


#endif //WIDGETTEST_H

widgettest.cpp:

#include "TFT_eSPI.h"
#include "widgettest.h"


Testwidged::Testwidged( TFT_eSprite *basesprite)
{
    _basesprite = basesprite;
}

void Testwidged::init()
{
    _tft = TFT_eSPI();
    _widget = TFT_eSprite(&_tft);
}
void Testwidged::setxy(int x, int y)
{
    _x = x;
    _y = y;
}
void Testwidged::setsize(int size_x, int size_y)
{
    _size_x = size_x;
    _size_y = size_y;
}

void Testwidged::draw()
{
    _widget.createSprite(_size_x,_size_y);
    _widget.fillScreen(TFT_BLACK);
    _widget.drawCircle(0,0,(_size_x/2)-2,TFT_RED);
    _widget.pushToSprite(_basesprite, _x, _y, TFT_BLACK);
   
}

output:

Processing twatch-s3 (platform: espressif32@6.3.0; framework: arduino; board: LilyGoWatch-S3)
-------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/LilyGoWatch-S3.html
PLATFORM: Espressif 32 (6.3.0) > LilyGo T-Watch S3 (16M Flash 8M OPI PSRAM )
HARDWARE: ESP32S3 240MHz, 320KB RAM, 16MB Flash
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES: 
 - framework-arduinoespressif32 @ 3.20009.0 (2.0.9) 
 - tool-esptoolpy @ 1.40501.0 (4.5.1) 
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 
 - toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
Converting main.ino
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 34 compatible libraries
Scanning dependencies...
Dependency Graph
|-- TFT_eSPI @ 2.5.43
|-- SPI @ 2.0.0
Building in release mode
Compiling .pio/build/twatch-s3/src/main.ino.cpp.o
Compiling .pio/build/twatch-s3/src/widgettest.cpp.o
In file included from src/widgettest.cpp:2:
src/widgettest.h: In constructor 'Testwidged::Testwidged()':
src/widgettest.h:19:17: error: no matching function for call to 'TFT_eSprite::TFT_eSprite()'
     Testwidged(){}
                 ^
In file included from .pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:1009,
                 from src/widgettest.cpp:1:
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note: candidate: 'TFT_eSprite::TFT_eSprite(TFT_eSPI*)'
   explicit TFT_eSprite(TFT_eSPI *tft);
            ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note:   candidate expects 1 argument, 0 provided
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note: candidate: 'TFT_eSprite::TFT_eSprite(const TFT_eSprite&)'
 class TFT_eSprite : public TFT_eSPI {
       ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note:   candidate expects 1 argument, 0 provided
src/widgettest.cpp: In constructor 'Testwidged::Testwidged(TFT_eSprite*)':
src/widgettest.cpp:5:48: error: no matching function for call to 'TFT_eSprite::TFT_eSprite()'
 Testwidged::Testwidged( TFT_eSprite *basesprite)
                                                ^
In file included from .pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:1009,
                 from src/widgettest.cpp:1:
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note: candidate: 'TFT_eSprite::TFT_eSprite(TFT_eSPI*)'
   explicit TFT_eSprite(TFT_eSPI *tft);
            ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note:   candidate expects 1 argument, 0 provided
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note: candidate: 'TFT_eSprite::TFT_eSprite(const TFT_eSprite&)'
 class TFT_eSprite : public TFT_eSPI {
       ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note:   candidate expects 1 argument, 0 provided
src/widgettest.cpp: In member function 'void Testwidged::init()':
src/widgettest.cpp:12:21: error: use of deleted function 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)'
     _tft = TFT_eSPI();
                     ^
In file included from src/widgettest.cpp:1:
.pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:427:7: note: 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)' is implicitly deleted because the default definition would be ill-formed:
 class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has access to protected members
       ^~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:427:7: error: non-static reference member 'fs::FS& TFT_eSPI::fontFS', can't use default assignment operator
src/widgettest.cpp:13:32: error: use of deleted function 'TFT_eSprite& TFT_eSprite::operator=(const TFT_eSprite&)'
     _widget = TFT_eSprite(&_tft);
                                ^
In file included from .pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:1009,
                 from src/widgettest.cpp:1:
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note: 'TFT_eSprite& TFT_eSprite::operator=(const TFT_eSprite&)' is implicitly deleted because the default definition would be ill-formed:
 class TFT_eSprite : public TFT_eSPI {
       ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: error: use of deleted function 'TFT_eSPI& TFT_eSPI::operator=(const TFT_eSPI&)'
In file included from src/widgettest.cpp:1:
.pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:427:7: note: 'TFT_eSPI& TFT_eSPI::operator=(const TFT_eSPI&)' is implicitly deleted because the default definition would be ill-formed:
 class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has access to protected members
       ^~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:427:7: error: non-static reference member 'fs::FS& TFT_eSPI::fontFS', can't use default assignment operator
In file included from /home/bert/Documents/PlatformIO/Projects/ygf/src/main.ino:5:
src/widgettest.h: In constructor 'Testwidged::Testwidged()':
src/widgettest.h:19:17: error: no matching function for call to 'TFT_eSprite::TFT_eSprite()'
     Testwidged(){}
                 ^
In file included from .pio/libdeps/twatch-s3/TFT_eSPI/TFT_eSPI.h:1009,
                 from /home/bert/Documents/PlatformIO/Projects/ygf/src/main.ino:4:
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note: candidate: 'TFT_eSprite::TFT_eSprite(TFT_eSPI*)'
   explicit TFT_eSprite(TFT_eSPI *tft);
            ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:12:12: note:   candidate expects 1 argument, 0 provided
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note: candidate: 'TFT_eSprite::TFT_eSprite(const TFT_eSprite&)'
 class TFT_eSprite : public TFT_eSPI {
       ^~~~~~~~~~~
.pio/libdeps/twatch-s3/TFT_eSPI/Extensions/Sprite.h:8:7: note:   candidate expects 1 argument, 0 provided
*** [.pio/build/twatch-s3/src/widgettest.cpp.o] Error 1
*** [.pio/build/twatch-s3/src/main.ino.cpp.o] Error 1
======================================================= [FAILED] Took 7.59 seconds =======================================================

 *  The terminal process "platformio 'run'" terminated with exit code: 1. 
 *  Terminal will be reused by tasks, press any key to close it. 

questions:

  1. is this a convenient / correct way to achieve this, or are there better ways.
  2. can someone point me in the right direction, and tell me what I’m doing wrong?

Replies are greatly appreciated. Kind regards, Bert

I figured it out myself,
main.ino:

#include "SPI.h"
#include "TFT_eSPI.h"
#include "Widget.h"


// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();

TFT_eSprite screen = TFT_eSprite(&tft);
Widget dot = Widget(&tft, &screen);
Widget dah = Widget(&tft, &screen);
void setup(void) {
  tft.init();
  tft.setRotation(2);
  screen.createSprite(240. 240);
  screen.fillSprite(TFT_GREEN);
  dah.init(70,20,30);
  dah.setcolor(255,0,0);
  dah.draw();
  dah.push();
  dot.init(20,20,20);
  dot.setcolor(0,0,200);
  dot.draw();
  dot.push();
 

}

void loop() {
  //widged.draw();

  screen.pushSprite(0,0);

}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

//Standard support
#include <Arduino.h>

#include <TFT_eSPI.h>


class Widget : public TFT_eSPI {

 private:
  TFT_eSPI *_tft;
  TFT_eSprite *_screen;
  TFT_eSprite _punt = TFT_eSprite(_tft);
  int _x = 0;
  int _y = 0;
  int _size = 10;
  int _color = TFT_BLUE;
  
public:
    //Widget() {} // do not use
    Widget(TFT_eSPI *tft, TFT_eSprite *screen);

    int init(int x, int y, int size);
    int setcolor(int r, int g, int b);
    void draw(void);
    void push(void);

    
};

#endif //WIDGET_H

widget.cpp:

#include "Widget.h"


Widget::Widget(TFT_eSPI *tft, TFT_eSprite *screen) {
  _tft = tft;
  _screen = screen;
}

int Widget::init(int x, int y, int size){
  _x = x;
  _y = y;
  _size = size;
  if(_size <0 || 240 < size) 
    return -1;

  return 0;
}


void Widget::draw(void){
  _punt.createSprite(50,50);
  _punt.fillScreen(TFT_BLACK);
  _punt.fillRect(0,0,_size,_size,_color);
}

void Widget::push(void){
  
  _punt.pushToSprite(_screen,_x,_y,TFT_BLACK);

}

int Widget::setcolor(int r, int g, int b){
  if (r < 0 || 255 < r || g < 0 || 255 < g || b < 0 || b > 255)
        return -1;

    int result;

    int red = r * 31 / 255;
    int green = g * 63/ 255;
    int blue = b * 31 / 255;


    //int result = (red << 11) | (green << 5) | blue;

    green = green << 5;
    red = red << 11;

    _color = red | green | blue;

    return 0;
}

I’m still playing around with it, but it works, and I’m quite proud of it.

and it will become the pattern on which I will base the next widgets. first a battery widgeted, digital clock widget, button widget ect

and if that looks good the next screen, probably a dashboard for the lights on board, navtext etc.

the question remains whether this is a good way to build your ui.

And replies on that question are greatly appreciated. Kind regards, Bert