Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Marcussacapuces91/doc-TFT_eSPI/llms.txt

Use this file to discover all available pages before exploring further.

Once a button is on screen you need two things: a way to determine whether a touch coordinate landed inside the button, and a way to track when the button transitions between the pressed and released states. TFT_eSPI_Button bundles both capabilities together. The contains() method performs a simple bounding-rectangle hit test. The press() / isPressed() / justPressed() / justReleased() group maintains a two-frame state machine — current state and previous state — so you can detect the exact frame on which the button was first touched or first released, without any external debounce flags.

contains()

Returns true when the point (x, y) lies inside the button’s bounding rectangle.
bool TFT_eSPI_Button::contains(int16_t x, int16_t y);
x
int16_t
Horizontal coordinate of the point to test, in screen pixels — typically the x value returned by tft.getTouch().
y
int16_t
Vertical coordinate of the point to test, in screen pixels.
Returns booltrue if both x and y fall within the button rectangle; false otherwise.

press()

Feeds the current touch state into the button’s internal state machine. Call this every iteration of loop() with true when the button is being touched and false when it is not. Internally, the previous state is shifted into a history slot before the new state is recorded, enabling justPressed() and justReleased() to compare the two frames.
void TFT_eSPI_Button::press(bool p);
p
bool
Pass true if the button is currently being touched; false if it is not. Combine with contains() to derive this value: btn.press(btn.contains(tx, ty)).

isPressed()

Returns true if the button was marked as pressed in the most recent call to press().
bool TFT_eSPI_Button::isPressed();
Use this when you need to act continuously while a button is held down (e.g. incrementing a value at each loop tick).

justPressed()

Returns true only on the first loop iteration after the button transitions from released → pressed — i.e. the previous state was false and the current state is true.
bool TFT_eSPI_Button::justPressed();
This is the recommended method for triggering a one-shot action when a button is first touched, because it fires exactly once per touch regardless of how long the finger stays on screen.

justReleased()

Returns true only on the first loop iteration after the button transitions from pressed → released — i.e. the previous state was true and the current state is false.
bool TFT_eSPI_Button::justReleased();
Use this to confirm a completed tap, or to restore the button’s visual state after drawing it inverted.

State-machine pattern

The recommended pattern for every loop tick is:
  1. Read the touch controller.
  2. Call press() with the result of contains() (or false when there is no touch at all).
  3. Check justPressed() to fire one-shot actions on touch-down.
  4. Check justReleased() to fire one-shot actions on lift-off.
  5. Optionally check isPressed() for continuous held-down behaviour.
Always call press() once per loop iteration, even when there is no touch. Passing false is how the state machine learns the button has been released and arms justReleased() for the next frame.

Complete touch loop example

#include <TFT_eSPI.h>
#include <SPI.h>

TFT_eSPI      tft = TFT_eSPI();
TFT_eSPI_Button btnRed;
TFT_eSPI_Button btnGreen;

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  btnRed.initButton(&tft,
                    80, 120,
                    120, 48,
                    TFT_WHITE, TFT_RED, TFT_WHITE,
                    "RED", 2);
  btnRed.drawButton();

  btnGreen.initButton(&tft,
                      220, 120,
                      120, 48,
                      TFT_WHITE, TFT_DARKGREEN, TFT_WHITE,
                      "GREEN", 2);
  btnGreen.drawButton();
}

void loop() {
  uint16_t tx = 0, ty = 0;
  bool touched = tft.getTouch(&tx, &ty);

  // ---------- update press state for every button ----------
  btnRed.press(touched   && btnRed.contains(tx, ty));
  btnGreen.press(touched && btnGreen.contains(tx, ty));

  // ---------- RED button ----------
  if (btnRed.justPressed()) {
    // Visual feedback: draw inverted
    btnRed.drawButton(true);
    // One-shot action
    tft.fillRect(0, 0, tft.width(), 60, TFT_RED);
  }
  if (btnRed.justReleased()) {
    // Restore normal appearance
    btnRed.drawButton(false);
  }

  // ---------- GREEN button ----------
  if (btnGreen.justPressed()) {
    btnGreen.drawButton(true);
    tft.fillRect(0, 0, tft.width(), 60, TFT_DARKGREEN);
  }
  if (btnGreen.justReleased()) {
    btnGreen.drawButton(false);
  }

  // ---------- Continuous held-down action (optional) ----------
  if (btnRed.isPressed()) {
    // Called every loop tick while RED is held
    // e.g. slowly brighten a LED
  }

  delay(20); // ~50 Hz polling rate
}
When your sketch has several buttons, loop over an array of TFT_eSPI_Button pointers and call press() on each one before checking any state. This ensures all buttons see the same touch snapshot for that frame.
Do not call justPressed() or justReleased() more than once per loop iteration per button. Each call does not consume the edge — both methods simply compare current vs. previous state — but calling press() again mid-loop would overwrite the previous state and corrupt edge detection.

Build docs developers (and LLMs) love