В продолжение темы XML-based интерфейсов, начатой
[MFC] CDailogXML — диалог на основе XML-"шаблона"Автор: SchweinDeBurg
Дата: 10.01.05
, еще два класса — CMenuXML и CHotKeysXML.
CMenuXML
Данный класс является потомком CMenu и предназначен для построения меню на основе XML-"шаблона" следующего вида:
<?xml version="1.0" encoding="Windows-1251"?>
<Menu>
<Popup Text="File">
<Item Text="New" ID="40001"/>
<Item Text="Open..." ID="40002"/>
<Item Text="Save" ID="40003"/>
<Item Text="Save As..." ID="40004"/>
<Item Type="Separator"/>
<Item Text="Page Setup..." ID="40005"/>
<Item Text="Print..." ID="40006"/>
<Item Type="Separator"/>
<Item Text="Exit" ID="40007"/>
</Popup>
...
</Menu>
Для создания меню используется метод
BOOL CreateMenuXML(LPCTSTR pszMenuName);
Через параметр
pszMenuName в него необходимо передать "имя" меню, определяющее имя XML-файла (без расширения ".xml"), содержащего информацию об элементах меню и их иерархии. Пример использования:
int CMainFrame::OnCreate(CREATESTRUCT* lpCS)
{
CMenuXML menuMain;
if (CFrameWnd::OnCreate(lpCS) != -1) {
menuMain.CreateMenuXML(_T("MainMenu"));
SetMenu(&menuMain);
menuMain.Detach();
return (0);
}
else {
return (-1);
}
}
CHotKeysXML
Данный класс является потомком CObject и предназначен для создания таблицы акселераторов на основе XML-"шаблона" следующего вида:
<?xml version="1.0" encoding="Windows-1251"?>
<HotKeys>
<HotKey ID="40001" Text="Ctrl+N"/>
<HotKey ID="40002" Text="Ctrl+O"/>
...
</HotKeys>
Для создания таблицы акселераторов используется метод
BOOL CreateTable(LPCTSTR pszTableName);
Через параметр
pszTableName в него необходимо передать "имя" таблицы, определяющее имя XML-файла (без расширения ".xml"), содержащего информацию о связи акселераторов с идентификаторами команд.
Для "связывания" созданного набора "горячих" клавиш с заданным окном (потомком CFrameWnd) используется метод
void AttachToFrame(CFrameWnd* pFrameWnd, BOOL fShowInMenu = TRUE);
Параметр
fShowInMenu определяет, нужно ли дополнить тексты команд главного меню окна
pFrameWnd информацией о соответствующих им акселераторах. Пример использования:
class CMainFrame: public CFrameWnd
{
...
CHotKeysXML m_hotKeys;
};
...
int CMainFrame::OnCreate(CREATESTRUCT* lpCS)
{
CMenuXML menuMain;
if (CFrameWnd::OnCreate(lpCS) != -1) {
menuMain.CreateMenuXML(_T("MainMenu"));
SetMenu(&menuMain);
menuMain.Detach();
m_hotKeys.CreateTable(_T("HotKeys"));
m_hotKeys.AttachToFrame(this);
return (0);
}
else {
return (-1);
}
}
Заметим, что классы CMenuXML и CHotKeysXML никак не связаны друг с другом и могут использоваться совершенно независимо.
Средства реализации и библиотеки:
MS Visual C++ 6.0 SP6
MS Palform SDK November 2001
MFC 6.0
Pugnacious XML Parser (автор — Kristen Wegner)
SGI STL 3.3
Демонстрационный проект: XMLMenus.zip (~48 Кб)
"Ключевые" файлы:
MenuXML.h — интерфейс класса CMenuXML
MenuXML.cpp — реализация класса CMenuXML
HotKeysXML.h — интерфейс класса CHotKeysXML
HotKeysXML.cpp — реализация класса CHotKeysXML
PugXML.h — парсер XML
PugXMLplus.h — функции-"обертки" для парсера XML (более строго проверяют результаты чтения численных атрибутов, чем "родные" методы)
StringConv.h — вспомогательные классы и функции, предназначенные для выполнения преобразований CHAR <-> WCHAR <-> TCHAR (с точки зрения реализации являются аналогами своих "собратьев" из ATL/MFC 7.x; могут быть заменены на соответствующие макросы/фукции из <AFXCONV.H> или <ATLCONV.H> любых версий MFC/ATL)
Детали реализации
В XML-файле, описывающем меню, допустимы следующие тэги:
<Menu> — обязательный "корневой" тэг; может иметь атрибут "HelpID", значение которого определяет идентификатор контекстной справки для "линейки меню" (menu bar) и должно быть строковым представлением 4-байтового целого числа. Внутри данного тэга могут содержаться один или несколько "дочерних" тэгов <Popup> и <Item>.
<Popup> — определяет "выпадающее меню" (popup menu), содержащее один или несколько элементов. Для данного тега распознаются атрибуты "Text" (текст данного элемена меню), "Type" (тип элемента — набор строк, соответствующих флагам MFT_*) и "State" (начальное состояние элемента — набор строк, соответствующих флагам MFS_*). Полный список распознаваемых классом CMenuXML типов и состояний можно подсмотреть в методах
static DWORD ParseMenuItemType(LPCTSTR pszTypeStr);
и
static DWORD ParseMenuItemState(LPCTSTR pszStateStr);
соответственно. Кроме того, для данного тэга допустим атрибут "HelpID", аналогичный одноименному атрибуту тэга <Menu>.
<Item> — определяет команду меню; этот тэг может содержать атрибуты "Text", "Type", "State" и "ID". Последний определяет идентификатор данной команды меню и должен быть строковым представлением 2-байтового целого числа.
Путь к XML-файлу, описывающему меню, определяется в методе
virtual void GetXMLpath(CString& strDest);
и "по умолчанию" строится следующим образом:
%AppData% \ AfxGetApp()->m_pszRegistryKey \ AfxGetAppName() \
Обратите внимание, что данная реализация GetXMLpath() предполагает, что в методе InitInstance() объекта-приложения был выполнен вызов
SetRegistryKey(_T("VendorName_Or_CompanyName"));
Создание в памяти шаблона меню выполняет метод
static const MENUTEMPLATE* CreateMenuExTemplate(LPCTSTR pszFileXML);
Поскольку он является статическим, им можно воспользоваться, не создавая экземпляра CMenuXML, а просто передав возвращенное значение в вызов CMenu::LoadMenuIndirect() — что собственно и делается в CMenuXML::CreateMenuXML()
.
Если папка, в которой должен находиться XML-файл, или сам этот файл отсутствуют, то в методе CMenuXML::CreateMenuXML() выполняется их создание; при этом в исполняемом файле приложения или одной из загруженных им MFC extension DLLs должен находиться ресурс типа "MENU_XML", имя которого совпадает с именем меню, переданным в вызов CreateMenuXML() (более подробно детали этого механизма описаны в
[MFC] CDialogXML — rev. 3Автор: SchweinDeBurg
Дата: 14.01.05
).
В XML-файле, описывающем акселераторы, допустимы следующие тэги:
<HotKeys> — обязательный "корневой" тэг; может иметь один или несколько "дочерних" тэгов <HotKey>.
<HotKey> — определяет "горячую" клавишу; распознаются атрибуты "ID" (идентификатор команды — строковое представление 2-байтового целого числа), "Text" ("название" сочетания клавиш, которое при необходимости будет додавлено в текст соответствующей команды меню) и "Code" (строковое представление 4-байтового целого числа, определяющего виртуальный код клавиши и флаги, соответствующие "клавишам сдвига" — Shift, Ctrl и Alt).
При разборе атрибутов каждого тэга <HotKey> используется следующая логика:
Вначале читается и запоминается значение атрибута "Text".
Затем выполняется чтение атрибута "Code". Если он присутствует и имеет корректное ненулевое значение, то предполагается, что младшее слово содержит код виртуальной клавиши (VK_*), а старшее — набор флагов HOTKEYF_* (это сделано для облегчения "интеграции" класса CHotKeysXML с элементом управленя "Hot Key"). Если же атрибут "Code" отсутствует или имеет некорректное значение, то код виртуальной клавиши и флаги-модификаторы определяются на основании значения атрибута "Text" — в методе CHotKeysXML::ParseHotKeyText().
Завершающим шагом является чтение атрибута "ID".
Если папка, в которой должен находиться XML-файл, или сам этот файл отсутствуют, то в методе CHotKeysXML::CreateTable() выполняется их создание; при этом в исполняемом файле приложения или одной из загруженных им MFC extension DLLs должен находиться ресурс типа "HOTKEYS_XML", имя которого совпадает с именем таблицы, переданным в вызов CreateTable().
[ posted via RSDN@Home 1.1.4 beta 3 r281 ]