Перейти к содержимому

Как написать меню на c

  • автор:

Как написать меню на c

Для создания меню в Windows Forms применяется элемент MenuStrip . Данный класс унаследован от ToolStrip и поэтому наследует его функциональность.

Наиболее важные свойства компонента MenuStrip:

  • Dock : прикрепляет меню к одной из сторон формы
  • LayoutStyle : задает ориентацию панели меню на форме. Может также, как и с ToolStrip, принимать следующие значения
    • HorizontalStackWithOverflow : расположение по горизонтали с переполнением — если длина меню превышает длину контейнера, то новые элементы, выходящие за границы контейнера, не отображаются, то есть панель переполняется элементами
    • StackWithOverflow : элементы располагаются автоматически с переполнением
    • VerticalStackWithOverflow : элементы располагаются вертикально с переполнением
    • Flow : элементы размещаются автоматически, но без переполнения — если длина панели меню меньше длины контейнера, то выходящие за границы элементы переносятся
    • Table : элементы позиционируются в виде таблицы

    MenuStrip выступает своего рода контейнером для отдельных пунктов меню, которые представлены объектом ToolStripMenuItem .

    Добавить новые элементы в меню можно в режиме дизайнера:

    Меню в C# и Windows Forms

    Для добавления доступно три вида элементов: MenuItem (объект ToolStripMenuItem), ComboBox и TextBox . Таким образом, в меню мы можем использовать выпадающие списки и текстовые поля, однако, как правило, эти элементы применяются в основном на панели инструментов. Меню же обычно содержит набор объектов ToolStripMenuItem.

    Также мы можем добавить пункты меню в коде C#:

    public partial class Form1 : Form < public Form1() < InitializeComponent(); ToolStripMenuItem fileItem = new ToolStripMenuItem("Файл"); fileItem.DropDownItems.Add("Создать"); fileItem.DropDownItems.Add(new ToolStripMenuItem("Сохранить")); menuStrip1.Items.Add(fileItem); ToolStripMenuItem aboutItem = new ToolStripMenuItem("О программе"); aboutItem.Click += aboutItem_Click; menuStrip1.Items.Add(aboutItem); >void aboutItem_Click(object sender, EventArgs e) < MessageBox.Show("О программе"); >>

    ToolStripMenuItem в конструкторе принимает текстовую метку, которая будет использоваться в качестве текста меню. Каждый подобный объект имеет коллекцию DropDownItems , которая хранит дочерние объекты ToolStripMenuItem. То есть один элемент ToolStripMenuItem может содержать набор других объектов ToolStripMenuItem. И таким образом, образуется иерархическое меню или структура в виде дерева.

    Если передать при добавление строку текста, то для нее неявным образом будет создан объект ToolStripMenuItem: fileItem.DropDownItems.Add(«Создать»)

    Назначив обработчики для события Click , мы можем обработать нажатия на пункты меню: aboutItem.Click += aboutItem_Click

    Отметки пунктов меню

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

    Еще одно свойство CheckState возвращает состояние пункта меню — отмечен он или нет. Оно может принимать три значения: Checked (отмечен), Unchecked (неотмечен) и Indeterminate (в неопределенном состоянии)

    Например, создадим ряд отмеченных пунктов меню и обработаем событие установки / снятия отметки:

    public partial class Form1 : Form < public Form1() < InitializeComponent(); ToolStripMenuItem fileItem = new ToolStripMenuItem("Файл"); ToolStripMenuItem newItem = new ToolStripMenuItem("Создать") < Checked = true, CheckOnClick = true >; fileItem.DropDownItems.Add(newItem); ToolStripMenuItem saveItem = new ToolStripMenuItem("Сохранить") < Checked = true, CheckOnClick = true >; saveItem.CheckedChanged += menuItem_CheckedChanged; fileItem.DropDownItems.Add(saveItem); menuStrip1.Items.Add(fileItem); > void menuItem_CheckedChanged(object sender, EventArgs e) < ToolStripMenuItem menuItem = sender as ToolStripMenuItem; if (menuItem.CheckState == CheckState.Checked) MessageBox.Show("Отмечен"); else if (menuItem.CheckState == CheckState.Unchecked) MessageBox.Show("Отметка снята"); >>

    Клавиши быстрого доступа

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

    public partial class Form1 : Form < public Form1() < InitializeComponent(); ToolStripMenuItem fileItem = new ToolStripMenuItem("Файл"); ToolStripMenuItem saveItem = new ToolStripMenuItem("Сохранить") < Checked = true, CheckOnClick = true >; saveItem.Click+=saveItem_Click; saveItem.ShortcutKeys = Keys.Control | Keys.P; fileItem.DropDownItems.Add(saveItem); menuStrip1.Items.Add(fileItem); > void saveItem_Click(object sender, EventArgs e) < MessageBox.Show("Сохранение"); >>

    Клавиши задаются с помощью перечисления Keys . В данном случае по нажатию на комбинацию клавиш Ctrl + P, будет срабатывать нажатие на пункт меню «Сохранить».

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

    • DisplayStyle : определяет, будет ли отображаться на элементе текст, или изображение, или и то и другое.
    • Image : указывает на само изображение
    • ImageAlign : устанавливает выравнивание изображения относительно элемента
    • ImageScaling : указывает, будет ли изображение растягиваться, чтобы заполнить все пространство элемента
    • ImageTransparentColor : указывает, будет ли цвет изображения прозрачным

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

    Чтобы указать, как разместить изображение, у свойства DisplayStyle надо установить значение Image . Если мы хотим, чтобы кнопка отображала только текст, то надо указать значение Text , либо можно комбинировать два значения с помощью другого значения ImageAndText . По умолчанию изображение размещается слева от текста:

    Изображения в меню в Windows Forms

    Также можно установить изображение динамически в коде:

    fileToolStripMenuItem.Image = Image.FromFile(@"D:\Icons\0023\block32.png");

    КАК добавить меню?

    Сейчас я научу вас добавлять в вашу программу меню. Да, именно то самое меню, без которого не обходится ни одна программа Windows! Теперь меню будет и в вашей программе!
    Меню бывают двух видов — главное меню и всплывающее. Первое размещается в окне под строкой заголовка, второе при правом щелчке мышью на каком-то объекте — рабочем поле, картинке и.т.д.
    Рассмотрим сначала главное меню.

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

    КАК создать простое меню?

    Создайте новый проект, который назовите MyMenu. В пустой проект добавьте файл с текстом первой нашей программы, который назовите MyMenu.cpp. С исходным текстом пока всё понятно. Создайте пустой файл ресурсов и назовите его MyMenu.rc. Включите его в проект. Сейчас в него мы запишем код простого меню.

    //Текст файла MyMenu.rc
    #include «windows.h»

    MainMenu MENU //имя нашего меню MainMenu
    <
    POPUP «Файл» //Всплывающее меню «Файл»

    MENUITEM «Выход», IDM_EXIT //Пункт меню. Ему соответствует идентификатор IDM_EXIT

    Когда вы сохраните файл RC, то увидите, что во вкладке Resource вашего проекта, появится меню с именем MAINMENU.

    Прекрасно. Теперь объявим имя этого меню в тексте программы, как мы это делали для иконок, курсоров и картинок:

    char szMenu[]=»MainMenu»; //разместите этй строку в начале программы

    .
    w.lpszMenuName=szMenu; //теперь поменяем ещё одну строчку.
    // Наконец-то в структуре WNDCLASS появится ссылка на настоящее меню!

    Когда вы скомпилируете и запустите вашу программу, то увидите, что окно обзавелось маленьким хорошеньким меню из одного пункта: «Файл», в котором есть вкладка «Выход», которая, правда, пока не работает.

    Поскольку меню, это своего рода, дочернее окно, ему нужен свой цикл обработки сообщений, чтобы задавать реакцию на выбор соответствующего пункта. Например, когда пользователь выберет пункт «Выход», программа должна завершить свою работу. Когда нажмёт «О программе. » — выдать небольшое диалоговое окно. Всё это прописывается в этом цикле.

    КАК применить меню на практике?

    Поразмышляем. Каждый пункт главного меню (на языке ресурсов POPUP) содержит пункты MENUITEM, которые содержат текст меню. Каждому пункту соответствует идентификатор, вроде IDM_EXIT. Идентификатор обычно начинается с префикса IDM_ (Identifer menu). В библиотечном файле содержатся идентификаторы пунктов меню.
    Если в меню нужно вставить разделитель, которым обычно отделяют пункт «Выход» от остальных в меню «Файл», пишут так:

    MENUITEM SEPARATOR //разделитель

    Разделитель объявляется без идентификатора.

    Если вы хотите, чтобы длинное меню состояло из двух колонок, начиная с этого пункта, добавляется слово MENUBARBREAK:

    MENUITEM «&Disk space», IDM_FREE, MENUBARBREAK //начиная с этого
    //пункта, меню будет идти в соседнем столбике.

    Если надо сделать подменю, применима следующая конструкция:

    POPUP «&User Name»
    MENUITEM «User &number», IDM_NUM

    POPUP «User &status»
    MENUITEM «A&dministrator», IDM_ADMIN
    MENUITEM «&Guest», IDM_GUEST
    >

    Таким образом, вкладка «User status» будет содержать подменю из двух пунктов: Administrator и Guest.

    И ещё. Вы, наверное, обратили внимание на знак &, который я старательно вставляю между слов. Смысл его такой. Чтобы дать доступ пользователю к пунктам меню с клавиатуры, программист пишет знак амперсанд & перед той буквой, нажав которую, пользователь может выбрать этот пункт. Тогда в меню слово «Файл» (&Файл) , будет записано, как Файл, и если я нажму Alt+Ф, то перейду на этот пункт. Сейчас уже трудно представить себе пользователя, работающего в Windows XP без мышки.
    Но признаком хорошего стиля программирования служит введение во все пункты возможности быстрого доступа с клавиатуры. Один из постулатов программирования: «Не надо решать за пользователя!». Да и меню без знаков подчёркивания выглядит каким-то голым.

    Отдельно будет сказано о картинках в меню (это не так уже часто и нужно), а также о так называемых акселлераторах клавиатуры — специальной таблицы условленных сочетаний клавиш (Ctrl+O, Ctrl+N, Shift+Ins), нажав которые, пользователь тем самым вызовет обработку нажатия того пункта меню, которому соответствует это сочетание. Например пункт «Правка->Выделить всё» имеет клавиатурный эквивалент Ctrl+A. Согласитесь, что гораздо удобнее набирая текст нажать Ctrl+S для быстрого сохранения, чем браться за мышку и лезть в меню.

    Теперь вы знаете всё, что нужно о синтаксисе меню в файле ресурсов. Для быстрого создания меню существует редактор ресурсов Visual C++. Добавив новый ресурс с помощью Ctrl+R, вы даёте ему имя. Во вкладке MENU появляется новое меню. Стоит щёлкнуть по нему два раза, и на экране появляется его схема, в которую вы можете вписывать новые пункты, добавлять разделители и вкладки, не прикладывая для этого никаких усилий.

    Все свойства меню и его пунктов задаются через окно Properties.

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

    switch(LOWORD(wParam))

    //Выбор пункта с идентификатором IDM_ADMIN
    case IDM_ADMIN: <
    .
    break;
    >

    //Выбор пункта, расположенного ниже
    case IDM_GUEST: <
    .
    break;
    >

    >


    .
    >

    Как видите, всё просто. Перехватываем значение wParam при поступлении WM_COMMAND. Раскладываем по полочкам наше меню и выполняем соответствующие процедуры.
    Далее я привожу полный текст программы с использованием меню.

    КАК использовать всю мощь меню?

    Сейчас мы слегка дополним наш файл ресурсов, после чего в маленьком меню заметно прибавится пунктов. Конечная цель — создать что-то вроде системной утилиты, которая узнаёт сколько всего места у нас на диске, сколько на нём осталось свободного пространства и как называется текущая папка. В другом пункте меню можно будет узнать текущую дату и время, а в третьем — имя пользователя и имя компьютера. Все эти знания нам очень пригодятся.

    //Текст файла MyMenu.h
    //Каждому пункту по личному номеру!
    #define IDM_EXIT 1
    #define IDM_DSPACE 2
    #define IDM_FREE 3
    #define IDM_CURRENT 4
    #define IDM_ABOUT 5
    #define IDM_TIME 6
    #define IDM_DATE 7
    #define IDM_ACOMP 8

    //Текст файла MyMenu.rc
    #include «MyMenu.h»
    #include «windows.h»

    MainMenu MENU
    //1-й пункт меню
    POPUP «&Файл»
    MENUITEM «В&ыход», IDM_EXIT
    >

    //2-й пункт меню
    POPUP «&Диск»
    MENUITEM «Всего на диске», IDM_DSPACE
    MENUITEM «Свободное место», IDM_FREE
    MENUITEM «Текущая папка», IDM_CURRENT
    >

    //3-й пункт меню
    POPUP «Дата и время»
    MENUITEM «Дата», IDM_DATE
    MENUITEM «Время», IDM_TIME

    //4-й пункт меню
    POPUP «О компьютере»
    MENUITEM «Имя пользователя», IDM_ABOUT
    MENUITEM «Имя компьютера», IDM_ACOMP

    //5-й пункт меню
    POPUP «&Помощь»
    MENUITEM «О программе», IDM_ABOUT
    >

    #include «MyMenu.h»

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

    char szProgName[]=»Имя программы»;
    char str[]=»Мой текст!»;
    char szMenu[]=»MainMenu»;
    char szMessage[]=»Выберите нужный пункт меню.»;
    short sLen;

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
    HWND hWnd;
    MSG lpMsg;


    WNDCLASS w;
    w.lpszClassName=szProgName; //имя программы
    w.hInstance=hInstance;
    w.lpfnWndProc=WndProc; //указатель на функцию окна
    w.hCursor=LoadCursor(NULL, IDC_ARROW);
    w.hIcon=LoadIcon(NULL, IDI_APPLICATION);
    w.lpszMenuName=szMenu; //имя нашего меню
    w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //цвет фона окна
    w.style=CS_HREDRAW|CS_VREDRAW; //стиль — перерисовываемое по х и по у
    w.cbClsExtra=0;
    w.cbWndExtra=0;

    //Если не удалось зарегистрировать класс окна — выходим
    if(!RegisterClass(&w))
    return 0;

    //Создадим окно в памяти, заполнив аргументы CreateWindow
    hWnd=CreateWindow(szProgName,
    «Демонстрация меню в Win32 API»,
    WS_OVERLAPPEDWINDOW,
    100,
    100,
    500,
    400,
    (HWND)NULL,
    (HMENU)NULL,
    hInstance,
    (LPSTR)NULL);

    //Выводим окно из памяти на экран
    ShowWindow(hWnd, nCmdShow);
    //Обновим содержимое окна
    UpdateWindow(hWnd);

    //Функция окна
    LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
    WPARAM wParam, LPARAM lParam)
    HDC hdc; //создаём контекст устройства
    PAINTSTRUCT ps; //создаём экземпляр структуры графического вывода

    //дисковая информация
    unsigned long lSectInClust, lByteInSect, lNumFreeClust, lNumClust, lTotal, lBuf, lBuf1;
    char szCurrent[MAX_PATH];

    //информация о дате и времени
    SYSTEMTIME st;
    WORD month, day, year, hour, min, sec;

    //идентификация имени пользователя и компьютера
    char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
    unsigned long len_ComputerName = MAX_COMPUTERNAME_LENGTH + 1;
    char UserName[256 + 1];
    unsigned long len_UserName = 256 + 1;

    //Цикл обработки сообщений
    switch(messg)

    case WM_COMMAND:
    switch(LOWORD(wParam))

    //Выход из программы
    case IDM_EXIT: DestroyWindow(hWnd);

    //Сколько места на диске?
    case IDM_DSPACE:
    GetDiskFreeSpace(NULL, &lSectInClust, &lByteInSect, &lNumFreeClust, &lTotal);
    lBuf1=lSectInClust*lByteInSect*lTotal;
    sLen=sprintf(szMessage, «Всего на диске: %ld Мб», lBuf1/1000000);
    break;

    //Свободно на диске
    case IDM_FREE:
    GetDiskFreeSpace(NULL, &lSectInClust, &lByteInSect, &lNumFreeClust, &lTotal);
    lBuf=lSectInClust;
    lBuf*=lByteInSect;
    lBuf*=lNumFreeClust;
    sLen=sprintf(szMessage, «На диске свободно: %ld Мб», lBuf/1000000);
    break;

    //Текущая папка
    case IDM_CURRENT:
    GetCurrentDirectory(MAX_PATH, szCurrent);
    sLen=sprintf(szMessage, «Тек. папка %s», szCurrent);
    break;

    //Текущее время
    case IDM_TIME:
    GetSystemTime(&st);

    min=st.wMinute;
    sec=st.wSecond;
    hour=st.wHour;
    if(min <10)
    sLen=sprintf(szMessage, «Время: %d:0%d:%d», hour, min, sec);
    else
    sLen=sprintf(szMessage, «Время: %ld:%d:%d», hour, min, sec);
    break;

    //Текущая дата
    case IDM_DATE:
    GetSystemTime(&st);
    year=st.wYear;
    month=st.wMonth;
    day=st.wDay;
    if(month <10)
    sLen=sprintf(szMessage, «Дата: %d/0%d/%d», day, month, year);
    else
    sLen=sprintf(szMessage, «Дата: %d/%d/%d», day, month, year);
    break;

    //Имя компьютера
    case IDM_ACOMP:

    if( comp != 0 )
    <
    sLen=sprintf(szMessage, «%s», ComputerName);
    >
    else
    MessageBox(hWnd, «Имя компьютера не доступно!», «Сообщение:», MB_OK|MB_ICONSTOP);

    //Имя пользователя
    case IDM_ABOUT:

    comp = GetUserNameA (UserName, &len_UserName);

    if( comp != 0 )
    <
    sLen=sprintf(szMessage, «%s», UserName);
    >
    else
    MessageBox(hWnd, «Имя пользователя не доступно!», «Сообщение. «, MB_OK|MB_ICONSTOP);

    >
    InvalidateRect(hWnd, NULL, TRUE);
    break;

    //Вывод строки на экран
    case WM_PAINT:
    hdc=BeginPaint(hWnd, &ps);
    TextOut(hdc, 10,10, szMessage, sLen);
    ValidateRect(hWnd, NULL);
    EndPaint(hWnd, &ps);
    break;

    //Завершение работы окна
    case WM_DESTROY:
    PostQuitMessage(0);
    break;

    default:
    return(DefWindowProc(hWnd, messg, wParam, lParam));
    >
    return 0;
    >

    Программа работает так. Строка текста szMessage, длиной sLen выводится на экран только при поступлении сообщения WM_PAINT. Каждый раз выделять контекст при выборе пункта меню мы бы замучились. При выборе каждого пункта, мы просто заполняем строку szMessage какой-либо информацией и вычисляем её длину sLen. Функция InvalidateRect отвечает за перерисовывание экрана, а значит передаёт ему сообщение WM_PAINT. Так как содержимое строки изменилось, на экране будет новое значение. Вот синтаксис функции перерисовки:

    InvalidateRect(hWnd, NULL, TRUE);

    Этот приём всегда очень выручает. Сообщение WM_PAINT остаётся нетронутым, меняются только числа введённые пользователем. А график рисуется совсем по-иному!

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

    1. Дисковые операции.
    case IDM_DSPACE:
    GetDiskFreeSpace(NULL, &lSectInClust, &lByteInSect, &lNumFreeClust, &lTotal);
    lBuf1=lSectInClust*lByteInSect*lTotal;
    sLen=sprintf(szMessage, «Всего на диске: %ld Мб», lBuf1/1000000);
    break;

    Выше были объявлены переменные: lSectInClust (секторов в кластере), lByteInSect (байт в секторе), lNumFreeClust (число свободных кластеров), lTotal (всего число кластеров). Функция GetDiskFreeSpace заполнила эти переменные реальными значениями этих параметров вашего жёсткого диска. lBuf — буфер, в который мы записали произведение: количество кластеров в секторе * число байт в кластере * общее число кластеров. Таким образом lBuf будет содержать количество байт на жёстком диске. Если изменить в формуле общее число кластеров на общее число свободных кластеров, мы узнаем, сколько свободных байт на винчестере.

    2.Текущая папка
    GetCurrentDirectory(MAX_PATH, szCurrent);
    sLen=sprintf(szMessage, «Тек. папка %s», szCurrent);

    Как мы уже говорили, MAX_PATH — константа, в которую записана длина максимально допустимого пути в Windows. Функция GetCurrentDirectory записывает в строку szCurrent текущий путь. Функция полностью поддерживает длинные имена, в отличие от старых API функций в Win16. В старых программах, написанных на Visual C++ 1.0, часто при добавлении какой-то папки можно увидеть дерево своего диска с обрубленными путями.

    3.Системное время
    case IDM_TIME:
    GetSystemTime(&st);

    min=st.wMinute;
    sec=st.wSecond;
    hour=st.wHour;
    if(min <10)
    sLen=sprintf(szMessage, «Время: %d:0%d:%d», hour, min, sec);
    else
    sLen=sprintf(szMessage, «Время: %ld:%d:%d», hour, min, sec);
    break;

    Структура, отвечающая за время прописана в библиотеке time.h. Она называется SYSTEMTIME. Создав экземпляр этой структуры, мы заполняем его поля функцией GetSystemTime. Затем мы присваиваем нашим переменным min, hour, sec значения этих полей: st.wMinute, st.wSecond, st.wHour. Если число минут меньше десяти, время будет отражаться так: 1:9:27, что неприемлемо. Поэтому неплохо будет отследить число минут меньшее 10 и добалять нолик. Можно это сделать и для секунд, но они не так бросаются в глаза.
    С датой всё то же самое, только используем другие поля: st.wYear, st.wMonth. Кстати есть ещё поля: st.wDayOfWeek (день недели), st.wMilliseconds — число милисекунд.

    4. Переменные окружения. Окружением называются окружающие нас важные данные: имя пользователя (в многопользовательских системах типа Windows 2000 (NT) это очень актуально), имя папки временных файлов Temp; имя компьютера, которое ему дали при установке Windows, путь в котором размещена папка Windows. Все эти данные используются серьёзными программами, которые привносят в систему свои драйвера, библиотеки DLL, файлы инициализации INI, и им просто необходимо знать путь системной папки. Тем не менее, получить доступ к этим данными предельно просто. Рассмотрим работу с такими функциями на примере получения имени компьютера.

    char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
    unsigned long len_ComputerName = MAX_COMPUTERNAME_LENGTH + 1; //длина имени
    BOOL comp; //признак того, можно ли получить эту информацию

    .
    case IDM_ACOMP: //выбрали соответствующий пунктик меню

    if( comp != 0 ) //Если информация доступна,
    <
    sLen=sprintf(szMessage, «%s», ComputerName); //формируем строку
    >
    else
    //сообщение об ошибке, если нет доступа к переменным окружения
    MessageBox(hWnd, «Имя компьютера не доступно!», «Сообщение:», MB_OK|MB_ICONSTOP);

    КАК работают акселлераторы клавиатуры?

    Совсем недавно мы работали с клавиатурой и обрабатывали сообщения: WM_KEYDOWN, WM_CHAR и другие. Там мы сталкивались с понятием виртуальных клавиш, и я привёл таблицу кодов этих клавиш. Например ENTER обозначался, как VK_RETURN, ESC — VK_ESCAPE и.т.д.
    Оказывается, можно очень просто связать конкретный идентификатор меню (IDM_EXIT, IDM_OPEN) с какой-нибудь виртуальной клавишей: Ctrl+Q, Ctrl+O.
    Добавим в проект новый ресурс, нажав Ctrl+R. В окне выбора ресурса выберем первую строчку Accelerator.
    Во влкадке ресурсов нашего приложения появится папочка Accelerator, в которой будет новый для всех нас ресурс: IDR_ACCELERATOR1. Первым делом переименуем его в IDR_MYACCEL. Считается плохим тоном программирования оставлять имена элементов управления, диалоговым окон и файлов, данные автоматически. Попробуй разобраться в программе с двадцатью окнами, которые называются IDD_DIALOG1, IDD_DIALOG2. IDD_DIALOGN.
    Теперь щёлкнем дважды по имени IDR_MYACCEL.
    У нас появилось окно редактирования акселлераторов.

    Пользоваться им предельно просто. Мы просто щёлкаем по пустой строке и в диалоговом окне выбираем идентификатор ресурса типа IDM_EXIT и сочетание клавиш, вызывающее его.
    Дважды щёлкните мышью по пустой строке в таблице. Появится окно свойств акселлератора Accel Properties:

    Щёлкните на вкладку ID окна Accel Properties. У вас появится длинный список идентификаторов, среди которых есть даже такие, которых вы не объявляли. Выберите например IDM_EXIT.
    Ниже есть вкладка Key. В ней можно выбрать виртуальную клавишу: VK_RETURN, VK_ESCAPE. или задать её самому. В группе флажков Modifiers определяется сочетание: Alt, Ctrl или Shift. Оставьте флажок на Ctrl и нажмите кнопку Next Key Typed. Появится окно, предлагающее опробовать вашу комбинацию.

    Нажмите Ctrl+Q — то сочетание, которое мы решили задать. Окно распознаёт все сочетания клавиш. Оно автоматически переставит переключатель на Alt или Shift, если вы нажмёте комбинацию с ними.
    Теперь, когда все поля окна свойств акселлератора заполнены, закройте его. В таблице виртуальных клавиш добавилась строчка, в которой есть имя вашего идентификатора и соответствующие ему клавиши. Удобно, не правда ли?

    Меню на Си (в консоли)

    При выборе задание 1 , на месте этого меню появилось следующее меню:

    Ввести из файла
    Записать вручную.

    Дополнен 13 лет назад
    Да. switch — case
    Лучший ответ

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

    short select()<
    char menu;
    printf(«%s\n»,»1.menu_1″);
    printf(«%s\n»,»2.menu_2″);
    printf(«%s\n»,»3.menu_3″);
    menu=getch();
    if (menu < '1' || menu >‘3’) <
    system(«cls»);
    printf(«Select from 1 to 3\n»);
    menu=select();
    >

    return menu;
    >
    int main(int argc, char* argv[])
    <
    char menu;
    menu = select();
    switch (menu)<
    case ‘1’:
    printf(«Ok! select 1\n»);
    break;
    case ‘2’:
    printf(«Ok! select 2\n»);
    break;
    case ‘3’:
    printf(«Ok! select 3\n»);
    break;
    default:
    printf(«Ok! select hren znaet chto\n»);
    break;
    >
    system(«pause»);
    return 0;
    >

    Остальные ответы
    через sitch — case ?

    самое простой вариант сделать цикл выполняй пока ..

    void main ()<
    bool rabotaem; // переменная отвечающая за работу всей программы
    rabotaem=true;
    int nmen; // номер меню
    //———-
    while (rabotaem)<
    cout cin >> nmen;
    cout // здесь можно использовать структуру case — switch( непомню синтаксис, смотри справку)
    // соответственно переход от одного меню к другому осуществлять за счет номера
    if (nmen==1)<
    // здесь действия для первого меню,
    // можно испоьзовть отдельные функции
    // главное меню можно взять как нулевое
    >;
    if (nmen==2)<
    // для второго
    >;
    if (nmen==3)<
    // для третьего
    >;
    if (nmen==0)<
    //здесь главное меню
    >

    Как создать меню на C или C++

    Превью к статье о том, как создать меню для консольного приложения на C/C++

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

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

    Разбиваем программу на пункты

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

    • Добавление товара в список
    • Вывод списка товаров (как минимум для контроля вводимых данных)
    • Вывод товара с наибольшей ценой
    • Вывод товара с наименьшей ценой
    • Выход (иначе программа никогда не сможет завершиться)

    Выводим пункты меню на экран

    Чтобы вывести меню на экран, очистим его и затем просто напечатаем с помощью printf или cout номер пункта и то, что он должен делать:

    Вариант для C:

    void print_menu() < system("cls"); // очищаем экран printf("What do you want to do?\n"); printf("1. Add good to list\n"); printf("2. Print all goods in list\n"); printf("3. Print the highest price\n"); printf("4. Print the lowest price\n"); printf("5. Exit\n"); printf(">"); >

    Вариант для C++

    void print_menu() < system("cls"); // очищаем экран cout "; >

    Считываем введённый пункт меню

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

    Вариант для C:

    int get_variant(int count) < int variant; char s[100]; // строка для считывания введённых данных scanf("%s", s); // считываем строку // пока ввод некорректен, сообщаем об этом и просим повторить его while (sscanf(s, "%d", &variant) != 1 || variant < 1 || variant >count) < printf("Incorrect input. Try again: "); // выводим сообщение об ошибке scanf("%s", s); // считываем строку повторно >return variant; >

    Вариант для C++:

    int get_variant(int count) < int variant; string s; // строка для считывания введённых данных getline(cin, s); // считываем строку // пока ввод некорректен, сообщаем об этом и просим повторить его while (sscanf(s.c_str(), "%d", &variant) != 1 || variant < 1 || variant >count) < cout return variant; >

    Обработка выбранного пункта меню

    Создадим для каждого пункта свой обработчик в виде процедуры, выполняющей указанное действие:

    void add_good(good **goods, int *size, int *capacity) < // реализация процедуры >void print_goods(good *goods, int size) < // реализация процедуры >void print_highest(good *goods, int size) < // реализация процедуры >void print_lowest(good *goods, int size) < // реализация процедуры >

    Чтобы выполнить действие в зависимости от введённого пункта воспользуемся оператором switch-case :

    switch (variant)

    Казалось бы, всё готово, однако пока что программа обработает лишь один пункт меню и затем завершится, хотя должна завершаться лишь при выборе пятого пункта — «выход». Чтобы организовать данный функционал, воспользуемся циклом do-while

    int variant; do < print_menu(); variant = get_variant(5); // получаем номер выбранного пункта меню switch (variant) < case 1: add_good(&goods, &size, &capacity); break; case 2: print_goods(goods, size); break; case 3: print_highest(goods, size); break; case 4: print_lowest(goods, size); break; >if (variant != 5) system("pause"); // задерживаем выполнение, чтобы пользователь мог увидеть результат выполнения выбранного пункта > while (variant != 5);

    Теперь наше меню будет работать до тех пор, пока пользователь не введёт число 5 чтобы выйти. При этом для всех остальных пунктов меню вызывается функция задержки system(«pause») , чтобы после завершения работы выбранного пункта меню нашей консольной программы пункты меню выводились не сразу, а лишь тогда, когда пользователь самостоятельно решит вернуться в него.

    Полный листнинг кода

    #include #include typedef struct good < char name[20]; // название-описание товара double price; // цена товара int count; // количество товара >good; void add_good(good **goods, int *size, int *capacity) < printf("Enter good description: "); scanf("%s", &(*goods)[*size].name); printf("Enter good price: "); scanf("%lf", &(*goods)[*size].price); printf("Enter good count: "); scanf("%d", &(*goods)[*size].count); (*size)++; if (*size >= *capacity) < *capacity *= 2; *goods = (good *)realloc(*goods, *capacity * sizeof(good)); >> void print_goods(good *goods, int size) < printf("+---------------------+-------------+-------+\n"); printf("| good | Price | Count |\n"); printf("+---------------------+-------------+-------+\n"); if (size == 0) printf("| No goods was added. |\n"); for (int i = 0; i < size; i++) printf("| %19s | %11.2lf | %5d |\n", goods[i].name, goods[i].price, goods[i].count); printf("+---------------------+-------------+-------+\n"); >void print_highest(good *goods, int size) < double max = goods[0].price; int imax = 0; for (int i = 1; i < size; i++) < if (goods[i].count >max) < max = goods[i].price; imax = i; >> printf("The highest price of goods is %.2lf (good is %s)\n", max, goods[imax].name); > void print_lowest(good *goods, int size) < double min = goods[0].price; int imin = 0; for (int i = 1; i < size; i++) < if (goods[i].count < min) < min = goods[i].price; imin = i; >> printf("The lowest price of goods is %.2lf (good is %s)\n", min, goods[imin].name); > void print_menu() < system("cls"); // очищаем экран printf("What do you want to do?\n"); printf("1. Add good to list\n"); printf("2. Print all goods in list\n"); printf("3. Print the highest price\n"); printf("4. Print the lowest price\n"); printf("5. Exit\n"); printf(">"); > int get_variant(int count) < int variant; char s[100]; // строка для считывания введённых данных scanf("%s", s); // считываем строку // пока ввод некорректен, сообщаем об этом и просим повторить его while (sscanf(s, "%d", &variant) != 1 || variant < 1 || variant >count) < printf("Incorrect input. Try again: "); // выводим сообщение об ошибке scanf("%s", s); // считываем строку повторно >return variant; > int main() < int variant; // выбранный пункт меню int size = 0; // количество элементов массива товаров int capacity = 1; // ёмкость массива товаров good *goods = (good *)malloc(capacity * sizeof(good)); // выделяем память под массив товаров do < print_menu(); // выводим меню на экран variant = get_variant(5); // получаем номер выбранного пункта меню switch (variant) < case 1: add_good(&goods, &size, &capacity); break; case 2: print_goods(goods, size); break; case 3: print_highest(goods, size); break; case 4: print_lowest(goods, size); break; >if (variant != 5) system("pause"); // задерживаем выполнение, чтобы пользователь мог увидеть результат выполнения выбранного пункта > while (variant != 5); return 0; >

    Демонстрация работы программы

    Демонстрация работы программы с меню

    Фото Кудиновой Светланы, автора этой статьи

    Программист, соосновательница programforyou.ru, рукодельница, всегда готова придти на помощь и помочь во всём разобраться

    Языки программирования: Python, C, C++, Pascal

    Выпускница МГТУ им. Н.Э. Баумана

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

    Copyright © 2017 — 2023 Programforyou — помощь с программированием | programforyou.ru

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *