Создайте меню из трех пунктов вывод плюсика вывод квадрата выход пункты оформите в виде процедур

Обновлено: 19.05.2024

В приложениях, написанных на Delphi, могут быть реализованы меню двух основных типов:

главное меню (MainMenu),оно принадлежит форме и отображается под ее панелью заголовка;

всплывающее (контекстное) меню (PopupMenu), оно может быть у всех визуальных компонентов и возникает (всплывает) при нажатии правой кнопки мыши на компоненте.

Пункт меню может быть в виде подменю или команды. При выборе пункта меню инициируется событие OnClick.

Для создания меню надо:

поместить на форму компонент MainMenu или PopupMenu ;

вызвать разработчик меню, дважды щелкнув по компоненту;

написать название пункта (Caption) и нажать Enter;

под первым пунктом появится заготовка для ввода пункта подменю, а справа – для ввода следующего пункта главного меню.

Для каждого пункта меню можно назначить горячие клавиши (свойство ShortCut), подсказку (Hint), картинку (Bitmap).

Панель инструментов представляет собой управляющий элемент, предназначенный для упрощения выбора часто используемых команд. Панели могут быть статическими (прикрепленными к некоторому краю окна) или плавающими, которые можно перемещать при выполнении приложения.

Способы создания панели инструментов:

на основе компонента Panel (Standard):

на панели размещают кнопки быстрого доступа ( SpeedButton ) и комбинированные списки ( ComboBox );

с помощью компонента ToolBar (Win32):

компонент автоматически задает для всех кнопок, размеще нных на ней, одинаковые размеры, упорядочивает их расположение;

с помощью компонента CoolBar (Win32):

эту панель инструментов можно настраивать и менять ее м естоположение при выполнении программы.

При запуске Delphi автоматически создает основную форму с именем Form1. На форме можно разместить главное меню и строку состояния, размещать элементы управления работы приложения, выводить текст и графику. Если приложение состоит из нескольких форм, то первая из созданных форм является главной. Ей передается управление в начале работы приложения, ее закрытие вызывает завершение выполнения приложения.

Формы имеют ряд свойств, которые определяют вид и поведение окна программы:

BorderStyle – определяет вид рамки окна

bsDialod диалоговая; bsSizeable обычная;

bsSingle форма с неизменяемыми параметрами;

bsNone не имеет рамки и заголовка;

BorderIcons - определяет набор кнопок в заголовке;

Icons определяет пиктограмму приложения;

AutoScroll – управляет появлением полос прокрутки;

Cursor определяет форму курсора мыши;

Enabled определяет реакцию на события от мыши, таймера и клавиатуры;

KeyPreview определяет, кто будет получать события от клавиатуры: форма или управляющий элемент на форме.

Menu позволяет выбрать один из доступных вариантов основного меню.

Создать и сохранить новый проект.

Р азместить на форме компонент MainMenu (Standard), выполните по нему двойной щелчок. Ввести подпись Монитор и имя mnuMonitor первому пункту меню и, по аналогии, всем остальным пунктам (см. рисунок).

Расположить на форме четыре компонента Image , задать для них информативные имена (например, picMinitor, picKey и т.п.), для свойства Picture выбрать соответствующий графический файл, сделать компоненты невидимыми, назначить всплывающие подсказки.

Расположить на форме метку (Name - Info).

Для пункта меню Монитор ввести следующий код:

Самостоятельно добавить в программу вывод в метку информации о назначении выбранного устройства.

Ввести программный код для остальных пунктов меню.

Проверить работу приложения.

Создать панель инструментов:

расположить на форме компонент ToolBar (Win32), присвоить имя Main Panel , для свойства EdgeBorders добавить значение ebBotton =True

щелкнуть на созданной панели правой кнопкой мыши и выбрать NewButton , установить кнопке следующие свойства:

аналогичным образом создать еще кнопки для остальных устройств и изменить их свойства;

для добавления изображений командам и кнопкам добавить на форму компонент ImageList (Win32) ;

дважды щелкнуть по компоненту, появится редактор, щелкните по кнопке Add и укажите размещение требуемых графических файлов \COMMON\GRAPHICS\ICONS\COMPUTER\. добавьте соответствующие файлы;

связать набор пиктограмм с панелью инструментов и основным меню: для компонентов Main Menu 1 и Main Panel для свойства Images из списка выбрать ImageList 1 ;

для каждого пункта меню и для каждой кнопки панели инструментов изменить значения свойства ImageIndex в соответствии с их назначением.

Проверить работу приложения.

Добавить в заголовок формы бегущую строку, для этого:

расположить на форме таймер (System) и ввести для него код:

procedure TForm1.Timer1Timer(Sender: TObject);

for i := 1 to (Length(a) - 1) do

a[i] := Application.Title[i + 1];

объявить глобальную переменную a: string;

в процедуру FormCreate ввести код

a := 'Компьютер полезен равно настолько, насколько грамотен использующий его человек. ';

12. Проверить работу приложения.

13. Сделать форму прозрачной, для этого в процедуру FormCreate добавить код:

14. Проверить работу приложения.

15. Отменить прозрачность формы.

16. Заполнить форму изображением, для этого:

установить на форму еще один компонент Image, задать значение для свойства Picture (любой файл .bmp), сделать компонент невидимым;

в процедуру FormCreate добавить код:

Проверить работу приложения.

Заблокировать введенный код.

Сделать форму полупрозрачной, для этого изменить значения следующих свойств:

AlphaBlend True, (включить полупрозрачность)

AlphaBlendValue 128 (степень прозрачности)

TransparentColorValue clBlack (какой цвет считать прозрачным)

TransparentColor True (включить прозрачность по цвету)

Проверить работу приложения.

Результат показать преподавателю, проект сохранить.

Задания для самостоятельного выполнения

(номер вашего задания такой же, как в практической работе №3)

Модернизировать ранее созданное приложение:

1. Создать главное меню для реализации следующих функций:

изменение скорости движения летательных объектов;

Модернизировать ранее созданное приложение:

1. Создать главное меню для реализации следующих функций:

изменение скорости падения буквы;

изменение регистра символа (заглавные, прописные);

изменение языка (латинские, русские)

Модернизировать ранее созданное приложение:

1. Создать главное меню для реализации следующих функций:

изменение цвета лапты;

изменение формы шарика (овал, шар, квадрат);

изменение скорости движения шарика

2. Создать всплывающее меню, которое выводится при щелчке по лапте и содержит два пункта: уменьшить длину, увеличить длину

Модернизировать ранее созданное приложение:

1. Создать главное меню для реализации следующих функций:

Какие типы меню существуют и как они создаются в приложении?

Какие возможности имеются для настройки меню?

Какие возможности имеются для настройки формы?

Какая последовательность создания панели инструментов?

ПРАКТИЧЕСКАЯ РАБОТА № 5

Тема : Элементы пользовательского интерфейса

Цель работы : Закрепить навыки проектирования интерфейса приложения, получить навыки использования стандартных диалоговых окон и буфера обмена.

Пояснения к работе

В данной работе используются новые компоненты:

RichEdit многострочный редактор для работы с форматированным текстом в формате RTF,свойство компонента SelAttributes позволяет менять атрибуты шрифта для выделенного фрагмента текста;

ColorBox – раскрывающийся список с образцами цвета ;

SpinEditor - окно редактирования со счетчиком для задания и показа данного значения ;

ImageList представляет собой набор пиктограмм, хранящихся на диске в файлах форматов .bmp и .ico. Размеры пиктограмм соответствуют кнопкам панели инструментов и командам меню. Доступ к каждой пиктограмме можно получить при помощи свойства ImageIndex – порядкового номера пиктограммы в наборе (нумерация с нуля).

Компоненты стандартных диалогов :

На странице Dialogs палитры компонентов размещены пиктограммы 11 компонентов. Они реализуют стандартные диалоги общего назначения, используемые в приложениях Windows:

OpenDialog (открытие файла), SaveDialog (сохранение файла), FontDialog (форматирование шрифта), ColorDialog (палитра цветов), FindDialog (поиск), ReplaceDialog (замена) и др. Для вызова любого стандартного диалога используется метод Execute - функция возвращает логическое значение: при закрытии окна диалога кнопкой ОК – True, при отмене – False.

После закрытия стандартного диалога он возвращает через свои свойства значения, выбранные или установленные в процессе диалога. Например, при открытии файла возвращаемым значением является имя открываемого файла (OpenDialog1.FileName), а при выборе цвета - новый цвет (значение свойства ColorDialig1.Color).

Чтение и запись текстовых файлов

Для работы с файлом необходимо назначить ему файловую переменную, т.е. ассоциировать ее с именем файла на диске. Через эту переменную будет выполняться вся работа с файлом. Для назначение файловой переменной F 1 используется процедура AssignFile (F1,FileName).

Для создания (записи) текстового файла используется процедура Rewrite (F1).

Если необходимо добавить текст в существующий файл, используется процедура Append (F1).

Для открытия (чтения) текстового файла используется процедура Reset (F1).

Чтение строки файла Readln (F1,Stroka);

Запись строки в файл Writeln (F1,Stroka);

После использования файла его следует закрыть процедурой CloseFile (F1).

Можно за один раз прочитать текстовый файл в многострочный редактор, например:

RichEdit1. Lines.LoadFromFile (‘c:\dogovor.txt’)

Запись содержимого текстового окна в файл одной командой

RichEdit1. Lines.SaveToFile (‘c:\dogovor.txt’)

Разработать приложение, реализующее основные функции текстового редактора:

форматирование шрифта для выделенного контекста;

копирование и перемещение выделенного контекста;

поиск и замена в тексте;

открытие и сохранение текстового файла;

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

Создать новый проект и сохранить его под именем MainEditor .

Создать на форме меню:

установить на форме компонент MainMenu (Standard);

присвоить ему имя mmMain . Каждому пункту меню задать информативное имя:

Создать панель инструментов:

расположить на форме компонент ToolBar (Win32), присвоить имя tlbMain , для свойства EdgeBorders добавить значение ebBotton True;

щелкнуть на созданной панели правой кнопкой мыши и выполнить NewButton , установить кнопке следующие свойства:

Hint создать файл

аналогичным образом создать еще кнопки и изменить им свойства: Открыть, Сохранить, Копировать, Вырезать, Вставить, Найти, Заменить ;

для добавления изображений командам и кнопкам добавить на форму компонент ImageList (Win32);

дважды щелкнуть по компоненту, появится редактор, щелкните по кнопке Add и указать размещение требуемых графических файлов Program Files\Common Files\Borland Shared\Images\Buttons, добавить соответствующий файл, в момент добавления на экране появится запрос о разбиении одной пиктограммы на две, ответьте утвердительно.

Связать набор пиктограмм с панелью инструментов и основным меню: для компонентов mmMain и tlbMain для свойства Images из списка выбрать ImageList 1 .

Изменить значения свойства ImageIndex для соответствующих пунктов меню и кнопок панели инструментов.

Добавить на панель инструментов компонент ColorBox (Additional) для выбора цвета шрифта, изменить значения свойств:

Name cobFontColor, Selected clBlack,

Style cbExtendedColors False

Добавить на панель инструментов компонент SpinEditor (Samples) для ввода размеров шрифта, изменить значения свойств:

Name - sdFontSize, MaxValue 70, MinValue 8)

Добавить на панель инструментов три компонента CheckBox (Standard) для изменения начертания шрифта, изменить значения свойств для каждого:

Name chBold, chItalic, chUnderLine

На форме установить компонент RichEdit (Win32), изменить значения свойств для этого объекта:

Name Document, ScrollBars ssBoth

Для объекта sdFontSize выбрать событие OnChange и ввести следующий код:

Для объекта chBold выберите событие OnClick и ввести следующий код:

document.Font.Style := document.Font.Style +[fsBold]

document.Font.Style := document.Font.Style -[fsBold];

Сохранить проект и проверить его работу:

ввести произвольный текст;

изменить размер шрифта и начертание Полужирный .

Самостоятельно ввести код для объектов chItalic и chUnderline (использовать константы fsItalic, fsUnderline), проверить работу приложения.

Для объекта cobFontColor выбрать событие OnChange и ввести следующий код:

Сохранить и проверить работу программы.

Для пункта меню и кнопки панели инструментов Вырезать ввести код:

Для пункта меню и кнопки панели инструментов Копировать ввести код:

Для пункта меню и кнопки панели инструментов Вставить ввести код:

В пункт меню Правка добавить подпункт Выделить все и ввести для него следующий код:

Проверить работу приложения.

Для того чтобы форматировать только выделенный фрагмент текста, внести изменения в код для объекта chBold

document. SelAttributes .Style := document. SelAttributes .Style +[fsBold]

document. SelAttributes. Style := document. SelAttributes .Style -[fsBold];

Проверить работу приложения и внести соответствующие изменения для других элементов форматирования.

Добавить на панель инструментов комбинированный список, задать ему имя cbFontName , для свойства Items ввести несколько значений, например: Times New Roman

Самостоятельно написать код, позволяющий изменять тип шрифта выделенного фрагмента.

Для выравнивания абзацев добавить на панель инструментов еще три кнопки, задать им имена btnLeft , btnCenter , btnRight и соответствующее изображение и ввести код в соответствии с назначением:

Проверить работу приложения.

Для форматирования абзацев маркированным списком добавить на панель инструментов еще одну кнопку, задать имя btnSpisok , изменить изображение и ввести для нее код:

Проверьте работу приложения. Самостоятельно изменить работу приложения, чтобы была возможность отменять маркированный список при повторном щелчке.

Добавить на форму компонент FontDialog (Dialogs)., присвоить имя fontD_1 Для пункта меню Формат/Шрифт ввести следующий код:

If fontd_1.Execute Then

Самостоятельно дополнить код, чтобы все выбранные атрибуты шрифта были применены к выделенному тексту.

Добавить на форму компонент ColorDialog (Dialogs)., присвоить имя ColorD_1. Добавить в пункт меню Формат подпункт Цвет .

Самостоятельно ввести код для изменения цвета шрифта выделенного текста.

Проверить работу приложения.

Добавить компоненты FindDialog и ReplaceDialog , изменить имена fd_1 и rd_1 соответственно.

Для пункта меню Правка/Найти ввести код:

If fd_1.Execute Then Begin End;

Для объекта Fd_1 выбрать событие OnFind и ввести код:

document.SelStart :=k -1; ;//начало выделения текста

document.SelLength :=length(finstr); //выделение текста

Else ShowMessage('Текст не найден);

Для пункта меню Правка/Заменить ввести код:

If rd_1.Execute Then Begin End;

Для объекта rd_1 выбрать событие OnReplace и ввести код:

document.SelStart :=k -1

document.SelText :=rd_1.replaceText;.// замена

Else ShowMessage('Текст не найден’);

Добавить на форму компонент SaveDialog (Dialogs), присвоить имя sd_1 , а свойству Filter значение - Документ|*.Txt . Самостоятельно ввести программу для сохранения содержимого текстового окна в файл.

Добавить на форму компонент OpenDialog (Dialogs), присвоить имя od_1 , а свойству Filter значение - Документ|*.Txt. Самостоятельно ввести программу для открытия файла и вывода его содержимого в текстовое окно.

Проверить работу приложения. Результат показать преподавателю.

Похожие документы:

М инистерство образования и науки российской федерации (12)

. программистов является закладка основ алгоритмизации и программирования – школьный . дисциплине 1 2 3 4 5 6 7 8 9 1 Язык программиро-вания Java Брагилев-ский Виталий . Объектно-ориентирован-ное программир-ование Михалкович Станислав Станиславович, .

О самообследовании основной образовательной программы (2)

. дисциплинам:  информатике, программированию и основам алгоритмизации;  вычислительным машинам, системам и сетям; . 20 32 158 Дейтел, Х.М. Как программировать на Java. - М : Бином . Вид исследований* Источник финансир- ования Объем финанси- рования, .

О самообследовании основной образовательной программы (11)

. дисциплинам:  информатике, программированию и основам алгоритмизации;  вычислительным машинам, системам и сетям; . 20 32 158 Дейтел, Х.М. Как программировать на Java. - М : Бином . Вид исследований* Источник финансир- ования Объем финанси- рования, .

Основы теоретической психологии

. формирова психических функций (алгоритмизация обучения, поэтапное фор . выступая в присущей научной теории программирующей роли ц отношению к соответствующей . И здесь принцип деятельностного опос-^ования оказывается системообразующим, объяснительным и .

Основы теоретической психологии

. формирова психических функций (алгоритмизация обучения, поэтапное фор . выступая в присущей научной теории программирующей роли ц отношению к соответствующей . И здесь принцип деятельностного опос-^ования оказывается системообразующим, объяснительным и .

Нажмите, чтобы узнать подробности

Создать приложение, показывающее рисунки с помощью основного меню, предусмотреть выход для закрытие приложения.

Меню – набор возможных команд, из которых надо выбрать одну. Меню, содержащее меню следующего уровня, называется вложенным меню.

Создание основного меню для показ изображений

Цель работы: Ознакомиться с основными средствами разработки оконных приложений на основе объектно-ориентированной среды Lazarus с использованием меню.

Выработка навыков:

Запуск программы и разработка интерфейса программного продукта.

Тестирование программного продукта.

Устранение ошибок в коде программного продукта.

Задание: Создать приложение, показывающее рисунки с помощью Главного и контекстного меню, предусмотреть выход и закрытие приложения.

Меню – набор возможных команд, из которых надо выбрать одну. Меню, содержащее меню следующего уровня, называется вложенным меню. Контекстное меню – меню, открывающееся при щелчке по необходимому объекту. Данное меню является вложенным, так как содержит пункты, в которых имеются подпункты.

Выполнить последовательно действия:

Запустить систему Lazarus и создать новый проект (Файл-Создать-Приложение).

Добавить компонент Image1 (для просмотра картинок).

Открыть в Палитре компонентов вкладку Standard (Стандартные).

Выбрать компонент MainMenu (Строка меню) и поместить его на форму.


Меню – это не простой объект, а взаимосвязанный объект, т.к. каждый пункт меню является отдельным объектом и обладает своими свойствами. Значок меню на форме – инструмент, который позволит получить доступ к специальному редактору меню. Структура меню имеет, например такой вид:

Запустить редактор меню, дважды щелкнув на значке меню на форме.


Записать пункт меню в Инспекторе объектов как Файл


Система присвоит объекту имя MainItem.

Ввести последовательно пункты меню: для этого правой кнопкой мыши создаем пункты подменю.


Закрыть редактор меню и проверить наличие меню в верхней части формы.


Запрограммировать показ картинок:

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


Добавить в эту процедуру единственный оператор:


ПУТЬ должен содержать имя диска, папки и файла с расширением, например: C:\lazarus\oblaka.bmp

Выбрать в строке меню на форме пункт Лес, будет создана процедура для обработки этого пункта.

Добавить в эту процедуру единственный оператор:



ПУТЬ должен содержать имя диска, папки и файла с расширением, например: C:\Windows\Лес.bmp

Проверить работу программы. Отладить в случае ошибок, которые появляются в Окне отладчика.

Программированию нельзя научить, можно только научится

Главное меню — компонент MainMenu

Это невизуальный компонент, т.е. место его размещения на форме в процессе проектирования не имеет никакого значения для пользователя — он все равно увидит не сам компонент, а только меню, сгенерированное им.

Дизайнер меню


Вызов дизайнера меню осуществляется двойным щелчком по компоненту MainMenu.

Дизайнер меню работает в паре с окном свойств. Создание и удаление пунктов осуществляется в дизайнере меню, а свойства отдельно взятого пункта устанавливаются в окне свойств.


Задание 1. Установите на форму компонент MainMenu. Вызовите дизайнер меню. Щелкните по рамке с точками в дизайнере меню. Перейдите в объектный инспектор и в свойстве Caption введите заголовок пункта меню File.

В компоненте MainMenu существует свойство AutoHotKeys. Если оно установлено в значение maAutomatic, то подбор горячих клавиш выполняется автоматически.


Задание 2. Сейчас под пунктом File нужно создать подчиненное меню со списком команд. Для этого просто щелкните в дизайнере меню на пункте File. Под пунктом File появится пустая ячейка - заготовка первого пункта выпадающего списка. Выберите этот пункт с помощью мыши и задайте ему в свойстве Caption заголовок Open. . Вместо пустой ячейки появится текст Open. и пустая ячейка переместится ниже.
Действуя по аналогии, добавьте еще три пункта: Save As. , Close и Exit.

Внимание! Не пытайтесь удалить пустой пункт, завершающий список команд - у вас ничего не выйдет. Да это и не требуется, поскольку пустые висячие пункты не отображаются в меню во время работы программы.


Для создания полноценного меню нужны средства вставки и удаления пунктов, создания вложенных меню и прочие. Поэтому в дизайнере меню для каждого отдельно взятого пункта предусмотрено контекстное меню с необходимым набором команд (рисунок 4 и таблица ).

Рисунок 4. Контекстные команды в дизайнере меню

Описание

Вставляет новый пункт.

Удаляет выбранный пункт.

Создает в позиции пункта подчиненное меню.

Создание пункта меню

Установить курсор в синюю рамку из точек, обозначающую место расположения нового раздела. Далее в объектном инспекторе необходимо задать заголовок меню (свойство Caption) и нажать клавишу Enter.

Вставка пункта меню

Если вы предварительно выделите какой-то раздел меню и выберите из контекстного меню команду Insert, то рамка нового раздела вставится перед выделенным ранее.

Создание подменю

Из контекстного меню выполнить команду Create Submenu, позволяющую ввести подменю в выделенный раздел (см. подменю раздела Опции на рисунке).

Перемещение пунктов меню

Захватите пункт меню щелчком левой кнопки мыши и, удерживая нажатой кнопку мыши, отбуксируйте его к новой позиции. Таким образом, можно переместить не только отдельный пункт, но и целое подчиненное меню со всеми его пунктами и вложенными меню.

Пункты меню

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

Описание свойства

Caption

Name

имя объекта, соответствующего разделу меню. Очень полезно давать этим объектам осмысленные имена, так как иначе вы скоро запутаетесь в ничего не говорящих именах, типа N21. Куда понятнее имена MFile, MOpen, MSave и т.п.

Shortcut

Default

определяет, является ли данный раздел разделом по умолчанию своего подменю, т.е. разделом, выполняемым при двойном щелчке пользователя на родительском разделе.

Break


используется в длинных меню, чтобы разбить список разделов на несколько столбцов. Возможные значение Break:
mbNone — отсутствие разбиения меню (это значение принято по умолчанию), mbBarBreak и mbBreak — в меню вводится новый столбец разделов, отделенный от предыдущего полосой (mbBarBreak) или пробелами (mbBreak). На рис. ниже показан пример, в котором в разделе 1-3 установлено значение Break = mbBreak, а в разделе 1-5 — Break = mbBarBreak.

Рисунок 4. Меню из нескольких столбцов

Checked

установленное в true, указывает, что в разделе меню будет отображаться маркер флажка, показывающий, что данный раздел выбран. Правда, сам по себе этот маркер не изменяется и в обработчик события OnClick такого раздела надо вставлять оператор типа

(в приведенном операторе подразумевается, что раздел меню назван MAutoSave).

RadioItem

Это свойство, установленное в true, определяет, что данный раздел должен работать в режиме радиокнопки совместно с другими разделами, имеющими то же значение свойства GroupIndex. По умолчанию значение GroupIndex равно 0. Но можно задать его большим нуля и тогда, если имеется несколько разделов с одинаковым значением GroupIndex и с RadioItem = true, то в них могут появляться маркеры флажков, причем только в одном из них (на рис.свойство RadioItem установлено в true в разделах Шаблон 1 и Шаблон 2, имеющих одинаковое значение GroupIndex).
Управлять переключениемы радиокнопок придется с помощью программного кода.

Bitmap

Изображение из указанного вами файла в пункте меню

ImageIndex

индекс изображения, хранящегося во внешнем компоненте ImageList. Указание на этот компонент вы можете задать в свойстве Images компонента MainMenu. Индексы начинаются с 0. Если вы укажете индекс -1 (значение по умолчанию), изображения не будет.


По аналогии с остальными классами компонентов можно было бы предположить, что в палитре компонентов существует компонент MenuItem. Однако его там нет, поскольку пункты меню не существуют сами по себе, а работают только в составе строки главного меню или окна контекстного меню. Тем не менее, они во многом ведут себя как настоящие компоненты, например, настраиваются в окне свойств и наряду с остальными компонентами помещаются в исходный текст формы в виде отдельных полей. Чтобы в этом убедиться, активизируйте редактор кода и найдите определение класса формы. Оно будет таким, как на рисунке ниже.

Разделительные линии

Логически связанные между собой команды принято отделять от других команд горизонтальной линией. Например, пункт Exit хорошо бы отделить от остальных (рисунок 8.8).


Задание 3: создать разделитель перед пунктом меню Exit. Для этого щелкните правой кнопкой мыши по пункту Exit и в открывшемся меню выберите Insert. В свойстве Caption укажите символ минуса (-).

Рисунок 8.8. Разделительная линия в меню

Комбинации клавиш

Некоторым пунктам меню назначают комбинации клавиш (shortcut), чтобы выполнять команды, не открывая меню. Они ускоряют работу с приложением и популярны среди опытных пользователей. Названия комбинаций клавиш отображаются справа от текста соответствующих пунктов. Например, во многих программах команде меню File / Open. назначается комбинация клавиш Ctrl+O.


Задание 4: выделите пункт Open в дизайнере меню, в объектном инспекторе выберите в списке значений свойства ShortCut требуемую комбинацию клавиш (рисунок).


Задание 5. Создайте пункты меню, показанные на рисунке 1.
Картинки для меню взять из папки C:/Program Files/Common Files/Borland Shared/Images/Buttons.

Контекстное всплывающее меню — компонент PopupMenu

Контекстное меню привязано к конкретным компонентам. Оно всплывает, если во время, когда данный компонент в фокусе, пользователь щелкнет правой кнопкой мыши.
Поскольку в приложении может быть несколько контекстных меню, то и компонентов PopupMenu может быть несколько. Оконные компоненты: панели, окна редактирования, а также метки и др. имеют свойство PopupMenu, которое по умолчанию пусто, но куда можно поместить имя того компонента PopupMenu, с которым будет связан данный компонент.
Формирование контекстного всплывающего меню производится с помощью Конструктора Меню, вызываемого двойным щелчком на PopupMenu, точно так же, как это делалось для главного меню.

Почти для всех проектов на микроконтроллере с экранчиком требуется система меню. Для каких-то проектов одноуровневое, для других — многоуровневое древовидное. Памяти, как обычно, мало, поэтому хочется запихнуть все во флэш.

Попутно, из проекта в проект, развивалась своя псевдоОС — таймеры, события, диспетчеры.
Я ее полностью писал на си, оптимизацией и вылизыванием еще не занимался.

Перебирая разные системы, наткнулся на MicroMenu:

Попробуем разобрать ее на части и прикрутить к системе.

Структура данных:
Меню организовано в виде четырехсвязного списка. Каждый элемент меню (пункт меню) ссылается на предыдущего и последующего элемента, также ссылается на своего родителя (пункт меню предыдущего уровня) и потомка (пункт подменю). Если это первый пункт, то предыдущего элемента у него нет, соответствующая ссылка пустая.

Изобразим это на рисунке:

Для чего такая избыточность? По сути, с текущим пунктом меню можно сделать четыре вещи:

  • Перейти вверх или вниз (предыдущий или следующий пункт)
  • Вернуться в родительское меню (если есть)
  • Выбрать текущий пункт. При этом мы или переходим в подменю (ели оно есть), или выполняется команда, прикрепленная к этому пункту меню.

Соответственно, все эти действия отражают четыре указателя. В оригинальной системе указатель на потомка обозван SIBLING, но я считаю это идеологически неверным. Sibling – это родственник того же уровня. Брат или сестра. Но никак не потомок. Поэтому мы будем использовать идеологически выверенное CHILD.

Итак, описание структуры пункта меню:

Добавлен байт Select – это код команды, привязанный к текущему пункту. Если у данного пункта есть подменю, код нулевой. Также есть поле Text. Капитан Очевидность подсказывает, что это, собственно, текст пункта меню. По расходам памяти — на каждый пункт меню расходуется 9 байт плюс длина текстовой части. И это все — кладется во флеш.

Самое полезное, почерпнутое у MicroMenu – набор дефайнов для быстрого и удобного определения меню.

В чем пафос такой конструкции? Для того, чтобы определить текущий элемент, нам надо указать ссылку на следующий, еще не известный компилятору. Поэтому этот дефайн создает заведомо избыточное количество описаний extern. Это означает, что такой идентификатор будет где-то описан, не обязательно в этом же файле. В качестве бонуса это позволит растащить меню по нескольким файлам, если вдруг возникнет такое неудовлетворенное желание.

Теперь самое интересное: описание структуры меню, как на рисунке.

Естественно, пункты меню можно описывать и вперемешку, в порядке обхода дерева. Типа такого:

MAKE_MENU(m_s1i1, m_s1i2, NULL_ENTRY, NULL_ENTRY, m_s2i1, 0, "Запуск"); // подменю Запуск MAKE_MENU(m_s2i1, m_s2i2, NULL_ENTRY, m_s1i1, NULL_ENTRY, MENU_MODE1, "Режим 1"); MAKE_MENU(m_s2i2, m_s2i3, m_s2i1, m_s1i1, NULL_ENTRY, MENU_MODE2, "Режим 2"); MAKE_MENU(m_s2i3, NULL_ENTRY,m_s2i2, m_s1i1, NULL_ENTRY, MENU_MODE3, "Режим 3"); MAKE_MENU(m_s1i2, m_s1i3, m_s1i1, NULL_ENTRY, m_s3i1, 0, "Настройка");

Можно даже пойти дальше — строить меню в какой-нибудь визуальной среде, а потом автоматически генерировать такой список. Но это на потом.

Плюсы и минусы такой организации. Минус — явная избыточность. Плюс — возможность быстро редактировать меню — вставить новый пункт, поменять местами, удалить. Изменяются только соседние элементы меню, без тотальной перенумерации. Мне этот плюс перевесил все остальные минусы.

Опять же бонус — можно организовать несколько не связанных друг с другом деревьев меню. Главное не потерять точку входа.

Дальше. Как ходить по меню. Автор предлагает несколько дефайнов. Я их сохранил, хотя можно и без них обойтись.

Вроде должно быть понятно. Выполняется проверка, если есть куда переходить, то переходим. Иначе — не переходим. Вызывается эта процедура таким образом:

Далее, процедура реакции на нажатие клавиш (в качестве параметра передается код нажатой клавиши):

Процедура отрисовки меню. Зависит от выбранного экранчика, а также от используемой анимации при выборе. Например у меня экранчик 128х64 точки, текущий пункт меню всегда по середине экрана, сверху и снизу выводятся два предыдущих и два последующих элемента (если есть). Отрисовка вызывается после каждого нажатися на кнопку и по таймеру, два раза в секунду. Мало ли, может изменится что.
В шапке можно выводить текст родителя, чтобы знать, где находимся. Можно двигать курсор по пунктам, а не пункты прокручивать. На вкус и цвет все фломастеры разные.

И последний штрих — инициализация меню:

Для начала хватит. В продолжении — сделать несколько меню, сделать процедуру работы с меню реентерабельной, забабахать модель в протеусе.

Краткое описание того, что делает процедура setHandler — она привязывает обработчик к событию. В данном случае, при возникновении события MSG_KEY_PRESS вызовется функция keyMenu для обработки этого события.

Для демонстрации системы меню, описанной в предыдущем посте, собрал модель в протеусе. На базе двухстрочного LCD-индикатора, контроллераatmega32 и пяти кнопок (влево-вправо-вверх-вниз и выбор). В своих схемах использую джойстики от мобилок, они тоже пятипозиционные. Также воткнул три светодиода, чтобы хоть как-то реагировать на выбор пунктов меню.

Обработка меню:

  • при выборе пунктов Start/Mode 1, Start/Mode 2, Start/Mode 3 загорается соответствующий светодиод
  • при выборе пункта Reset — все светодиоды гаснут
  • после выбора любого конечного пункта, возвращаемся обратно в корень меню.

Некоторые модификации, связанные с моделированием:

  • заменил весь текст на английский, потому что в оригинале модель экранчика не поддерживает русский язык. Да, я знаю, про замену dll, но не у всех она есть, а для просмотра — пойдет.
  • моя боевая библиотека работы с LCD почему-то отказалась работать с моделью. Поэтому взял какую-то первую попавшуюся из древнего проекта.
  • отключил автоповтор кнопок (на модели неудобно работать), но он есть

Ну и, надеюсь, мне простят подключение светодиодов без балластного резистора? ;)

Файлы к статье

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.

121 thoughts on “Организация древовидного меню”

Прикольно.
А как организовать такое меню на 7-сегментных индикаторах?

А в чем проблема то? Поменяй тип отображения только и всего. А в поле текст загони какой нибудь 7сег код спецсимвола, который у тебя будет отвечать за имя пункта меню.

Все то же самое, только вместотекста — цифры )

Проектик, не помешал бы.

В конец знакогенератора (здесь это DcMatrix) дописываем новых символов (например А Б В Г Е и т.п.). Дальше просто выводим символы как и обычные цифры, только что код >9.

P.S. Надеюсь не сильно туплю, время позднее …

На холодильных установках стоят веселые менюшки :) Как они бедные извращались, чтобы названия параметров вместить в 3 семисегментника …

Так что сделать реально, правда русские буквы плохо выходят из палок, да и английские далеко не все.

Просто пронумеровать пункты, а расшифровку в инструкцию. И пусть читают.

namespace LedTest
public partial class Form1 : Form
bool ledOn = false; // Флаг включен (true) или нет (false) светодиодик на плате
ushort vid = 0x16C0, pid = 0x05DC; // Тут комментарии излишни — это VID и PID
ATMega8 dev; // Объявляем объект типа ATMega16(так в оригинале я заменил на М8)

public Form1()
InitializeComponent();
>

>
Close();
>
else // Если все хорошо, настроим микроконтроллер по USB
dev.DDRB |= 0x3f; // Пины bx00111111 порта B — на вывод
dev.PORTB &= 0x00; // Выключим светодиодик на плате
dev.DDRC |= 0x3f; // Пины bx00111111 порта C — на вывод
dev.PORTC &= 0x00; // Выключим светодиодик на плате
dev.DDRD |= 0xeb; // Пины bx11101011 порта D — на вывод
dev.PORTD &= 0x00; // Выключим светодиодик на плате
//dev.DDRA |= 0x55; // для меги 16-32
//dev.PORTA &= 0x00; // Выключим светодиодик на плате
>
>

// работа с портом B ++++++++++++++++++++++++++++++++++++++++++++++++++++++
private void button1_Click(object sender, EventArgs e)

ledOn = !ledOn;
if (ledOn)

dev.PORTB |= 0x01; // Включим светодиодик на плате
//System.Threading.Thread.Sleep(5000); // это таймер

dev.PORTB &= 0x00; // Выключим светодиодик на плате
dev.PORTC &= 0x00; // Гасим все в порту С это на пробу!
dev.PORTD &= 0x00; // Гасим все в порту D это на пробу!
panel1.BackColor = Color.LightYellow;
panel2.BackColor = Color.LightYellow;
panel3.BackColor = Color.LightYellow;
panel4.BackColor = Color.LightYellow;
panel5.BackColor = Color.LightYellow;
panel6.BackColor = Color.LightYellow;
panel7.BackColor = Color.LightYellow;
panel8.BackColor = Color.LightYellow;
panel9.BackColor = Color.LightYellow;
panel10.BackColor = Color.LightYellow;
panel11.BackColor = Color.LightYellow;
panel12.BackColor = Color.LightYellow;
panel13.BackColor = Color.LightYellow;
panel14.BackColor = Color.LightYellow;
panel15.BackColor = Color.LightYellow;
panel16.BackColor = Color.LightYellow;
panel17.BackColor = Color.LightYellow;
panel18.BackColor = Color.LightYellow;

> это часть кода
Смысл в том что я удаленно перегружаю зависшие устройства, там реле стоят. Только надо б чтоб если комп завис а реле само вернулось в исходное состояние-5 сек.
Памагите!

Есть небольшое замечание:

Более удобная реализация делается на многомерных массивах, не нужно указывать детей, соседей и родителей.
Плюс вместо кода операции лучше сделать ссылку на колбек функцию.

По поводу колбэк функции. Да, в оригинале было сделано именно так. В моей парадигме — возникает событие
sendMessage(MSG_MENU_SELECT, sel);
а кто его будет обрабатывать — это не головная боль меню.

не нужно запоминать иерархию, нужно запомнить только текущий путь меню.
делается это массивом размером в максимальную глубину дерева.

Здесь речь не идет о супер-скоростной обработке информации, типа сотни тысяч раз в секунду. Даже если работа с этим деревом будет затянется на десятки миллисекунд (что очень и очень врядли), то все равно это будет быстрее, чем скорость обновления картинки на недорогом ЖК индикаторе. Более приоритетные прерывания во время выполнения этой задачи — тоже не проблема, пусть себе выполняются.

Здесь мне кажется удобство разработки и объем занимаемой памяти заметно более важно, чем быстродействие.

А вообще, наваять свою удобную и себе понятную архитектуру поддержки меню является весьма хорошим упражнением по программизму.

А если меню неоднородное, а имеет разную глубину, то получим на массивах большую избыточность по занимаемым данным.

Да, зато нету необходимости ручной работы. Забудешь ссылку поменять (изменилось имя переменной) и кушай гемморой с битой ссылкой. А тут можно компактно обработать рекурсивной функцией. Да займет больше ресурсов, зато красивое и масштабируемое решение. Конечно если пишешь для Тини прийдётся немного попрыгать на углях :3

А я делал подобную систему на нескольких массивах структур — получилось довольно компактно (почти без дыр) и удобно. А главное — почти всё в статике, кроме полей ввода/вывода. Правда доделать до конца пока ещё не успел (появился срочный проект), как руки дойдут, может опишу поподробнее.

Что в данном случае контекст? Какие-то внешние переменные?

Я наоборот хочу все упихать в один модуль, чтобы процедура стала реентерабельной.

Ето меню для WinAVR или еще для Codevision подойдет?

WinAVR. Диалекта Codevision не знаю, скорее всего будут различия в работе с флэшем. А так — связный список он и в Африке связный список.

Переход вправо имхо логичней было бы повесить на кнопку вправо

А он, собственно, и висит на кнопке вправо. Просто, поскольку джойстик пятипозиционный, то нажатие на него такжа приравнивается к движению вправо.

А, точно, это же С… Привык к паскалевскому case.

Проходил через такое описание, когда текст отдельно, а пункты — отдельно.

// массив меню изменения режима меню
PROGMEM t_menu m_mode[] = item_sim(mmm1,menu_one),
item_sim(mmm2,menu_multi)
>;

Мозг можно поломать увидев m_s1i1 — что это.
Только скачав оригинал, понял что имелось ввиду что то типа Level1Item1.

А названия в принципе-то и не важны. Если принять второй формат описания, когда подпункты меню идут сразу вслед за родительским пунктом, то структура меню будет видна и так, невооруженным глазом.

У меня тоже как-то встала проблема постоения меню. Честно говоря смотреть что-то готовое даже в голову не приходило, да и тогда наверное этого не так много было. Писал я на Си, знаю я правда его достаточно посредственно( всякие тайпдефы, указатели и прочее я практически не знаю и очень редко применяю, из-за чего иногда получается громоздко).

Задача была аналогичная — сделать меню, на экранчике 128х64, древовидное. Причем напротив некоторых пунктов нужно было сделать чекбокс, а в некоторых возможность ввода чисел, не выходя из интерфейса меню. Впрочем это больше проблемы отображения чем построения самого меню.
Структуру меню я решил хранить ввиде строки для минимального использования памяти

^ — означает начало новой страницы меню,
| — разделяет пункты меню. причем первая строчка после ^ является заголовком страницы, а не пунктом
$ — означает то место куда должно вписываться число, которое можно редактировать с клавиатуры.

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

Кроме всего этого необходимы таблицы переходов, которые выглядели так(специально укоротил чтобы суть ясна была):

//указатель меню
flash signed char menu_page[]= < -2, 1, 1, 1, 2, 4, 5, 3>; // номер страницы меню
flash unsigned char menu_line[]= < 0, 0, 1, 2, 1, 4, 6, 0>; // номер пункта меню
flash signed char menu_to_page[]= < 1, 2, 3, 4, 5, -5, -4, -6>; // куда посылает данный пункт меню

Тут следует заметить, что при нажатии на пункт меню может происходить две разные в корне вещи
вариант 1 — мы переходим на следущий уровень меню
вариант 2 — выполняется какое либо нестандартное действие — открытие специального окна, или какие-то действия и возврат в меню.
В первом случае в третьем массиве указывается номер страницы меню. Во втором — пишется отрицательное число. его модуль означает номер специального действия, которые все описаны в программе.

ТАБЛИЦА СО ЗНАЧЕНИЯМИ

// Всякие значения в менюшках
// ПЕРВУЮ КОЛОНКУ ОСТАВИТЬ ПУСТОЙ
flash unsigned char page[]= < 0, 0, 5, 5, 5, 5, 5, 5>; // страница меню
flash unsigned char line[]= < 0, 5, 0, 1, 2, 3, 4, 5>; // пункт меню
unsigned int value[]= < 0, 100, 0, 0, 0,59048, 1, 0>; // значение (хранится в оперативной памяти)
flash unsigned int max_value[]= < 0, 1000, 1000, 255,59048,59048, 255, 255>; // максимально допустимое число
flash unsigned char digits[]= < 0, 4, 4, 3, 5, 5, 3, 3>; // сколько позиций отводить на написание числа(минимум)

ТАБЛИЦА С ЧЕКБОКСАМИ
тут все аналогично. в моей программе они пока не использовались, поэтому и пусто везде.

// чекбоксы в меню
// ПЕРВУЮ КОЛОНКУ ОСТАВИТЬ ПУСТОЙ
flash unsigned char box_page[]= < 0, 0, 0, 0, 0, 0, 0, 0>;
flash unsigned char box_line[]= < 0, 0, 0, 0, 0, 0, 0, 0>;
unsigned char box_value[]= < 2, 2, 2, 2, 2, 2, 2, 2>;

Прочитав как другие люди по-нормальному делают меню, понимаю что можно было наверное намного ровнее сделать :) Особенно всякие таблицы переходов можно было сделать на тайпдефах. Главный недостаток этой схемы — нельзя добавить пункт меню между другими без перенумерации в пределах одной страницы. Впрочем, если часто все это использовать — можно написать редактор, который будет генерить весь код, и тогда все проблемы такого плана отпадут.

Конечно к этому всему нужны функции вывода, но они весьма специфичны ибо писались под один конкретный проект и выкладывать их нет смысла.

>Главный недостаток этой схемы — нельзя добавить пункт меню между другими без перенумерации в пределах одной страницы.

Вот это меня всегда убивало и сподвигло на поиск новой системы.

я сколько ни пробовал прикрутить конечные автоматы, они какие-то нежизнеспособные. Либо количество состояний зашкаливает, либо параллельность надо.

запятую пропустил. Да и дальше — строки 7 и 8 вместе не имеют смысла. Строка 11 — нет метки куда переходить.

с запятой та же ситуация..
а в остальном все в порядке…

понимаете в чем тут дело, прога выполняет подсчет совпадений с маской, счетчик в регистре L

Читайте также: