Создание многоуровневого графического меню
- Войдите на сайт для отправки комментариев
Ср, 15/04/2020 - 11:03
Помогите допилить многоуровневое меню. Само меню работает, но с под меню не могу разобраться, как его реализовать. Код прилагаю
#include <SPI.h> // библиотека для работы SPI (дисплей) #include <TFT_eSPI.h> // библиотека дисплея #include "GyverEncoder.h" // библиотека энкодера #import "menu1.h" // иконка 1 пункта меню #import "menu2.h" // иконка 2 пункта меню #import "menu3.h" // иконка 3 пункта меню #import "menu4.h" // иконка 4 пункта меню #import "menu5.h" // иконка 5 пункта меню #import "menu6.h" // иконка 6 пункта меню #import "menu11.h" // иконка подменю 1 1 #import "menu12.h" // иконка подменю 1 2 // ---------------------------------------- МОДУЛЬ ДИСПЛЕЯ ----------------------------------------------------------- #define lightOFF 5 // пин подсветки дисплея uint16_t selectcolor = 0xFEC0; // цвет выделения пункта меню TFT_eSPI tft = TFT_eSPI(); // создаем объект tft TFT_eSprite timespriteON = TFT_eSprite(&tft); // создаем спрайт для обновления настройки времени включения освещения TFT_eSprite timespriteOFF = TFT_eSprite(&tft); // создаем спрайт для обновления настройки времени включения освещения TFT_eSprite luxspriteON = TFT_eSprite(&tft); // создаем спрайт для обновления настройки включения освещения по датчику освещенности TFT_eSprite luxspriteOFF = TFT_eSprite(&tft); // создаем спрайт для обновления настройки выключения освещения по датчику освещенности TFT_eSprite waterspriteONm = TFT_eSprite(&tft); TFT_eSprite waterspriteONHUMa = TFT_eSprite(&tft); TFT_eSprite waterspriteONa = TFT_eSprite(&tft); // ---------------------------------------- МОДУЛЬ ЭНКОДЕРА ----------------------------------------------------------- #define CLK 14 // пины энкодера #define DT 27 // пины энкодера #define SW 26 // пины энкодера Encoder enc1(CLK, DT, SW); // настраиваем пины энкодера byte menu =1; // обозначаем переменную пунктов меню byte menuu =1; //***************************************НАЧАЛО ПРОГРАММЫ*************************************************************** void setup () { enc1.setType(TYPE2); // устанавливаем тип энкодера enc1.setTickMode(AUTO); // устанавливаем режим энкодера AUTO tft.init(); // запускаем дисплей tft.setRotation(1); // поворачиваем изображение на дисплее tft.fillScreen(TFT_BLACK); // закрашиваем дисплей в черный цвет tft.setSwapBytes(true); updateMenu(); // выполняем меню } //-------------------------------------ЦИКЛИЧЕСКАЯ ЧАСТЬ ПРОГРАММЫ----------------------------------------------------------- void loop() { if (enc1.isRight()) { // если энкодер вправо menu++; // то выбираем следующий пункт меню ++ updateMenu(); // отрисовываем меню заново while (enc1.isRight()); } if (enc1.isLeft()) { // если энкодер влево menu--; // то выбираем предыдущий пункт меню -- updateMenu(); // отрисовываем меню заново while (enc1.isLeft()); } if (enc1.isPress()) { // при нажатии на энкодер включаем дисплей executeAction(); // переходим в блок выполнения updateMenu(); while (enc1.isPress()); } } //-------------------------------------------ФУНКЦИЯ ВЫДЕЛЕНИЯ ЭЛЕМЕНТА МЕНЮ-------------------------------------------------- void select (uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t selectcolor) { tft.drawRect(x0, y0, w, h, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга tft.drawRect(x0+1, y0+1, w-2, h-2, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга tft.drawRect(x0+2, y0+2, w-4, h-4, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга tft.drawRect(x0+3, y0+3, w-6, h-6, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга tft.drawRect(x0+4, y0+4, w-8, h-8, selectcolor); // делаем жирный квадрат из 5 квадратов вложенных друг в друга } //------------------------------------------------ ФУНКЦИЯ ОТРИСОВКИ МЕНЮ -------------------------------------------------- void updateMenu(){ switch (menu) { case 0: menu = 1; break; case 1: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(1, 8, 50,52, selectcolor); // выделяем 1 пунет меню break; case 2: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(56, 8, 50,52, selectcolor); // выделяем 2 пунет меню break; case 3: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(110, 8, 50,52, selectcolor); // выделяем 3 пунет меню break; case 4: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(1, 68, 50,52, selectcolor); // выделяем 4 пунет меню break; case 5: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(56, 68, 50,52, selectcolor); // выделяем 5 пунет меню break; case 6: tft.pushImage(1, 8, 50, 52, menu1); // 1й пункт меню tft.pushImage(56 ,8, 50, 52, menu2); // 2й пункт меню tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт меню tft.pushImage(1 ,68, 50, 52, menu4); // 4й пункт меню tft.pushImage(56 ,68, 50, 52, menu5); // 5й пункт меню tft.pushImage(110 ,68, 50, 52, menu6); // 6й пункт меню select(110, 68, 50,52, selectcolor); // выделяем 6 пунет меню break; case 7: menu = 6; break; } } //----------------------------------ПОДМЕНЮ 1-------------------------------------------------------- void submenu1(){ tft.fillScreen(TFT_BLACK); switch (menuu) { case 0: menuu = 1; break; case 1: tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю select(1, 8, 50,52, selectcolor); // выделяем 1 пунет подменю break; case 2: tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю select(56, 8, 50,52, selectcolor); // выделяем 2 пунет подменю break; case 3: tft.pushImage(1, 8, 50, 52, menu11); // 1й пункт подменю tft.pushImage(56 ,8, 50, 52, menu12); // 2й пункт подменю tft.pushImage(110 ,8, 50, 52, menu3); // 3й пункт подменю select(110, 8, 50,52, selectcolor); // выделяем 3 пунет подменю break; case 4: menuu = 3; break; if (enc1.isRight()) { // если энкодер вправо menuu++; // то выбираем следующий пункт подменю ++ submenu1(); // отрисовываем меню заново while (enc1.isRight()); } if (enc1.isLeft()) { // если энкодер влево menuu--; // то выбираем предыдущий пункт подменю -- submenu1(); // отрисовываем меню заново while (enc1.isLeft()); } if (enc1.isPress()) { // при нажатии на энкодер включаем дисплей // executeAction(); // переходим в блок выполнения tft.fillScreen(TFT_BLACK); tft.drawString("Execute sub 1 1",5,5); delay(5000); submenu1(); while (enc1.isPress()); } } } //*****************************БЛОК ВЫПОЛНЕНИЯ********************************************************* void executeAction() { // фунция выполнения пунктов меню switch (menu) { case 1: submenu1(); // переход в подменю 1 1 break; case 2: action2(); // выполнение 2го пункта меню break; case 3: action3(); // выполнение 3го пункта меню break; case 4: action4(); // выполнение 4го пункта меню break; case 5: action5(); // выполнение 5го пункта меню break; case 6: action6(); // выполнение 6го пункта меню break; } } // ********************************** БЛОКИ ИСПОЛНЕНИЯ ПУНКТОВ МЕНЮ ****************************************************** // ------------------------------------------ 1й Пункт меню -------------------------------------------------------------- void action1() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #1"); digitalWrite(13, HIGH); delay(2000); digitalWrite(13, LOW); tft.fillScreen(TFT_BLACK); } // ------------------------------------------ 2й Пункт меню -------------------------------------------------------------- void action2() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #2"); digitalWrite(13, HIGH); delay(2000); digitalWrite(13, LOW); tft.fillScreen(TFT_BLACK); } //------------------------------------------------------------------------------------------------------------------------------------ void action3() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #3"); digitalWrite(13, HIGH); delay(2000); digitalWrite(13, LOW); tft.fillScreen(TFT_BLACK); } void action4() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #4"); delay(2000); tft.fillScreen(TFT_BLACK); } void action5() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #5"); delay(2000); tft.fillScreen(TFT_BLACK); } void action6() { tft.fillScreen(TFT_BLACK); tft.setCursor (10, 10); tft.print(">Executing #6"); delay(2000); tft.fillScreen(TFT_BLACK); }
https://ibb.co/m8DrRs3
выглядит так. Проблема в том, что при переходе в под меню 1.1 программа вываливается в основное меню.
с под меню не могу разобраться
А оно так не делается. С таким походом Вы его на 99,99% не сделаете, а на оставшиеся 0,01% программа получится получится такой огромной, сложной и запутанной, что вероятность отладки до приемлемой надёжности практически неотличима от 0. По крайней мере, я бы не справился и даже браться бы не стал.
Многоуровневое меню делается не в лоб, а через дерево элементов. Тогда код остаётся в разумных размерах, разумной понятности, и всё получается. дерево элементов можно делать по-разному, но по-любому это должно быть дерево.
Хотел создавать отдельную тему тоже с многоуровневым меню, но меня опередили. В сети я нашел очень простой, на мой взгляд, вариант одноуровневого меню, самое главное что оно уже функциональное. Но опыта мало и не знаю как правильно сделать навигацию вверх/вниз в подменю. Возможно здесь то что тебе нужно.
Можете ткнуть пальцем, хоть куда копать. примеры или еще что...
Oscar. поправте меня, но по-моему понятия "одноуровневое меню" не предполагает никаких "подменю"... или я не прав?
Что касается кода, судя по огромному числу операторов delay() - вряд ли его писал продвинутый автор...
Oscar. поправте меня, но по-моему понятия "одноуровневое меню" не предполагает никаких "подменю"... или я не прав?
мм.. впринципе Вы правы, но в конце есть последние три m=30 ... 32. Это я пытался прикрутить второй уровень что бы сделать его многоуровневым, но не получается сделать прокрутку вверх/вниз. Я пытался сделать по аналогии как и для первого уровня, но не работает.
Что касается кода, судя по огромному числу операторов delay() - вряд ли его писал продвинутый автор...
Я так понимаю что автор это использовал для борьбы с дребезгом контактов, но в любом случае контроллер это не грузит.
Я так понимаю что автор это использовал для борьбы с дребезгом контактов, но в любом случае контроллер это не грузит.
delay(100) уже ПОСЛЕ обработки КАЖДОГО нажатия? - а что оно делает кроме загрузки контроллера, по вашему?
Второй delay да, лишний, я его не увидел.
Так у меня тоже меню работает, а вот под меню в данном варианте Нет. В цикле программы идет привязка к основному меню. Здесь действительно нужен другой подход.
Выглядеть должно примерно так:
Внутри каждого подменю такой же интерфейс и switch с вариантами .
Т.е. когда menu_item =MAIN_SCREEN, мы видим главный экран и кнопками(энкодером и тп) меняем значение курсора и переменную. По кнопке ОК изменяем значение menu_item и соответственно видим другую отрисовку и уже в другом, вложенном switch меняем значение другой переменной(положение курсора)
Можете ткнуть пальцем, хоть куда копать. примеры или еще что...
Странный Вы человек. Я же Вам написал, что это делается на деревьях. Куда Вам ещё тыкать? Ну, ладно, если так хотите - пожалуйста.
Kakmyc
Как в вашем случае выглядит цикл программы? с опросом кнопок. Просто если кнопка вниз то осн меню --. Если вверх, то осн меню ++. дальше выбрали подменю. вверх под меню++, вниз под меню --. Как вы в void loop будете опрашивать кнопки? Сразу для меню и подменю и под подменю? Вы привели аналог моего кода.
Тихо. Тут религиозные фанатики "правильного кода" сейчас нас с тобой заклюют, но я попробую тебе помочь.
Добавь переменную, напр. SubMenu
Дальше, думаю ты догадаешься что и как поправить.
Дальше, думаю ты догадаешься что и как поправить.
Ну, да. А у подменю могут быть свои подменю. А одно меню (одного уровня) может содержать как терминальные элементы, так и подменю. И так на каждый случай добавляем переменные. Если меню содержит хотя бы два десятка элементов, то отладить такое будет невозможно.
Зачем обязательно придумывать костыли, если можно сделать системно и правильно? Это спорт такой?
Зачем обязательно придумывать костыли, если можно сделать системно и правильно? Это спорт такой?
ждем выступление вавгата "а ТС именно так и заказывал" :)
Kakmyc
Как в вашем случае выглядит цикл программы? с опросом кнопок. Просто если кнопка вниз то осн меню --. Если вверх, то осн меню ++. дальше выбрали подменю. вверх под меню++, вниз под меню --. Как вы в void loop будете опрашивать кнопки? Сразу для меню и подменю и под подменю? Вы привели аналог моего кода.
Я не знаю, как у вас опрашиваются кнопки.
Но в моем варианте, как обычно.
Только вот результаты используются в одном меню , в том которое на данный момент является активным.
ну раз все побежали показывать свой г... код :) то я тоже продемонстрирую
Я в одном из проектов описывал все строчки меню единообразно
и потом собирал из таких строчек все меню со всеми вложениями:
для наглядности вставил пустые строки между подменю.
Цифра после текста означает id элемента, на который указывает строчка. Если такому id соответвует строка с типом SUB_MENU -значит переходим на уровень ниже (или выше). Если для такого id подменю нет - значит это просто действие.
Например, строчка
указывает на подменю
а строка
указывает на меню с ID =0, то есть выход на верхнй уровень
Топорно конечно, зато любое кол-чество дополнительный уровней и строчек меню можно добавить независимо от других.
В своё время прочитал http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html проникся, адаптировал под себя и с тех пор использую во всех местах, где нужно многоуровневое меню. Перегружено конечно, но за то очень легко сделать любой глубины и ширины, при этом вставить в любую точку дополнительный пункт даже не надо ничего переделывать. Потом появилось micromenu V2 https://github.com/abcminiuser/micromenu-v2 обещали что легче, но руки посмотреть не дошли.
любое кол-чество дополнительный уровней и строчек меню можно добавить независимо от других.
Вот и я ж про тоже. Деревья - они такие.
Я бы еще в дополнение к next, добавил бы ещё prev - тогда удаление на лету - как два пальца получается.
ЕвгенийП не совсем пойму, этот пример для построения текстового меню. У меня графическое.
этот пример
Какой? Я не давал никаких примеров.
этот пример для построения текстового меню. У меня графическое.
С точки зрения организации данных разницы нет никакой от слова совсем. У любого меню есть терминальные элементы и подменю. У любого элемента (кроме корневого) есть "родитель". У большинства элементов есть "братья и сёстры". Организация данных всегда одинаковая. А уж как Вы там его показываете, командой "showText" или "showImage" - это вопрос №321.
Если хотите грамотно делать меню, изучите работу с деревьями. Так в лоб, с какими-то бессистемными переменными-флагами Вы этого не сделаете.
Сорри за тупость, но я не понял. дерево своего меню нарисовал:
дальше как я понял, мы описываем меню.
А вот дальше я нифига не понял.
дальше как я понял, мы описываем меню.
А вот дальше я нифига не понял.
Этого маловато. Я сейчас Вам набросаю общих идей в виде псевдокода, но именно "псевдо". Уж простите, запускать и отлаживать сейчас некогда, а кроме того, я тут за ужином немного поборолся с вирусом (дезинфицирующего срецтва принял), но идейно как это делать покажу (на примере Вашего дерева). Щас ... , возвращайтесь через часик.
Ну, вот, смотрите.
Я сделал некое универсальное меню, в которое напихал всё, что спьяну вспомнил. Для любого реального проекта, здесь много лишнего и ненужного, но я хотел показать как делаются разные вещи.
Здесь можно создавать меню, показывать его с любым уровнем вложенности, на лету добавлять и удалять элементы.
На все эти возможности есть комментарии и примеры. Читайте комментарии, запускайте примеры, если чего – спрашивайте. Для примера взято Ваше меню, но я добавил ещё один уровень.
Сразу предупреждаю, не проверял, т.к. в данный момент не могу, но на UNO по идее должно работать, разве что опечатка какая – тогда поправим.
Запускайте. смотрите примеры, как сделано, разбирайтесь, если что - спрашивайте, но не обещаю насчёт сегодня - что-то я сегодня перебрал с дезинфекцией :-(
ЕвгенийП ого! лихо. спасибо, буду разбираться. надеюсь разберусь. Скетч без ошибок, все работает. Я так же по Вашим рекомендациям смотрел в нете построение меню древом. После графического представления меню, идет построение матрицы, которую Вы реализовали в коде. Дети, внуки, правнуки только не понятны. Меню11 и меню12 это дети родителя меню1 или дети родителей меню1-меню6 ?
SMenuItem m0(
""
); --- согласен, это нулевое меню бога, которое не отображается и служит типа контрольной точки отсчета, у которого нет ни предыдущего ни последующего соседа
SMenuItem m1(
"Menu1"
, nullptr, & m0); ----- до него ничего нет, справа по идее от него должен быть m2 ??
Родитель всегда только один - третий параметр конструктора
SMenuItem m4(
"Menu4"
, & m3, &m0); // Родитель
m4 -> это m0SMenuItem m412(
"Menu412"
, & m411, & m41);
// Родитель
m412 -> это m41Вообще, схема ТОЧНО ТАКАЯ как на Вашей картинке с единственной разницей - я добавил три элемента, которых у Вас не было - m411, m412 и m413 - все трое - дети 41.
Поэтому, если Вам непонятно кто чей родитель, смотрите свою картинку или же то, что печатается - там же ясно кто чьи дети - они со сдвигом печатаются - дети под родителем со сдвигом вправо..
SMenuItem m1(
"Menu1"
, nullptr, & m0); ----- до него ничего нет, справа по идее от него должен быть m2 ??
Перед ним - никого, т.к. у него второй параметр nullptr. А за ним тот, у кого второй параметр m1. Вообще, второй параметр - это имя того, кто перед этим элементом. Вы смотрите на печать и на свою картинку.
Понятно с детьми изложили. Я думал строится все слоями: вначале все пункты меню, 2й слой пункты ПОДменю, 3 слой пункты ПОДпод меню и тд и точка перехода между слоями.
int
id; непонятно где этот идентификатор используется.
И главное, это вызов.
Начало программы. Рисую все пункты меню. Курсор ставлю в позицию меню1. Вызывать так: SMenuItem m1; ??
int
id; непонятно где этот идентификатор используется.
Нигде. Это на вырост. Почти наверняка пригодится в будущем.
И главное, это вызов.
Начало программы. Рисую все пункты меню. Курсор ставлю в позицию меню1. Вызывать так: SMenuItem m1; ??
На самом деле, это тоже делается единообразно (всегда одинаково). Рисуете меню. Заводите специальный указатель currentItem и настраиваете его на текущее активное меню:
currentItem = & m1
Через него делаете все переходы и вызовы.
.... блин, перечитал ... сам не понимаю давайте-ка я сейчас тот пример расширю.
Только я не буду добавлять никаких экранов, а сделаю так. Текущий элемент меню будет всегда показываться "звёздочкой". Вместо ENTER вводим цифирь. Означает она следующее:
1 - продвинуться по меню вверх, если есть куда (на том же уровне)
2 - продвинуться вниз, если есть куда (на том же уровне)
3 - перейти на уровень вверх (к родителю)
4 - если это не листик, то перейти на уровень вниз, а если листик, то выполнить этот пункт
Другие числа (и знаки) игнорируются.
Походите по меню туда сюда, убедитесь, что всё работает. Потом попробуйте что-то менять и смотрите, правильно ли Вы поняли программу (адекватно ли она реагирует на Ваши изменения).
И, главное, имейте в виду - любое меню, хоть текстовое, хоть графическое. хоть голосовое - любое делается примерно также. Разница только в функция показа (у меня они называются show).
Пробуйте. Следите за звёздочкой - она означает активный (выбранный) в данный момент элемент. Как видите, можно ходить по меню и исполнять терминальные элементы.
Кстати, можно на лету добавлять и удалять элементы (как мы делали в прошлом примере), всё продолжает адекватно работать (можете попробовать), однако ... ВНИМАНИЕ!!! Тут есть грабли. Если Вы попытаетесь удалить элемент, который в настоящий момент активен - всё поломается. Чтобы такого не было, надо проверять при удалении не активен ли удаляемый элемент и либо отказываться удалять, либо переводить активность на другой элемент. Но это Вы уж сами. Как переводить активность в этом примере показано (кнопки 1 и 2).
ЕвгенийП
Огромное спасибо. Это почти готовая операционка. Неплохо было бы модеру в шапку приклеить. Если не секрет, сколько осваивали язык?
Если не секрет, сколько осваивали язык?
Пишет, что за день в новом языке разобраться может. Думаю, что он - энопланетянин.
Многие языки по синтаксису и структуре похожи. Мне для того, чтобы перейти с Бейсика на Паскаль тоже немного времени понадобилось. Тк очень похожи.
Если не секрет, сколько осваивали язык?
Я по работе язычник, т.е. я занимаюсь наукой в области языков программирования (кстати, Ворота - тоже). Правда, если смотреть на более узкую специализацию, то языками несколько другого типа, но в контексте любительского форума это совсем несущественно.
Ппц я тупой похоже. Целый день въезжал в то как это дерево структурное работает. Ладно хоть дошло в итоге. Ещё два дня ушло на то, что бы понять, как прикрутить туда функции. Грёбаный синтаксис, какое то написание не совсем очевидное if(curItem->Handler){(*curItem->Handler)();}
Зато теперь понял, что если прикрутить туда какой-нить идентификатор действия, типа :
можно делать вообще что угодно одним энкодером или тремя кнопками.
Ещё немного и лямбда-функции начнут зохватывать мозг.
Ещё немного и лямбда-функции начнут зохватывать мозг.
Мозг такими темпами не доживёт.
Долго искал причину, почему скачет по меню программа. Оказалось энкодер какашный, программно не фильтруется толком.
лямбда-функции начнут зохватывать мозг.
Ну, уж нет! Эта корова коронавируса и он её доит! И никаким функциям он её не отдаст, будь они хоть лямбда, хоть дзета.
Скоро всем в мозги внедрят интерпретаторы машинного кода. И в мире закончится срачЪ какой язык лучше. И с компьютером мы все будем на "ты".
Скоро всем в мозги внедрят интерпретаторы машинного кода. И в мире закончится срачЪ какой язык лучше. И с компьютером мы все будем на "ты".
Вряд ли.
Подавляющее большинство людей диссонируют с понятием логики. Там любой интерпретатор загнётся
Очередной затык приключился.
Ничего не понял.
Ничего не понял.
Есть переменная, как структуре на нее передать ссылку ?
Ну, не знаю, есть 100500 способов. Можно в структуре завести поле - ссылку или указатель на эту переменную. Но, проще завести эту переменную как статическое поле структуры - тогда она будет одна на все экземпляры структуры, но при этом оставаться её внутренним полем.
Ну, не знаю, есть 100500 способов. Можно в структуре завести поле - ссылку или указатель на эту переменную. Но, проще завести эту переменную как статическое поле структуры - тогда она будет одна на все экземпляры структуры, но при этом оставаться её внутренним полем.
В общем то я про это и спрашиваю.
Как будет выглядеть правильный синтаксис, для передачи указателя структуре
В ардуине посмари исходник attachInterrupt(), там ссылка на функцию-хендлер сейвится в массив.
Handler по указателю у меня работает.
У меня на int матом ругается
Приводите код полностью. Откуда мне знать на что он ругается?
Как будет выглядеть правильный синтаксис, для передачи указателя структуре
Ну, для начала нужно передавать именно указатель, а не его разыменование, т.е., разумеется не *myInt, а хотя бы & myInt, но, повторяю, приводите код полностью.
Только на 100500% более грамотно не передавать указатель, а завести статическое поле. Расход памяти будет меньше на 2 * <количество экземпляров>. Да и вообще, если класс работает с внешними указателями - это признак неграмотного проектирования программы.
Хорошо, попробуем с другой стороны: