Пакка, сразу несколько рекомендаций:
1) Если ты вводишь какую-то целочисленную переменную, которая не может быть отрицательной - всегда пиши в названии слово
unsigned. Например, "индекс массива" всегда неотрицателен, поэтому его следует объявлять как
unsigned int. И поверь, это ничуть не излишество.
Представь, что у тебя есть такой фрагмент кода:
bool array[10];
int index = -3;
array[index] = true;
Этот код, как видно, содержит ошибку: в нём "минус третьему" элементу массива присваивается какое-то значение. Но, как это ни странно, в большинстве случаев такой код нормально скомпилируется в экзешник! Ошибка либо будет замечена лишь во время самой работы программы, либо будет не замечена вообще: а что, поменяли
*(array + index) участок памяти, делов-то
И это очень плохо, когда какую-то ошибку приходится подолгу выискивать... Теперь давай добавим перед
int слово
unsigned:
bool array[10];
unsigned int index = -3;
array[index] = true;
Этот код, напротив, даже не скомпилируется - нормальные компиляторы
(к которым Борландовский продукт, кстати, не относится) не допустят программу к исполнению, а выведут ошибку:
"Присвоение беззнаковой переменной знакового значения". Всё! Ошибка
уже замечена, время сэкономлено. Есть разница, верно?
2) Если ты уверен, что твоя переменная не может принимать каких-то "больших" значений - то не стоит объявлять её тип как
int, лучше пользуйся
short int (диапазон из 2
16 значений) или даже
char (диапазон из 2
8 значений). Это позволяет экономить оперативную память, поскольку значения таких типов занимают в ней меньше места - особенно, если они составляют собой массив.
3) Никогда не используй нумерацию каких-либо элементов
(массива, списка, STL-контейнера) с единицы, как в строке 6 твоего кода. Только с нуля! Это часто может привести к ошибке исполнения - особенно, если приходится работать непосредственно с памятью (через указатели). Вот, кстати, за что мне ещё не нравится Borland VCL - в ней нумерация букв в
String-овой строке идёт именно с единицы, прям как в Паскале каком-то. Хорошо хоть,
std::string мне никто пользоваться не запрещает
4) Если какая-то последовательность действий представляет собой логический блок, то есть ты можешь выделить его в какую-то функцию - то выделяй. Например,
"заполнение массива bh случайными числами" - это и есть логический блок, и поэтому его лучше вынести в отдельную функцию. Плюс такого решения в том, что если тебе понадобилось обратиться к такому "блоку" снова - ты просто вызываешь функцию снова, а не тупо копипастишь код.
Более того, подобные функции нужно стараться делать как можно более "универсальными". Например, для вышеуказанного примера - чтобы функция
"заполнения массива случайными числами" могла работать не только с массивом
bh, а с любым массивом вообще. Это избавит тебя от необходимости написания новых функций для каждого массива - поскольку "универсальная" функция для подобных целей у тебя уже есть. Правда, при работе с массивами возникают сложности, связанные с тем, что для корректной работы с ними сторонних функций, необходимо каждый раз указывать размер массива. В связи с этим, возникает пятый пункт.
5) Вообще не используй статические массивы ("обычные"), а юзай динамические. Лучше всего -
std::vector, он наиболее прост для понимания, плюс совместим с С-шными функциями, работающими со статическими массивами. У динамических массивов его размер всегда хранится "внутри" массива, плюс его
(размер) в любой момент можно изменить (со статическим такой фокус не пройдёт).
Теперь ещё раз посмотри в мой код. Он всё ещё кажется тебе таким сложным? Давай я его объясню.
Первые три строки - это объявление динамического массива, о которых я говорил выше. Первая строка подключает библиотечный файл для работы с ними (её нужно писать лишь один раз внутри всего проекта). Типом "динамический массив" здесь является
std::vector, а в фигурных скобках указан тип его элементов (например,
"динамический массив элементов типа int" описывается как
std::vector<int>). Но так как массив у нас двумерный, то в фигурных скобках записан "он сам". Надеюсь, теперь понятно, откуда взялась запись
std::vector< std::vector<unsigned short> > ? Но так как всё время писать такую длинную конструкцию не очень красиво, то с помощью служебной команды
typedef мы вводим для этой конструкции слово-синоним
TMatrix (учти, что эта команда работает лишь с
типами, это тебе не
#define). Наконец, в третьей строке мы вводим сам динамический массив
bh на основе только что созданного типа
TMatrix.
Потом я объявляю две строковые константы.
EXE_PATH - это просто путь к папке, где хранится экзешник твоей программы. Далее, функция
GenerateMatrix заполняет твой массив
bh случайными числами. Обрати внимание, что параметр "input" передаётся в неё по ссылке - таким образом, эту функцию можно использовать для любого массива, имеющего тип
TMatrix - а не только для
bh. Если что, в ней
resize(...) - изменяет размер динамического массива. Всё остальное, думаю, понятно.
Функция
DrawingMatrix рисует матрицу из Label-ов, как на скриншоте в твоём сообщении №40. Она работает по такому принципу: вначале она ищет Label-ы с именами вида
"Label_i_j" (где i и j меняются) на форме
form, и если не находит какие-то из них - то она их создаёт. После этого, она меняет их заголовок на нужное "число", взятое из массива
input (в данном случае, массива
bh). Текущий Label всегда хранится в указателе
current, указывающем на только что найденный Label. Его поиск производится в этой строчке:
TLabel* current = dynamic_cast<TLabel*>(form->FindComponent(name));
Что она означает? Смотри справа налево.
FindComponent - это метод формы
form, который ищет компонент на этой форме по его имени (переменная
name). Этот метод возвращает значение типа
*TComponent, то есть указатель на тип TComponent. Для того, чтобы работать с ним, как с Label-ом, этот указатель нужно привести к типу
*TLabel - то есть нужно сделать так, чтобы он указывал именно на Label. Для этого вызывается шаблонная функция
dynamic_cast<TLabel*>(...) (то бишь, сама функция называется "dynamic_cast", а в
фигурных скобках записан новый тип параметра, к которому и будет приводить указатель, записанный в
круглых скобках). После всего этого, справа от знака равенства у нас будет указатель на TLabel, который и можно присвоить переменной
current. Остальное просто.
Наконец, функция
DrawingSquares создаёт/изменяет картинки (TImage), подгружая в них информацию из соответствующих файлов. Загрузка содержимого картинки из файла "обёрнута" в конструкцию
try-catch - это блок "обработки исключений" в C++ (поскольку файл может отсутствовать, и тогда функция
LoadFromFile сгенерирует исключение, которое и будет поймано
catch). Всё остальное в ней аналогично предыдущей функции. Все эти три функции вызываются в самом низу, в обработчике нажатия кнопки
Button1.
P.S. Надеюсь, что не зря распинался