Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Ресурсы. меню и акселераторы - MFC

Понятие ресурсов

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

При сборке проекта приложения, ресурсы добавляются к EXE-файлу уже после линковки. Для описания ресурсов существует специальный язык, а сами описания хранятся в текстовых файлах с расширением rc. Раньше программисты вручную писали сценарии ресурсов на языке ресурсов, сейчас же так никто не делает, а используются визуальные редакторы. Перед добавлением к исполняемому файлу сценарии преобразуются в бинарный вид с помощью компилятора ресурсов, в результате чего получается файл с расширением res. Как правило, все эти шаги выполняются автоматически при работе из интегрированной среды Visual C++. Вообще, ручное редактирование ресурсных сценариев требуется сейчас уже очень редко, лишь при определении нестандартных ресурсов в сложных проектах. Мы будем использовать только интегрированную среду, как это сейчас делают многие программисты.

Каждый ресурс имеет свой уникальный идентификатор. Это может быть либо строка, либо число (константа). Числа можно использовать всегда, а строки - не всегда. Мы будем использовать и то, и другое. Редактор ресурсов из Visual C++ помещает имена констант в файл resource.h, который нужно включить в файлы программы. Стандартные идентификаторы хранятся в файле afxres.h, который обычно используется автоматически ресурсным редактором.

Меню

Меню обычно создаются визуально. В Visual C++ нужно нажать клавиши Ctrl+2 или нажать кнопку создания нового меню на панели инструментов. Среда автоматически добавит в проект сценарий ресурсов и перейдет к редактированию меню.

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

Меню, как отдельному ресурсу, должен быть присвоен числовой или символьный идентификатор. При редактировании символьные идентификаторы заключаются в кавычки. Также, каждому пункту меню должен быть присвоен уникальный числовой идентификатор. Это позволит программе реагировать на выбор пункта в меню, в этом случае MFC будет вызывать соответствующий обработчик (об этом несколько позже). По принятому соглашению, все идентификаторы пунктов меню начинаются с IDM_. В самих названиях пунктов можно указывать ключевые клавиши, поставив перед буквой символ &. В этом случае, если меню активно, пункт можно выбрать также и с клавиатуры.

На рис. 5 показан процесс создания меню в среде Visual C++. Другие ресурсы создаются аналогично. Этот процесс довольно прост.


Рис. 5. Процесс визуального создания меню в среде Visual C++

Включение меню в окно приложения

Когда ресурс меню создан, его можно использовать в окне программы. Это можно сделать, указывая меню при создании окна: строковый идентификатор ресурса меню нужно указать в качестве последнего параметра в функции Create():

 	this->Create(0, "Приложение с меню",
                         WS_OVERLAPPEDWINDOW,
         		rectDefautl, 0, "MYMENU");
 
В результате будет создано окно с меню. Но для того, чтобы меню можно было использовать, необходимо создать обработчики сообщения WM_COMMAND для каждого пункта меню. Если для какого-то пункта нет обработчика, то MFC заблокирует этот пункт (он будет выделен серым цветом).

Сообщение WM_COMMAND

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

 	ON_COMMAND(Идентификатор, ИмяОбработчика);
 
Каждый обработчик для WM_COMMAND должен возвращать void. Обработчики не имеют параметров. Имя выбирается произвольно, обычно используется префикс On.

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

Акселераторы

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

 	BOOL CFrameWnd::LoadAccelTable(LPCSTR ResourceName);
 
После загрузки таблицы акселераторов, нажатие заданных в ней комбинаций клавиш приводит к автоматической генерации сообщения WM_COMMAND с идентификатором, определенным в этой таблице для данной комбинации клавиш.

Акселераторы легко создавать в среде Visual C++. Для каждого элемента таблицы нужно нажать желаемую клавишу или их комбинацию, и указать числовой идентификатор. Если указать идентификаторы, которые уже использовались в меню, то мы получим клавиши быстрого доступа, дублирующие команды меню.

Окна сообщений

Это простейшие диалоговые окна, предопределенные в системе. Для создания окна сообщения используется функция с прототипом:

 	int CWnd::MessageBox(LPCSTR MessageText,
 	LPCSTR WindowTitle = 0,
 	UINT MessageBoxType = MB_OK);
 
Параметр MessageText определяет само сообщение. Параметр WindowTitle - заголовок окна сообщения. И параметр MessageBoxType задает стиль окна, иконку, отображаемую слева от сообщения, и одну или несколько кнопок. Этот параметр задается комбинацией констант с помощью операции "|", начинающихся на префикс MB_. Все наборы кнопок заранее определены. Функция возвращает идентификатор нажатой кнопки: IDABORT, IDRETRY, IDIGNORE, IDCANCEL, IDNO, IDYES, или IDOK.

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

Пример программы, использующей меню, акселераторы и окна сообщений

 	menu.hpp
 
 	#include "stdafx.h" 
 	// Класс основного окна
 	class CMainWin: public CFrameWnd {
 	public:
 	CMainWin();
 	afx_msg void OnPaint();
 	// Обработчики команд меню и акселераторов
 	afx_msg void OnCommand_Alpha();
 	afx_msg void OnCommand_Beta();
 	afx_msg void OnCommand_Gamma();
 	afx_msg void OnCommand_Epsilon();
 	afx_msg void OnCommand_Zeta();
 	afx_msg void OnCommand_Eta();
 	afx_msg void OnCommand_Theta();
 	afx_msg void OnCommand_Help();
 	afx_msg void OnCommand_Time(); //Только акселератор
 	DECLARE_MESSAGE_MAP()
 	};

	// Класс приложения
	class CApp: public CWinApp {
   	public:
 	BOOL InitInstance();
 	};
 
 	menu.cpp
 	#include "stdafx.h"
 	#include <string.h>
 	#include <stdio.h>
 	#include "MENU.HPP"
 	#include "IDS.H"
 
 	CMainWin::CMainWin()
 	{
 	// Прямоугольник для построения окна
 	RECT rect;
 	rect.left = 20; rect.top = 10;
 	rect.right = 600; rect.bottom = 460;
 	this->Create(0, "Menus", WS_OVERLAPPEDWINDOW, rect, 0,
 			"MYMENU");
 	// Загрузка таблицы акселераторов
 	this->LoadAccelTable("MYMENU");
 	}
 
 	BOOL CApp::InitInstance()
 	{
 	m_pMainWnd = new CMainWin;
 	m_pMainWnd->ShowWindow(SW_RESTORE);
 	m_pMainWnd->UpdateWindow();
 	return TRUE;
 	}
 
 	// Карта откликов на сообщения
 	BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
 	ON_WM_PAINT()
 	ON_COMMAND(IDM_ALPHA, OnCommand_Alpha)
 	ON_COMMAND(IDM_BETA, OnCommand_Beta)
 	ON_COMMAND(IDM_GAMMA, OnCommand_Gamma)
 	ON_COMMAND(IDM_EPSILON, OnCommand_Epsilon)
 	ON_COMMAND(IDM_ZETA, OnCommand_Zeta)
 	ON_COMMAND(IDM_ETA, OnCommand_Eta)
 	ON_COMMAND(IDM_THETA, OnCommand_Theta)
 	ON_COMMAND(IDM_HELP, OnCommand_Help)
 	ON_COMMAND(IDM_TIME, OnCommand_Time)
 	END_MESSAGE_MAP()
 
 	afx_msg void CMainWin::OnPaint()
 	{
 	CPaintDC dc(this);
 	CString s("Press Ctrl-T to get current date and time");
 	dc.TextOut(100, 200, s);
 	}

 	// Далее идут обработчики сообщений WM_COMMAND.
 	// В них используется функция для вывода окон
 	// сообщений
 	// CWnd::MessageBox(LPCTSTR, LPCTSTR, UINT).
 
 	afx_msg void CMainWin::OnCommand_Alpha()
 	{
 	// Использование окна сообщений
 	this->MessageBox("OnCommand_Alpha() handler called.",
 			    "WM_COMMAND message", 
 			    MB_OK | MB_ICONINFORMATION);
 	}

 	afx_msg void CMainWin::OnCommand_Beta()
 	{
 	this->MessageBox("OnCommand_Beta() handler called.",
  			    "WM_COMMAND message",
 			    MB_OK | MB_ICONINFORMATION);
 	}

 	afx_msg void CMainWin::OnCommand_Gamma()
 	{
 	this->MessageBox("OnCommand_Gamma() handler called.",
 			    "WM_COMMAND message", 
                             MB_OK | MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnCommand_Epsilon()
 	{
 	this->MessageBox("OnCommand_Epsilon() handler called.", "WM_COMMAND
 	message", 
 	MB_OK | MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnCommand_Zeta()
 	{
 	this->MessageBox("OnCommand_Zeta() handler called.",
 			    "WM_COMMAND message", 
                             MB_OK | MB_ICONINFORMATION);
 	}
 
 
 	afx_msg void CMainWin::OnCommand_Eta()
 	{
 	this->MessageBox("OnCommand_Eta() handler called.",
 			    "WM_COMMAND message", 
                             MB_OK | MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnCommand_Theta()
 	{
 	this->MessageBox("OnCommand_Theta() handler called.",
                             "WM_COMMAND message", 
                             MB_OK | MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnCommand_Help()
 	{
 	this->MessageBox("OnCommand_Help() handler called.",
                             "WM_COMMAND message", 
                             MB_OK | MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnCommand_Time()
 	{
 	// Получаем текущее время, используя класс MFC CTime
 	CTime currentTime = CTime::GetCurrentTime();
 	CString s = currentTime.Format("%A %B %#d, %Y, %#I:%M%p");

 	s = "OnCommand_Time() handler called.\n\n" 
 	    + ("Current date and time:\n" + s);
 	this->MessageBox(s, "WM_COMMAND message");
 	}
 	CApp App; // Единственный объект приложения
 

Рис. 6. Программа, использующая меню, акселераторы и окна сообщений

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

Также внимательно изучите исходные тексты. Попробуйте изменить меню и акселераторы с помощью редактора ресурсов. Обратите внимание, что мы использовали в проекте два новых файла: stdafx.h и stdafx.cpp. Первый из них включает все самые распространенные заголовочные файлы MFC, а второй - ничего не делающий модуль, использующий заголовочный файл. Это сделано для облегчения использования прекомпилированных заголовочных файлов. Также, в этом случае файл stdafx.obj включает всю необходимую информацию о типах.


назад | содержание | вперед

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
53K
21 сентября 2009 года
SoulStranger
0 / / 21.09.2009
+1 / -1
Мне нравитсяМне не нравится
21 сентября 2009, 16:30:11
Всё работает, кроме 1 ГДЕ ФАЙЛ IDS.H???
если проблемы с типами LPCSTR включите многобайтовую кодировку
2.
11K
22 июля 2005 года
Wooden
7 / / 22.07.2005
+0 / -1
Мне нравитсяМне не нравится
13 августа 2009, 09:16:36
К сожалению, этот пример не работает:

>this->Create(0, "Приложение с меню",
> WS_OVERLAPPEDWINDOW,
> rectDefautl, 0, "MYMENU");


Зато вот так заработало:
>this->Create(0, "Приложение с меню",
> WS_OVERLAPPEDWINDOW,
> rectDefautl, 0, MAKEINTRESOURCE(MYMENU));
3.
37K
11 марта 2009 года
elmaster
23 / / 11.03.2009
+0 / -1
Мне нравитсяМне не нравится
13 марта 2009, 13:36:39
Пример не работает пишет 26 ошибок..
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог