Казахстан |
Библиотека классов 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 – обновлять.