As pointed out in a comment on your original question, a template is likely the best solution.
Templates allow you to write highly flexible code. I won't explain why; that's something that goes a little beyond the actual question. However, the following will show that you can create a template that means you can create a buttonArrayTFT
class with N number of buttonTFT
elements, so long as N is known at compile time. The link given as a comment talks describes various aspects of templates but does not necessarily explain how to string it all together.
From the section Non-type parameters for templates, you will see that you can specify an integer as a parameter for creating N elements of an array member variable.
But what about the type parameter, T? You can simply omit it. You don't actually have to create a template for a type.
In your .h file:
template <uint8_t ARRAY_SIZE>
class buttonArrayTFT
{
public:
// One thing to remember about templates: you have to pack the definition
// into the header file with the declaration to avoid all manner of headaches.
buttonArrayTFT(XPT2046_Touchscreen &_ts = ts, Adafruit_ILI9341 &_tft = tft)
{
// Perhaps this is a good opportunity to check that the specified
// size of the array is sensible, i.e. not zero and no more than 12.
if ((ARRAY_SIZE == 0) || (ARRAY_SIZE > 12))
{
// decide how you want to handle this problem
}
// Add the rest of your constructor here
}
void create_array(uint8_t R, uint8_t C, char *but_txt[]);
uint8_t checkPress(TS_Point &p);
// This little piece of magic allows you to access buttonTFT 'x' of the
// private _buttonArray as if a buttonArrayTFT class was an array
buttonTFT &operator[](uint8_t index)
{
// Check that 'index' is a valid element in the array
if (index > _num_items)
{
// decide how you want to handle this problem
}
return _buttonArray[index];
}
private:
buttonTFT _buttonArray [ARRAY_SIZE];
// I recommend making this constant
const uint8_t _num_items = ARRAY_SIZE;
};
I shall leave it up to you to sort out your privates, publics and protecteds, and I have left out ButtonTFT _button0;
to keep you on your toes.
You'll also notice that the array is private, as before, but there is now no array-of-pointers-to-buttons. This is because there is no need; the magic buttonTFT &operator[](int index)
allows you to access array elements directly.
In your .ino file, or as appropriate, you use the following code to create and then wield the class:
buttonArrayTFT<4> myFourButtonArray(/* constructor arguments as required*/);
buttonArrayTFT<12> myTwelveButtonArray(/* constructor arguments as required*/);
This gives you two instances of the class, with the respective number of buttonTFT
elements! You can now access specific buttons using the following code:
myFourButtonArray[0]; // Returns a reference to the first buttonTFT
myTwelveButtonArray[10]; // Returns a reference to the eleventh buttonTFT
myFourButtonArray[n] // Returns a reference to the 'n+1'th buttonTFT
On the assumption that the buttonTFT
class has some kind of 'read' function that returns a TRUE or FALSE for the status of the button, you can write:
if (myFourButtonArray[0].read())
{
// executed if the button is ON
}
else
{
// executed if the button is OFF
}
A NOTE ON CONST-NESS:
The overloading of operator[]
, while wonderfully magic, is open to abuse. However, this is no different from your original code. The array of buttonTFT
elements is private but there is public access to all the buttons almost as if the array was not private. In the case of your original code, one could write:
myButtonArray._buttons[0] = myButtonArray._buttons[1];
Now _buttons[0]
points to the same buttonTFT as _buttons[1]
.
Ouch. Now myButtonArray._buttons[0]->read()
is literally the same thing as myButtonArray._buttons[1]->read()
.
That said, my code does not make it a great deal better; the equivalent code:
myFourButtonArray[0] = myFourButtonArray[1];
Simply copies the right hand side over to the left hand side. You still have two distinct buttonTFT
instances, with probably no memory leaks, but I am guessing that buttonTFT
class may contain a reference to an Input pin, so the _button[0]
pin will now be whatever _button[1]
pin is because the member variable that stores the pin reference will be overwritten.
To solve this weakness, simply add the const
qualifier to the beginning of the operator[]
overload:
const buttonTFT &operator[](uint8_t index)
{ // };
Now the buttonTFT
element cannot be altered. This of course brings in a new headache that all functions that rely on myArray[n]
also need to be constant. It is up to you to determine how constant correctness should be interpreted and whether it is worth the hassle.