Библиотека классов MFC
Продолжение программы. Создание меню
Задача. Создать меню со следующими элементами: Программа
Выход; Движение
Старт; Движение
Стоп. Добавить обработку выбора пункта меню Программа
Выход, остальные пункты пока не обрабатывать.
Чтобы создать меню, необходимо создать файл ресурсов:
- Resource View
клик правой кнопкой мыши
Add
Resource… - Выберем тип ресурса Menu.
- Создаем меню (в свойствах меню укажем имя идентификатора: IDR_MENU, в свойствах каждого из пунктов также укажем нужные имена идентификаторов).
Добавим код:
…
#include "afxext.h" // MFC Расширения
#include "resource.h" // Идентификаторы ресурсов
#define IDC_MYBUTTON 100 // Идентификатор кнопки
…
class CMainWnd : public CFrameWnd
{
…
int OnCreate(LPCREATESTRUCT lpCreateStruct);//функция вызывается при создании окна
void MenuExit(); //Процедура реакции на выбор пункта меню
~CMainWnd(); //Деструктор
private:
CStatic* MyStatic; //Указатель на объект надпись
CMyButton* MyButton; //Элемент управления кнопка
CEdit* MyEdit; //Указатель на объект поле редактирования
CStatusBar m_wndStatusBar; //Класс панели состояния
CMenu m_wndMenu; //Это наш класс Меню
DECLARE_MESSAGE_MAP(); //Таблица сообщений
};
CMainWnd::CMainWnd()
{
Create(NULL,"Окно приложения пользователя",WS_OVERLAPPEDWINDOW,rectDefault,NULL,NULL); //Создать окно программы
ON_WM_CREATE() //Событие создания окна
ON_COMMAND(ID_FILE_EXIT, MenuExit) //Обработка реакции на выбор меню
END_MESSAGE_MAP()
…
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
m_wndStatusBar.Create(this);
m_wndMenu.LoadMenu(IDR_MENU); // Загрузить меню из файла ресурса
SetMenu(&m_wndMenu); // Установить меню
return 0;
}
void CMainWnd::MenuExit()
{
DestroyWindow(); // Уничтожить окно
}
CMyApp theApp;Скомпилируем и проверим работу программы с меню.
Продолжение программы. Таймер
Задача. Вывести в клиентскую часть окна круг, который при выборе пункта меню Движение
Старт, начинает движение и отскакивает от стенок клиентской области, а при выборе пункта меню Движение
Стоп, останавливается. Обработать нажатие клавиш: "
,
,
,
" ускоряющих (замедляющих) движение шарика в направлениях указанных стрелками.
Добавим в описание класса окна следующий код:
class CMainWnd : public CFrameWnd
{
…
private:
int VX, sgn_x; //Приращение координаты по оси x и знак приращения
int VY, sgn_y; //Приращение координаты по оси y и знак приращения
CRect newPlace; //квадрат, в который вписан отображаемый круг
CRect oldPlace; //квадрат, в который был вписан отображаемый круг в предыдущий момент
…
DECLARE_MESSAGE_MAP(); // таблица откликов окна
public:
…
afx_msg void MenuStart(); // процедура реакции на выбор пункта меню
afx_msg void MenuStop(); // процедура реакции на выбор пункта меню
afx_msg void OnTimer(UINT_PTR); // обработка сообщения WM_TIMER
afx_msg void OnPaint(); // обработка WM_PAINT
afx_msg void OnKeyDown(UINT, UINT, UINT); //обработка нажатия клавиши клавиатуры
};В карту сообщений окна добавим:
BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) // таблица откликов на сообщения … ON_COMMAND(ID_MOTION_START,MenuStart) //выбор пункта "старт" ON_COMMAND(ID_MOTION_STOP,MenuStop) //выбор пункта "стоп" ON_WM_TIMER() ON_WM_PAINT() ON_WM_KEYDOWN() // реакция на нажатие клавиши END_MESSAGE_MAP()
Добавим инициализацию полей в конструкторе класса:
CMainWnd::CMainWnd()
{
oldPlace.left = 150;
oldPlace.top = 150;
oldPlace.right = 170;
oldPlace.bottom = 170;
newPlace = oldPlace;
VX = VY = sgn_x = sgn_y = 1;
…
}Реализация объявленных методов:
void CMainWnd::MenuStart()
{
SetTimer(ID_TIMER_FOR_MOT,10,NULL); //Запуск таймера
}
void CMainWnd::MenuStop()
{
KillTimer(ID_TIMER_FOR_MOT); //Остановка таймера
}
void CMainWnd::OnTimer(UINT_PTR nIDEvent)
{
CRect rectClient;
GetClientRect(&rectClient);
rectClient.bottom -= 20;
rectClient.left += 110;
if(newPlace.right > rectClient.right || newPlace.left < rectClient.left)
sgn_x = -sgn_x;
if(newPlace.bottom > rectClient.bottom || newPlace.top < rectClient.top)
sgn_y = -sgn_y;
newPlace.left+= sgn_x*VX;
newPlace.right += sgn_x*VX;
newPlace.top += sgn_y*VY;
newPlace.bottom += sgn_y*VY;
InvalidateRect(oldPlace); //Затирается круг со старым центром
ValidateRect(newPlace); //Прорисовка круга с новым центром
oldPlace = newPlace;
}
void CMainWnd::OnPaint()
{
CPaintDC dc(this);
CBrush bBrush(RGB(0,0,255));
dc.SelectObject(&bBrush);
dc.Ellipse(newPlace);
}
void CMainWnd::OnKeyDown(UINT nChar, UINT, UINT)
{
switch(nChar) //Обработка символов с соответствующими кодами
{
case 40: if(sgn_y > 0) VY++;
else VY--;
break;
case 38: if(sgn_y > 0) VY--;
else VY++;
break;
case 37: if(sgn_x > 0) VX--;
else VX++;
break;
case 39: if(sgn_x > 0) VX++;
else VX--;
break;
}
}Комментарий
Функция SetTimer(…) запускает системный таймер с идентификатором, указанным в параметрах, и генерирует синхронно сообщение WM_TIMER для окна, вызвавшего ее, пока таймер не будет уничтожен функцией KillTimer(…) с соответсвующим параметром – идентификатором работающего таймера. Для одного окна может быть запущено несколько таймеров.
Продолжение программы. Вывод данных в строку состояния
Задача. Отобразить в панели состояния текущие координаты курсора.
В проекте создадим ресурс, содержащий две строки:
Resource View
клик правой кнопкой мыши
Add Resource… Выберем тип ресурса String Table. Нажмем OK. Появится новый ресурс. Он используется для хранения текстовых строк.
В него нужно добавить две строки:
- кликаем правой кнопкой мыши и выбираем New String ( IDS_STRING_X );
- Caption
10 символов подчеркивания (резервируем под вывод 10 символов); - создадим еще одну строку – IDS_STRING_Y.
Создадим массив, в котором будут находиться идентификаторы строк (после #define ):
static UINT indicators[] =
{
IDS_STRING_X, //Идентификатор первой строки в ресурсах
IDS_STRING_Y //Идентификатор второй строки в ресурсах
};Изменим функцию OnCreate для того, чтобы установить индикаторы:
int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_wndStatusBar.Create(this); //Создать строку состояния
m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)); //Установить в строку идентификаторы
m_wndStatusBar.SetPaneInfo(0,0,0,50); //Изменение размеров первой секции строки состояния
m_wndStatusBar.SetPaneInfo(1,0,0,50); //Изменение размеров второй секции строки состояния
m_wndMenu.LoadMenu(IDR_MENU); //Загрузить
…
}В таблицу откликов занесем реакцию на движение мыши:
BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) //Таблица откликов окна … ON_WM_CREATE() //Событие создания окна ON_WM_MOUSEMOVE() //Движение мыши … END_MESSAGE_MAP()
И описание соответствующей функции в классе рамки окна:
class CMainWnd : public CFrameWnd
{
public:
…
afx_msg void OnMouseMove(UINT, CPoint cp); //Движение мыши
…
};Реализация:
void CMainWnd::OnMouseMove(UINT, CPoint cp)
{
char chX[10]; //Буфер для координат
char chY[10]; //Буфер для координат
itoa(cp.x,chX,10); //Число переводим в строку
itoa(cp.y,chY,10); //Число переводим в строку
CString csStatusX(chX); //Формируем строку
CString csStatusY(chY); //Формируем строку
m_wndStatusBar.SetPaneText(0,csStatusX); //Выводим первую панель
m_wndStatusBar.SetPaneText(1,csStatusY); //Выводим вторую панель
}Скомпилировать и запустить проект – при перемещении курсора его координаты отображаются в строке состояния.
Комментарии
Для отображения в панели состояния, необходимо создать массив идентификаторов. Это необходимо для начала работы панели, а массив служит как шаблон. При запуске будет выведено именно то, что есть в строках, находящихся в ресурсах. Функция SetIndicators(...) говорит панели состояния о том, что у нее будут две панели. В параметрах – массив идентификаторов и количество элементов:
BOOL SetIndicators(const UINT* lpIDArray, int nIDCount);
Параметр lpIDArray – указатель на массив, nIDCount – количество элементов в массиве, sizeof(indicators)/sizeof(UINT) – размер массива/размер одного элемента
Движение мыши отслеживается с помощью сообщения – ON_WM_MOUSEMOVE(). Обработчиком этого сообщения является функция – OnMouseMove(). Этой функции передается положение мыши в виде Point. Далее, необходимо сделать перевод числа в строку - itoa, использовать объект класса CString, и, для вывода в строку состояния, использовать функцию SetPaneText(...)
BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );
nIndex – номер панели для вывода, lpszNewText – текст для вывода, bUpdate – обновлять.