








// Arduino_GFX_Button.h
#ifndef _Arduino_GFX_Button_H_
#define _Arduino_GFX_Button_H_
#include <Arduino.h>
#include <Arduino_GFX.h> // 変更: TFT_eSPIからArduino_GFXに変更
class Arduino_GFX_Button {
public:
Arduino_GFX_Button(void);
void initButton(Arduino_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
uint16_t outline, uint16_t fill, uint16_t textcolor,
char *label, uint8_t textsize);
void drawButton(bool inverted = false);
bool contains(int16_t x, int16_t y);
void press(bool p);
bool isPressed();
bool justPressed();
bool justReleased();
private:
Arduino_GFX *_gfx; // 変更: TFT_eSPI*からArduino_GFX*に変更
int16_t _x, _y;
uint16_t _w, _h;
uint8_t _textsize;
uint16_t _outlinecolor, _fillcolor, _textcolor;
char _label[10];
bool currstate, laststate;
};
#endif
// Arduino_GFX_Button.cpp
#include "Arduino_GFX_Button.h"
Arduino_GFX_Button::Arduino_GFX_Button(void) {
_gfx = nullptr;
_x = _y = _w = _h = 0;
_outlinecolor = _fillcolor = _textcolor = 0;
_textsize = 1;
_label[0] = 0;
currstate = laststate = false;
}
void Arduino_GFX_Button::initButton(Arduino_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
uint16_t outline, uint16_t fill, uint16_t textcolor,
char *label, uint8_t textsize) {
_gfx = gfx;
_x = x;
_y = y;
_w = w;
_h = h;
_outlinecolor = outline;
_fillcolor = fill;
_textcolor = textcolor;
_textsize = textsize;
strncpy(_label, label, 9);
_label[9] = 0;
}
void Arduino_GFX_Button::drawButton(bool inverted) {
uint16_t fill, outline, text;
if (!inverted) {
fill = _fillcolor;
outline = _outlinecolor;
text = _textcolor;
} else {
fill = _textcolor;
outline = _outlinecolor;
text = _fillcolor;
}
_gfx->fillRoundRect(_x - (_w / 2), _y - (_h / 2), _w, _h, 3, fill);
_gfx->drawRoundRect(_x - (_w / 2), _y - (_h / 2), _w, _h, 3, outline);
if (_label[0] != 0) {
_gfx->setTextColor(text);
_gfx->setTextSize(_textsize);
_gfx->setCursor(_x - strlen(_label) * 8 * _textsize, _y + 8 * _textsize);
// _gfx->setCursor(_x - strlen(_label) * 3 * _textsize, _y - 4 * _textsize);
_gfx->print(_label);
}
}
bool Arduino_GFX_Button::contains(int16_t x, int16_t y) {
return ((x >= _x - _w / 2) && (x < (_x + _w / 2)) &&
(y >= _y - _h / 2) && (y < (_y + _h / 2)));
}
void Arduino_GFX_Button::press(bool p) {
laststate = currstate;
currstate = p;
}
bool Arduino_GFX_Button::isPressed() {
return currstate;
}
bool Arduino_GFX_Button::justPressed() {
return (currstate && !laststate);
}
bool Arduino_GFX_Button::justReleased() {
return (!currstate && laststate);
}
//Keypad_Arduino_GFX.ino
//V2024/06/14 by JK1VCK
//blog URL:https://gijin77.blog.jp/archives/41161525.html
//Modified by JK1VCK
#include <Arduino_GFX_Library.h>
#include <XPT2046_Touchscreen.h>
#include "Arduino_GFX_Button.h" // 改良版のArduino_GFX_Buttonをインクルード
#include <gfxfont.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/FreeSansOblique12pt7b.h>
#include <Fonts/FreeSans18pt7b.h>
//フォント設定
#define LABEL1_FONT &FreeSansOblique12pt7b // Key label font 1
#define LABEL2_FONT &FreeSansBold12pt7b // Key label font 2
#define LABEL3_FONT &FreeSans18pt7b // Key label font 3
//タッチパネル XPT2046 ピン設定
#define TOUCH_XPT2046
#define TOUCH_XPT2046_SCK 18
#define TOUCH_XPT2046_MISO 19
#define TOUCH_XPT2046_MOSI 23
#define TOUCH_XPT2046_CS 21
#define TOUCH_XPT2046_INT -1
#define TOUCH_XPT2046_ROTATION 0
#define TOUCH_XPT2046_SAMPLES 50
// タッチパネルのキャリブレーションパラメータ
#define TOUCH_MIN_X 200
#define TOUCH_MAX_X 3900
#define TOUCH_MIN_Y 200
#define TOUCH_MAX_Y 3900
//Arduino_GFX 設定の開始(各端子に接続されたピン番号を指定する)
#define GFX_BL 32 //バックライトピン番号
Arduino_DataBus *bus = new Arduino_ESP32SPI(27 /* DC */, 14 /* CS */, 18 /* SCK */, 23 /* MOSI */,19 /* MISO */);
Arduino_GFX *gfx = new Arduino_ILI9341(bus, 33 /* RST */, 1 /* rotation */);
XPT2046_Touchscreen ts(TOUCH_XPT2046_CS, TOUCH_XPT2046_INT);
//キーパッドの開始位置、キーのサイズと間隔
#define KEY_X 40 // キーの中心位置
#define KEY_Y 96
#define KEY_W 62 // 幅 & 高さ
#define KEY_H 30
#define KEY_SPACING_X 18 // X & Y ギャップ
#define KEY_SPACING_Y 20
#define KEY_TEXTSIZE 1 //フォントサイズr
//数値表示用ボックスのサイズと位置
#define DISP_X 1
#define DISP_Y 10
#define DISP_W 238
#define DISP_H 50
#define DISP_TSIZE 3
#define DISP_TCOLOR CYAN
//数値の長さ、それを保存するためのバッファ、文字インデックス
#define NUM_LEN 12
char numberBuffer[NUM_LEN + 1] = "";
uint8_t numberIndex = 0;
//メッセージのステータス位置
#define STATUS_X 30
#define STATUS_Y 65
//キーパッド用に15個のキーを作成する
char keyLabel[15][5] = {"New", "Del", "Send", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "#" };
uint16_t keyColor[15] = {RED, DARKGREY, DARKGREEN,
BLUE, BLUE, BLUE,
BLUE, BLUE, BLUE,
BLUE, BLUE, BLUE,
BLUE, BLUE, BLUE
};
Arduino_GFX_Button key[15];
uint16_t t_x = 0, t_y = 0; // タッチ座標保存用
uint16_t b_x = 0, b_y = 0;
bool pressed;
//------------------------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
Serial.println("Arduino_GFX library KeyPad!");
pinMode(GFX_BL, OUTPUT); //LCD バックライト設定
digitalWrite(GFX_BL, HIGH);
gfx->begin(); //LCD 初期化
gfx->setRotation(0);
gfx->fillScreen(BLACK);
ts.begin(); //タッチパネル初期化
ts.setRotation(2); //タッチパネルの個体によりLCDと違う事がある(0->2)
gfx->fillRect(0, 0, 240, 320, DARKGREY); // keypad background 描画
gfx->fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, BLACK); // 表示エリアとフレーム描画
gfx->drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, WHITE);
drawKeypad(); // keypad 描画
}
//------------------------------------------------------------------------------------------
void loop(void) {
if (ts.touched()) {
TS_Point p = ts.getPoint(); // タッチ座標の取得
t_x = map(p.x, TOUCH_MIN_X, TOUCH_MAX_X, 0, 240); // タッチ座標をスクリーン座標に変換
t_y = map(p.y, TOUCH_MIN_Y, TOUCH_MAX_Y, 0, 320);
if (!((b_x==t_x)&&(b_y==t_y))) {
Serial.printf("X=%4d Y=%4d \n",t_x,t_y); //デバッグ用シリアル出力
b_x=t_x;b_y=t_y;
}
pressed = true;
} else {
pressed = false;
}
//キー座標ボックスにタッチ座標が含まれているかどうかを確認します
for (uint8_t b = 0; b < 15; b++) {
if (pressed && key[b].contains(t_x, t_y)) {
key[b].press(true); //ボタンが押されたことを伝える
Serial.printf("b=%4d true\n",b);
} else {
key[b].press(false); //ボタンが押されていないことを伝える
}
}
//キーの状態が変化したかどうかを確認する
for (uint8_t b = 0; b < 15; b++) {
if (b < 3) gfx->setFont(LABEL1_FONT);
else gfx->setFont(LABEL2_FONT);
if (key[b].justReleased()) key[b].drawButton(); //通常描画
if (key[b].justPressed()) {
key[b].drawButton(true); //反転描画
//数字パッドボタンの場合は、関連する#を数字バッファに追加します。
if (b >= 3) {
if (numberIndex < NUM_LEN) {
numberBuffer[numberIndex] = keyLabel[b][0];
numberIndex++;
numberBuffer[numberIndex] = 0; //ゼロで終了
}
status(" "); // 古いステータスをクリアする
}
if (b == 1) { //Delボタンで最後の文字を削除する
numberBuffer[numberIndex] = 0;
if (numberIndex > 0) {
numberIndex--;
numberBuffer[numberIndex] = 0;
}
status(" "); // 古いステータスをクリアする
}
if (b == 2) {//Sentボタンでシリアルポートに値を送信する
status(" "); // 古いステータスをクリアする
status("Sent value to serial port");
Serial.println(numberBuffer);
}
if (b == 0) {//Newボタンで値をクリアする
status(" "); // 古いステータスをクリアする
status("Value cleared");
numberIndex = 0; //インデックスを0にリセット
numberBuffer[numberIndex] = 0; //バッファにnullにする
}
// 番号表示フィールドを更新する
gfx->setFont(LABEL3_FONT); //ボックスに合うフォントを選択する
gfx->setTextColor(DISP_TCOLOR);
//文字列を描画します。返される値はピクセル単位の幅です。
int xwidth = drawString(numberBuffer, DISP_X + 8, DISP_Y + 12,DISP_TSIZE);
//次に、黒い四角形を描いて、残りの部分を隠します。この方法でちらつきはありません
gfx->fillRect(DISP_X + 4 + xwidth, DISP_Y + 1, DISP_W - xwidth - 5, DISP_H - 2, BLACK);
delay(200);
}
}
}
//指定の位置に文字列を描画------------------------------------------------------------------
int drawString(char *str,int32_t posX, int32_t posY,int8_t t_size){
int width = 0;
gfx->setCursor(posX,posY);
gfx->setFont(0);
gfx->setTextSize(t_size);
gfx->print(str);
while (*str) {
width += 6 * t_size; // 標準フォントの幅(6ピクセル)にテキストサイズを掛ける
str++;
}
return width;
}
//キーパッドを描画--------------------------------------------------------------------------
void drawKeypad() {
for (uint8_t row = 0; row < 5; row++) {
for (uint8_t col = 0; col < 3; col++) {
uint8_t b = col + row * 3;
if (b < 3) gfx->setFont(LABEL1_FONT);
else gfx->setFont(LABEL2_FONT);
key[b].initButton(gfx, KEY_X + col * (KEY_W + KEY_SPACING_X),
KEY_Y + row * (KEY_H + KEY_SPACING_Y),
KEY_W, KEY_H, WHITE, keyColor[b], WHITE,
keyLabel[b], KEY_TEXTSIZE);
key[b].drawButton();
}
}
}
//ステータスバーにメッセージを描画----------------------------------------------------------
void status(char *msg) {
gfx->setCursor(STATUS_X, STATUS_Y);
gfx->setTextColor(WHITE, DARKGREY);
gfx->setFont(0);
drawString(msg, STATUS_X, STATUS_Y,1);
}