платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 8 - меню

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 8 - меню

Сообщение  electrik в Вс Июн 28, 2009 8:38 pm

Win32 API. Урок 8. Меню

В этом туториале мы научимся, как вставить в наше окно меню.

Теория:

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

Короче говоря, первые два пункта меню должны быть "File" и "Edit", а последний - "Help". Вы можете вставить ваши собственные пункты между "Edit" и "Help".
Если пункт меню вызывает диалоговое окно, вам нужно заканчивать название пункта эллипсисом (...).

Меню - это разновидность ресурсов. Есть несколько видов ресурсов, таких как диалоговые окна, строковые таблицы, иконки, битмапы, меню и т.д. ресурсы описываются в отдельном файле, называющемся файлом ресурсов, который, как правило, имеет расширение .rc. Вы можете соединять ресурсы с исходным кодом во время компиляции. Окончательный продукт - это исполняемый файл, который содержит как инструкции, так и ресурсы.

Вы можете писать файлы ресурсов, используя любой текстовый редактор. Они состоят из набора фраз, определяющих внешний вид и другие атрибуты ресурсов, используемых в программе. Хотя вы можете писать файлы ресурсов в текстовом редакторе, это довольно тяжело. Лучшей альтернативой является использование редактора ресурсов, который позволит вам визуально создавать дизайн ваших ресурсов. редакторы ресурсов обычно входят в пакет с компиляторами, такими как Visual C++, Borland C++ и т.д.

Вы описываете ресурс меню примерно так:

      MyMenu  MENU
{
[menu list here]
}

Си-программисты могут заметить, что это похоже на объявление структуры. MyMenu - это имя меню, за ним следует ключевое слово MENU и список пунктов меню, заключенный в фигурные скобки. Вместо них вы можете использовать BEGIN и END. Этот вариант больше понравится программистам на Паскале.

Список меню включает в себя выражения 'MENUITEM' или 'POPUP'.

'MENUITEM' определяет пункт меню, который не является подменю. Его синтаксис следующий:

      MENUITEM "&text", ID [,options]

Выражение начинается ключевым словом 'MENUITEM', за который следует текст, который будет отображаться. Обратите внимание на амперсанд. Его действие заключается в том, что следующий за ним символ будет подчеркнут. Затем идет строка в качестве ID пункта меню. ID - это номер, который будет использоваться для обозначения пункта меню в сообщении, посылаемое процедуре окно, когда этот пункт меню будет выбран. Каждое ID должно быть уникальным.

Опции опциональны. Доступны следующие опции:

• *GRAYED - пункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст серого цвета.
• *INACTIVE - пункт меню неактивен, и он не генерирует сообщение WM_COMMAND. Текст отображается нормально.
• *MENUBREAK - этот пункт меню и последующие пункты отображаются после новой линии меню.
• *HELP - этот пункт меню и последующие пункты выравнены по правой стороне.


Вы можете использовать одну из вышеописанных опций или комбинировать их оператором "or". Учтите, что 'INACTIVE' и 'GRAYED' не могут комбинироваться вместе. Выражение 'POPUP' имеет следующий синтаксис:

  POPUP "&text" [,options]
{
[menu list]
}

Выражение 'POPUP' определяет пункт меню, при выборе которого выпадает список пунктов в маленьком popup-окне. Список меню может быть выражением 'MENUITEM' или 'POPUP'. Есть специальный вид выражения 'MENUITEM' - 'MENUITEM SEPARATOR', который отрисовывает горизонтальную линию в popup-окне.

Последний шаг - это ссылка на ваш скрипт ресурса меню в программе.

Вы можете сделать это в двух разных местах.

• В члене lpszMenuName структуры WNDCLASSEX. Скажем, если у вас было меню под названием "FirstMenu", вы можете присоединить меню к вашему окну следующим образом:

wc.lpszMenuName = @"FirstMenu"

• *С помощью параметра-хэндла меню в функции CreateWindowEx:

dim shared hMenu as HMENU
...
...
hMenu = LoadMenu(hInst, "FirstMenu") ' получим хэндл меню
hwnd = CreateWindowEx _
(NULL, _ ' дополнительные стили
"SimpleWinClass", _
@AppName, _
WS_OVERLAPPEDWINDOW, _
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _
CW_USEDEFAULT, _
CW_USEDEFAULT, _
NULL, _
hMenu, _
hInst, _ '
NULL)

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

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

Когда пользователь выберет пункт меню, процедура окна получит сообщение WM_COMMAND. Нижнее слово wParam'а содержит ID выбранного пункта меню.

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

Пример:

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

файл menu.bas
Код:

' меню
#include "windows.bi"
#include "menu.bi"
declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы

end WinMain( GetModuleHandle( NULL ) ,NULL,GetCommandLine() , SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений

function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_COMMAND ' если получили сообщение WM_COMMAND
select case loword(wParam) ' читаем нижнее слово из wParam
case IDM_TEST
MessageBox(NULL,"You selected Test menu item",@AppName,MB_OK)
case IDM_HELLO
    MessageBox(NULL,"Hello, my friend", @AppName,MB_OK)
case IDM_GOODBYE
MessageBox(NULL,"See you again", @AppName, MB_OK)
case IDM_EXIT
DestroyWindow(hWnd)
end select
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function


'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' структура сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
with wc ' заполняем структуру wc
.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
.cbWndExtra = NULL
.hInstance = hInst  ' хэндл модуля
.hbrBackground = cast(HGDIOBJ, COLOR_WINDOW+1) ' Цвет фона
.lpszMenuName = NULL ' хэндл меню меню
.lpszClassName = @ClassName ' имя класса окна
.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
.hIconSm = .hIcon 'Хэндл маленькой иконки
.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
end with

' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(NULL, _ ' дополнительные стили
ClassName, _ ' строка с именем класса окна
AppName, _ ' строка с именем окна
WS_OVERLAPPEDWINDOW, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
CW_USEDEFAULT, _ ' ширина окна
CW_USEDEFAULT, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

ShowWindow( hwnd,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hwnd) ' обновить клиентскую область

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

Файл menu.bi
Код:

#define ClassName "SimpleWinClass" ' класс окна
#define AppName "Our First Window" ' название программы
#define IDM_TEST 32000
#define IDM_HELLO 32001
#define IDM_GOODBYE 32002
#define IDM_EXIT 32003

Файл menu.rc
Код:

#include "menu.bi"
FirstMenu MENU
{
POPUP "&PopUp"
{
MENUITEM "&Say Hello",IDM_HELLO
MENUITEM "Say &GoodBye", IDM_GOODBYE
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}
MENUITEM "&Test", IDM_TEST
}

компилировать:
fbc -s gui menu.rc menu.bas

Анализ:

Давайте сначала проанализируем файл menu.bi.

#define IDM_TEST 32000
#define IDM_HELLO 32001
#define IDM_GOODBYE 32002
#define IDM_EXIT 32003

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

ну а теперь файл ресурсов menu.rc

  FirstMenu MENU

Определите ваше меню ключевым словом 'MENU'.

   POPUP "&PopUp"
{
MENUITEM "&Say Hello",IDM_HELLO
MENUITEM "Say &GoodBye", IDM_GOODBYE
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}

Определите popup-меню с четырьмя пунктами меню, третье - это сепаратор.

  MENUITEM "&Test", IDM_TEST

Определите пункт меню в основном меню.

Далее мы изучим исходный код.

case WM_COMMAND
select case loword(wParam) ' читаем нижнее слово из wParam
case IDM_TEST
MessageBox(NULL,"You selected Test menu item",@AppName,MB_OK)
case IDM_HELLO
   MessageBox(NULL,"Hello, my friend", @AppName,MB_OK)
case IDM_GOODBYE
MessageBox(NULL,"See you again", @AppName, MB_OK)
case IDM_EXIT
DestroyWindow(hWnd)

В процедуре окна мы обрабатываем сообщение WM_COMMAND. Когда пользователь выбирает пункт меню, его ID посылается процедуре окна в нижнем слове wparam'а вместе с сообщением WM_COMMAND. мы сравниваем значение в wparam с ID пунктов меню, определенными ранее, и поступаем соответствующим образом. В первых трех случаях, когда пользователь выбирает 'Test', 'Say Hello и 'Say GoodBye', мы отображаем текстовую строку в messagebox'е.
Если пользователь выбирает пункт 'Exit', мы вызываем DestroyWindow с хэндлом нашего окна в качестве его параметра, которое закрывает наше окно.


Последний раз редактировалось: electrik (Вт Май 23, 2017 5:51 pm), всего редактировалось 1 раз(а)

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 8 - меню

Сообщение  electrik в Вс Июн 28, 2009 8:40 pm

Win32 API. Урок 8. Меню - продолжение


Как вы можете видеть, указание имени меню в классе окна довольно просто и прямолинейно. Тем не менее, вы также можете использовать альтернативный метод

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

Код:

' меню
#include "windows.bi"
#include "menu.bi"
declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы

dim shared hMenu as HMENU
end WinMain( GetModuleHandle( NULL ) ,NULL,GetCommandLine() , SW_SHOWNORMAL ) ' вызвать основную функцию
'сдесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений

function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_COMMAND ' если получили сообщение WM_COMMAND
select case loword(wParam) ' читаем нижнее слово из wParam
case IDM_TEST
MessageBox(NULL,"You selected Test menu item",@AppName,MB_OK)
case IDM_HELLO
    MessageBox(NULL,"Hello, my friend", @AppName,MB_OK)
case IDM_GOODBYE
MessageBox(NULL,"See you again", @AppName, MB_OK)
case IDM_EXIT
DestroyWindow(hWnd)
end select
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function


'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' переменная сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
with wc ' заполняем структуру wc
.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
.cbWndExtra = NULL
.hInstance = hInst  ' хэндл модуля
.hbrBackground = cast(HGDIOBJ, COLOR_WINDOW+1) ' Цвет фона
.lpszMenuName = NULL ' хэндл меню
.lpszClassName = @ClassName ' имя класса окна
.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
.hIconSm = .hIcon 'Хэндл маленькой иконки
.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
end with

' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

          hMenu = LoadMenu(hInst, "FirstMenu") ' получим хэндл меню
' Создадим окно
hwnd = CreateWindowEx _
(NULL, _ ' дополнительные стили
ClassName, _ ' строка с именем класса окна
AppName, _ ' строка с именем окна
WS_OVERLAPPEDWINDOW, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
CW_USEDEFAULT, _ ' ширина окна
CW_USEDEFAULT, _ ' высота окна
NULL, _ ' хэндл родительского окна
hMenu, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

ShowWindow( hwnd,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hwnd) ' обновить клиентскую область

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

анализ

dim hMenu as HMENU

hMenu = LoadMenu(hInst, "FirstMenu") '
hwnd = CreateWindowEx _
(NULL, _
ClassName, _
AppName, _
WS_OVERLAPPEDWINDOW, _
CW_USEDEFAULT, _
CW_USEDEFAULT, _
CW_USEDEFAULT, _
CW_USEDEFAULT, _
NULL, _
hMenu, _
hInst, _
NULL)

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

Перед вызовом CreateWindowEx, мы вызываем LoadMenu, передавая ему хэндл процесса и указатель на имя меню. LoadMenu возвращает хэндл нашего меню, который мы передаем CreateWindowEx.

[C] Iczelion, пер. Aquila.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения