Ответ

Предупреждение: в данной теме не было сообщений более 730 дней.
Если не уверены, что хотите ответить, то лучше создайте новую тему.
Имя:
E-mail:
Тема:
Иконка:

Визуальная проверка:
Без рук и топоренка построена избенка:
4x50 (цифрой):
В рот мне ....:

подсказка: нажмите alt+s для отправки или alt+p для предварительного просмотра сообщения


Сообщения в этой теме

Автор: pumpkin
« : 19 Июля 2010, 18:07:13 »

Цитировать
Ну я просто добавил еще один одинаковый блок как на те две кнопки, и прицепил третью кнопку. А в описание меню добавил еще одно поле.
Точно. Тоже думаю, что это оптимальное решение. Меню в секции $data такого вида:
   Метка_своя:
   Data Тип_Меню
   Data "Название_меню"
   Adr2 Метка_дочернего /или/ Adr Метка_подпрограммы
   Adr2 Метка_соседа_слева
   Adr2 Метка_соседа_справа
   Adr2 Метка_родителя

Вот еще вариант обработки клавиш, который мене в голову пришел:
Цитировать
\' Если тип меню - команда и был нажат "Enter" (2), то:
 If B = 50 Then
   If Type = Id_command Then
     Read Dataptr
     movw R30,R8
     icall
     Goto Display_new_menu
   End If
 End If

 Offset = 0    \' Нажат "Enter" (2) но не команда, а подменю
 If B = 49 Then Offset = 2     \' Нажата  "<-" (1) - смещение 2 байта
 If B = 51 Then Offset = 4     \' Нажата "->" (3) - смещение 4 байта
 If B = 52 Then Offset = 6     \' Нажата "Esc" (4) - смещение 6 байт
 While Offset > 0
   Read Dummy                          \' смещаемся к нужному меню
   Offset = Offset - 1
 Wend

 Read Dataptr
 sts {MenuPointer}, R8
 sts {MenuPointer + 1}, R9
 Goto Display_new_menu
Автор: Andy
« : 19 Июля 2010, 07:04:22 »

Ну я просто добавил еще один одинаковый блок как на те две кнопки, и прицепил третью кнопку. А в описание меню добавил еще одно поле.  Потом вывел одинаковые блоки в подпрограммы - получилось компактно и красиво. Вот и все.
Автор: pumpkin
« : 19 Июля 2010, 05:45:08 »

Цитировать
Неочевидно стало добавлять новые условия (я добавил еще одну кнопку для возврата в предыдущее меню).
Добавил к каждому пункту меню в секции data еще одну связь на родительский элемент или просто адреса родителей запоминаешь по ходу работы? Интересно просто.

Основная мысль предыдущего моего сообщения была в том, чтобы в зависимости от нажатой кнопки, при помощи Read Dummy переместиться на нужную связь. Если сосед слева - 2 байта, сосед справа - 4 байта, родитель (если возврат в предыдущее добавить) - 6 байт. А потом уже один раз выполнить (он для всех кнопок ведь одинаков) блок
   Read Dataptr
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu

Но можно и по-твоему. Вариантов реализации много. :)
Автор: Andy
« : 19 Июля 2010, 03:49:00 »

Что-то как-то... Условий менше не стало, Неочевидно стало добавлять новые условия (я добавил еще одну кнопку для возврата в предыдущее меню). Короче, я вывел
   Read Dummy
   Read Dummy
и
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
в отдельные функции и успокоился. Итак все очень неплохо.
Автор: pumpkin
« : 18 Июля 2010, 13:25:57 »

Ага, можно оптимизировать. И в функцию даже не нужно. Просто этот кусок кода, где два раза повторяется:
Цитировать
\' Если нажата не 2 (Enter), то пропускаем 2 байта с адресом
\' команды или подменю - они нам не нужны.

Read Dummy
Read Dummy
\' Проверяем, нажата ли 1 (<-)
If B = 49 Then
   \' Читаем адрес предыдущего меню на этом уровне (сосед слева)
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
End If

\' Если нажата и не 1 (<-), то снова пропускаем 2 байта с адресом
\' соседа слева - они нам тоже не нужны.

Read Dummy
Read Dummy
\' Проверяем, нажата ли 3 (->)
If B = 51 Then
   \' Читаем адрес следующего меню на этом уровне (сосед справа)
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
End If

оптимизировать таким макаром:
Цитировать
\' Если нажата не 2 (Enter), то пропускаем 2 байта с адресом
 \' команды или подменю - они нам не нужны.

 Read Dummy
 Read Dummy

\' Если нажато 1 (<-) - мы на месте
 \' Если нажато 2 (->) - то смещаемся еще на 2 байта

 If B = 51 Then
   Read Dummy
   Read Dummy
 End If

 If B = 49 Or B = 51 Then
   \' Читаем адрес пункта меню (<- или ->), на который пришли
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
 End If

Можно еще Dummy объявить как Word и вызывать Read Dummy не дуплетом, а одинарно.

---------
Исправил чуть.
Автор: Andy
« : 18 Июля 2010, 12:32:30 »

Цитировать
И добавление нового пункта меню добавит всего 7 байт (без учета строки с названием, естественно).
И самое смешное, что алгоритм можно оптимизировать, например этот блок:

Цитировать
\' Если нажата не 2 (Enter), то пропускаем 2 байта с адресом
\' команды или подменю - они нам не нужны.
Read Dummy
Read Dummy
\' Проверяем, нажата ли 1 (<-)
If B = 49 Then
   \' Читаем адрес предыдущего меню на этом уровне (сосед слева)
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
End If

повторяется 2 раза практически без изменений, по одному на каждую кнопку. Но пока вывести его в отдельную функцию не удалась, всему виной фраза Goto Display_new_menu. Из-за нее стек срывается, нельзя выходить из функции без return. Но это не суть важно...
Автор: Andy
« : 18 Июля 2010, 11:11:56 »

Пока сделал кривенько, попозже код напишу. Пока под микроскопом изучаю твой код, учусь, типа.
Автор: pumpkin
« : 18 Июля 2010, 10:58:39 »

И добавление нового пункта меню добавит всего 7 байт (без учета строки с названием, естественно).

PS: Алгоритм ввода строки и редактирования ее BackSpace-oм еще нужен? Или уже сделал давно?
Автор: Andy
« : 18 Июля 2010, 10:35:03 »

А так получилось очень быстрое и маленькое меню. Очень удобно добавлять новые подменю Код занимает всего 600 байт!
Автор: Andy
« : 18 Июля 2010, 10:33:26 »

Отлично! В коий раз снимаю шляпу...

Все почти сразу заработало, Единственно поправил этот кусочег:

Цитировать
Else
     \' Читаем адрес метки команды (идет в Data сразу за названием)
     Read Dataptr
     \' Вызываем подпрограмму по этому адресу.
     movw R30,R8
     icall
     \' И после ее отработки идем в самое начало. Здесь можно и выйти
     \' из меню вообще или остаться в этом пункте меню или еще что-нибудь.

lds R8, {MenuPointer}
lds R9, {MenuPointer + 1}

     Goto Main_menu
   End If


Так как первую строку Restore Menu1 я вывел за пределы функции, чтобы попадать из любого места программы в нужное мне меню.

А подпрограммы портят регистры и меню вылетает неизвестно куда. Пихать в стек их не помогает, надежнне восстановить из переменной. Появился отличный эффект обратного попадания в родительское меню, откуда подпрограмма вызывалась.
Автор: pumpkin
« : 16 Июля 2010, 22:16:26 »

Написал ближе к твоим требованиям. Структура меню - в данных, а код - отдельно, один для всех. Код обильно прокомментировал.
Единственное - ввод-вывод. Так как не знаю, как прикрутить LCD и AT keyboard в эмуляторе, сделал ввод через Waitkey(), а вывод через Print. И вместо клавиш влево (<-), вправо (->) и Enter использовал, соответственно, "1", "3" и "2". Но это, думаю, не важно. Ввод-вывод свои поставишь.

Для добавления пунктов код трогать не надо. Надо только добавлять пункты с связями в секцию $data, и писать подпрограммы для действий.

Цитировать
$regfile = "M644def.dat"
$crystal = 8000000

$hwstack = 64
$swstack = 64
$framesize = 64

$lib "adr2.lib"

Dim Menupointer As Word

Dim B As Byte

Dim Type As Byte
Dim Dummy As Byte
Dim Message As String * 32

\' Типы меню
Const Id_submenu = &HAA
Const Id_command = &H55

Main_menu:
 \' Ставим указатель Data на первый пункт главного меню
 Restore Menu1
 \' Сохраняем в MenuPointer текущий указатель Data,
 \' который лежит в регистрах R8 и R9 (ассемблерный код).
 sts {MenuPointer}, R8
 sts {MenuPointer + 1}, R9

Display_new_menu:
 \' Извлекаем из MenuPointer указатель в регистры R8 и R9,
 \' то есть передвигаем указатель Data в позицию MenuPointer.
 lds R8, {MenuPointer}
 lds R9, {MenuPointer + 1}

 \' Читаем тип меню (подменю или команда), название и печатаем название
 Read Type
 Read Message
 Print Message

 \' Ждем клавишу, пока она не 1 (<-) или 2 (Enter) или 3 (->).
Wait_key:
 B = Waitkey()
 If B < 49 Then
    Goto Wait_key
 End If
 If B > 51 Then
   Goto Wait_key
 End If

 \' Проверяем, нажата ли 2 (Enter)
 If B = 50 Then
   \' Если тип у нас - подменю, то:
   If Type = Id_submenu Then
     \' Читаем адрес дочернего меню (идет в Data сразу за названием)
     Read Dataptr
     \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
     sts {MenuPointer}, R8
     sts {MenuPointer + 1}, R9
     Goto Display_new_menu
   \' Иначе (если тип - команда), то:
   Else
     \' Читаем адрес метки команды (идет в Data сразу за названием)
     Read Dataptr
     \' Вызываем подпрограмму по этому адресу.
     movw R30,R8
     icall
     \' И после ее отработки идем в самое начало. Здесь можно и выйти
     \' из меню вообще или остаться в этом пункте меню или еще что-нибудь.
     Goto Main_menu
   End If
 End If

 \' Если нажата не 2 (Enter), то пропускаем 2 байта с адресом
 \' команды или подменю - они нам не нужны.
 Read Dummy
 Read Dummy
 \' Проверяем, нажата ли 1 (<-)
 If B = 49 Then
   \' Читаем адрес предыдущего меню на этом уровне (сосед слева)
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
 End If

 \' Если нажата и не 1 (<-), то снова пропускаем 2 байта с адресом
 \' соседа слева - они нам тоже не нужны.
 Read Dummy
 Read Dummy
 \' Проверяем, нажата ли 3 (->)
 If B = 51 Then
   \' Читаем адрес следующего меню на этом уровне (сосед справа)
   Read Dataptr
   \' Записываем его в MenuPointer и идем читать и рисовать это новое меню
   sts {MenuPointer}, R8
   sts {MenuPointer + 1}, R9
   Goto Display_new_menu
 End If

 End

\' ---------
\' Подпрограммы для команд

Runmenu11:
 \' Здесь делаем полезные дела
 Print "Running command from menu 1 -> 1"
 Return

Runmenu12:
 \' Полезные дела
 Print "Command of menu 1 -> 2"
 Return

Runmenu2:
 \' Полезные дела
 Print "Command of menu 2"
 Return

Runmenu3:
 \' Полезные дела
 Print "Command of menu 3"
 Return

\' ---------
\' Блок данных. Здесь и находится структура меню. Порядок пунктов меню не важен,
\' главное правильно указать связи-адреса на дочерний элемент (подменю или
\' команду) и соседей слева и справа. Структура такая:
\'
\'   Метка_своя:
\'   Data Тип_Меню
\'   Data "Название_меню"
\'   Data Метка_дочернего
\'   Data Метка_соседа_слева
\'   Data Метка_соседа_справа
\'
$data

Menu1:
Data Id_submenu
Data "Menu 1 v"
Adr2 Menu10
Adr2 Menu3
Adr2 Menu2

Menu10:
Data Id_submenu
Data "Menu up^"
Adr2 Menu1
Adr2 Menu12
Adr2 Menu11

Menu11:
Data Id_command
Data "Menu 11!"
Adr Runmenu11
Adr2 Menu10
Adr2 Menu12

Menu12:
Data Id_command
Data "Menu 12!"
Adr Runmenu12
Adr2 Menu11
Adr2 Menu10

Menu2:
Data Id_command
Data "Menu 2 !"
Adr Runmenu2
Adr2 Menu1
Adr2 Menu3

Menu3:
Data Id_command
Data "Menu 3 !"
Adr Runmenu3
Adr2 Menu2
Adr2 Menu1
Автор: Andy
« : 16 Июля 2010, 07:54:15 »

Цитировать
Посмотри в сторону Adr и Adr2. Вот в документации Bascom-а топик: http://avrhelp.mcselec.com/index.html?adr___adr2.htm
Там как раз в качестве примера реализация меню рассматривается. Глянул только мельком - вроде оно.

Цитировать
И еще бы алгоритм ввода строки и редактирования ее BackSpace-oм, ессесно эхоповтором на дисплее...
А это, кстати, нужно еще?
 

Посмотрел, как баран, так и не понял как это работает. Какие-то умножения на два и все такое, чувствую, штука нужная, а как это работает - не пойму....
Автор: pumpkin
« : 15 Июля 2010, 19:33:52 »

Посмотри в сторону Adr и Adr2. Вот в документации Bascom-а топик: http://avrhelp.mcselec.com/index.html?adr___adr2.htm
Там как раз в качестве примера реализация меню рассматривается. Глянул только мельком - вроде оно.

Цитировать
И еще бы алгоритм ввода строки и редактирования ее BackSpace-oм, ессесно эхоповтором на дисплее...
А это, кстати, нужно еще?
Автор: Andy
« : 15 Июля 2010, 16:13:32 »

А вот вопрос  такой есть. Можно ли в бейсике каким либо обраозом передать подпрограмму или метку как параметр? что-то вроде указателя?

Например меню мое сотоит из однотипных блоков

Menumain:
\'Меню Работа с кассой
Cls
Longstr = W28                                               \'Работа с кассой
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Menu21                                       \'Нажат ENTER - Программа выбора кассы
Case 56 : Goto Mainmenu                                     \'Нажата Стрелка Вверх
Case 50 : Goto Menu3                                        \'Нажата Стрелка Вниз
End Select
Loop

хотелось бы сделать одну функцию, а туда передавать как параметр  например подпрограмму Menu3 и вызывать ее. Очень меня давно этот вопрос интересует, постоянно на него натыкаюсь. Код можно очень сильно сократить...


типа так:
ukaz=Menu3

gosub Menumain



Menumain:

бла  бла

Case 50 : Goto ukaz

return

Условие переходит на Menu3.... Profit...

Можно так сделать?

Автор: Andy
« : 15 Июля 2010, 15:57:23 »

Вот окончательный вариант меню, очень легко добавлять новые меню и подменю любой степени вложенности.


Mainmenu:
Gosub Beep
Cls
Longstr = W27                                               \'Выбор Кассы
Gosub Printlsd

Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr1                                       \'Нажат ENTER - Программа выбора кассы
Case 50 : Goto Menu2                                        \'Нажата Стрелка Вниз
\'Case 56 : Goto Menu3                                       \'Нажата Стрелка Вверх
End Select
Loop



Menu2:
\'Меню Работа с кассой
Cls
Longstr = W28                                               \'Работа с кассой
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Menu21                                       \'Нажат ENTER - Программа выбора кассы
Case 56 : Goto Mainmenu                                     \'Нажата Стрелка Вверх
Case 50 : Goto Menu3                                        \'Нажата Стрелка Вниз
End Select
Loop


Menu3:
\'Меню Загрузка EPROM
Cls
Longstr = W14                                               \'Загрузка EPROM
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr3                                       \'Нажат ENTER -
Case 56 : Goto Menu2                                        \'Нажата Стрелка Вверх
Case 50 : Goto Menu4                                        \'Нажата Стрелка Вниз
End Select
Loop



Menu4:
\'Меню Загрузка блока
Cls
Longstr = W13                                               \'Загрузка блока
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr4                                       \'Нажат ENTER -
Case 56 : Goto Menu3                                        \'Нажата Стрелка Вверх
Case 50 : Goto Menu5                                        \'Нажата Стрелка Вниз
End Select
Loop



Menu5:
\'Меню Выгрузка EPROM
Cls
Longstr = W15                                               \'Выгрузка EPROM
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr5                                       \'Нажат ENTER -
Case 56 : Goto Menu4                                        \'Нажата Стрелка Вверх
Case 50 : Goto Menu6                                        \'Нажата Стрелка Вниз
End Select
Loop



Menu6:
\'Тест
Cls
Longstr = W34                                               \'Тест
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr6                                       \'Нажат ENTER -
Case 56 : Goto Menu5                                        \'Нажата Стрелка Вверх
\'Case 50 : Goto Menu6                                        \'Нажата Стрелка Вниз
End Select
Loop

Menu21:
\'Меню отчета с фискалки по датам
Cls
Longstr = W16                                               \'С фиск. по датам
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Fisk                                         \'Нажат ENTER -
\'Case 56 : Goto Menu5                                        \'Нажата Стрелка Вверх
Case 50 : Goto Menu22                                       \'Нажата Стрелка Вниз
Case 100 : Goto Menu2                                       \'Нажат ESC
End Select
Loop



Menu22:
\'Меню отчета с фискалки по сменам
Cls
Longstr = W17                                               \'С фиск. по сменам
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Fisksmena                                    \'Нажат ENTER -
Case 56 : Goto Menu21                                       \'Нажата Стрелка Вверх
Case 50 : Goto Menu23                                       \'Нажата Стрелка Вниз
Case 100 : Goto Menu2                                       \'Нажат ESC
End Select
Loop



\'Программа пустая
Menu23:
Cls
Longstr = "Ёycїo 1"
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
Case 13 : Goto Progr4                                       \'Нажат ENTER -
Case 56 : Goto Menu22                                       \'Нажата Стрелка Вверх
\'Case 50 : Goto Menu23                                       \'Нажата Стрелка Вниз
Case 100 : Goto Menu2                                       \'Нажат ESC
End Select
Loop





Menu31:
\'По годам кварталам и месяцам
Cls
Longstr = W18                                               \'Год.Кварт.Месяц
Gosub Printlsd
Do
Gosub Kbdinput
Select Case B
\'Case 13 : Goto Fisksmena                                    \'Нажат ENTER -
\'Case 56 : Goto Menu21                                       \'Нажата Стрелка Вверх
Case 50 : Goto Menu32                                       \'Нажата Стрелка Вниз
Case 100 : Goto Menu21                                      \'Нажат ESC
End Select
If B = 13 Then
1val = 1
2val = 3
Goto Fiskini
End If
Loop



и так далее....