Опубликован: 10.03.2009 | Уровень: специалист | Доступ: платный
Лекция 2:

Библиотека классов MFC

Разработка Windows-приложения c использованем библиотеки MFC

Создание и вывод Windows-окна на экран с использованием MFC

Создадим простейшую программу под Windows средствами Visual C++ 2005

  1. File \to New \to Project.
  2. Project types: Win32, Templates: Win32 Project.
  3. Ok.
  4. An empty project.
  5. Finish.
  6. Добавляем в проект файл *.cpp.
  7. Project \to Properties. Вкладка Configuration Properties \to General.
  8. Значение поля Character Set установливаем Use Multi-Byte Character Set.
  9. Значение поля Use of MFC устанавливаем Use MFC in a Static Library.
  10. Ok.

Введем код программы:

#include "afxwin.h"       //MFC основные и стандартные компоненты

class CMyApp : public CWinApp
{
public:
  CMyApp();        //Конструктор по умолчанию
  virtual BOOL InitInstance();  //Стандартная инициализация
};

class CMainWnd : public CFrameWnd
{
public:
  CMainWnd();        //Конструктор по умолчанию
};

CMainWnd::CMainWnd()
{
Create(NULL,"Окно приложения пользователя", WS_OVERLAPPEDWINDOW, rectDefault, NULL, NULL);    //Создать окно программы
}  

CMyApp::CMyApp()        //Конструктор главного класса приложения
{}

BOOL CMyApp::InitInstance()     //Стандартная инициализация
{
  m_pMainWnd=new CMainWnd();    //Создать указатель на класс окна
  ASSERT(m_pMainWnd);      //Проверить его правильность
  m_pMainWnd->ShowWindow(SW_SHOW);  //Показать окно
  m_pMainWnd->UpdateWindow();    //Обновить окно
  return TRUE;        //Вернуть, что все нормально
};
CMyApp theApp;          //Запуск приложения

Комментарий к программе

Первая строка – файл заголовков afxwin.h, предназначен для программирования под Windows с использованием библиотеки MFC. Он включает описание классов, функций и переменных, а также ссылается на windows.h.

Замечание: В каждой программе на С++ есть главная функция программы. В Dos, это main(), в Windows – WinMain(). В рассматриваемой программе ее нет, так как в MFC есть класс CWinApp, который включает главную функцию программы.

Во второй строке создается класс CMyApp, как производный от CWinApp и который наследует все его свойства, методы и т.д. В этом классе объявлен конструктор по умолчанию (без параметров). Он необходим, иначе не скомпилировать программу. В конце программы от класса CMyApp создается объект класса CMyApp theApp. Он тоже без параметров. CWinApp имеет виртуальный метод InitInstance(). Этот метод должен возвращать ненулевое значение, если инициализация прошла нормально, а иначе 0. Он предназначен, чтобы описать класс окна программы и отобразить окно на экране. В конструкторе класса CMainWnd вызывается функция создания окна Create(…), в которой есть несколько параметров. Первый параметр указывает на имя класса окна, он пока не нужен и поэтому NULL, дальше указатель – имя окна программы. WS_OVERLAPPEDWINDOW определяет стиль окна (обычное перекрывающее окно с заголовком, кнопкой вызова системного меню, кнопками минимизации и максимизации и рамкой). Параметр rectDefault говорит о том, что размер окна присвоит Windows по умолчанию. Рассмотрим функцию Create(…) подробнее:

BOOL CFrameWnd::Create(LPCSTR ClassName, LPCSTR Title, DWORD Style = WS_OVERLAPPEDWINDOW, const RECT &XYSize = rectDefault, CWnd *Parent = 0, LPCSTR MenuName = 0, DWORD ExStyle = 0, CCreateContext *Context = 0);

Первый параметр, ClassName, определяет имя класса окна для оконной подсистемы Windows. Обычно его не нужно явно задавать, так как MFC выполняет всю необходимую работу. Параметр Title определяет заголовок окна. Параметр Style задает стиль окна. По умолчанию создается стандартное перекрываемое окно. Можно задать свой стиль, объединив с помощью операции "или" (|)несколько констант из приведенных ниже:

Константа Элемент окна
WS_OVERLAPPED Стандартное окно с рамкой
WS_MAXIMIZEBOX Кнопка максимизации
WS_MINIMIZEBOX Кнопка минимизации
WS_SYSMENU Системное меню
WS_HSCROLL Горизонтальная полоса прокрутки
WS_VSCROLL Вертикальная полоса прокрутки

В примере используется член-функция со следующим прототипом:

virtual BOOL CWinApp::InitInstance();

Это виртуальная функция, которая вызывается каждый раз при запуске программы. В ней должны производиться все действия, связанные с инициализацией приложения. Функция должна возвращать TRUE при успешном завершении и FALSE в противном случае. В программе в функции сначала создается объект класса CMainWnd, и указатель на него запоминается в переменной m_pMainWnd. Эта переменная является членом класса CWinThread. Она имеет тип CWnd* и используется почти во всех MFC-программах, так как содержит указатель на главное окно. Так как m_pMainWnd указывает на CMainWnd, то можно вывести на экран окно:

m_pMainWnd->ShowWindow(SW_SHOW);

Параметр определяет, каким образом окно будет показано на экране. Наиболее распространенные значения следующие:

Константа Действие
SW_HIDE Окно становится невидимым
SW_MAXIMIZE Окно максимизируется
SW_MINIMIZE Окно минимизируется
SW_SHOW Окно отображается, если было невидимо
SW_RESTORE Окно приводится к нормальному размеру

Показать окно:

m_pMainWnd->UpdateWindow();

Запустив программу на выполнение, получим в результате окно.

Дополнение. При создании окна часто используют структуру Rect.

Пример:

RECT x;
x.top = 30;
x.left = 30;
x.bottom = 300;
x.right = 300;
Сreate(NULL, "My New Window", WS_OVERLAPPEDWINDOW, x);

Замечание. В библиотеке MFC используется ряд глобальных функций. Все они начинаются с префикса Afx. (Когда MFC только разрабатывалась, то проект назывался AFX – Application Framework). После ряда существенных изменений, AFX была переработана в MFC, но прежнее название сохранилось во многих идентификаторах библиотеки и в названиях файлов.

Продолжение программы. Вставка элементов управления в окно (Controls)

Для работы возьмем наш первый проект и внесем изменения. Добавим следующий код после всех #include:

#define IDC_MYBUTTON 100  //Идентификатор кнопки
#define IDC_MYEDIT 102    //Идентификатор поля редактирования

Необходимо изменить описания конструктора класса окна:

class CMainWnd : public CFrameWnd
{
public:
CMainWnd();    //Конструктор по умолчанию
  ~CMainWnd();     //Деструктор
private:
  CStatic* MyStatic;  //Указатель на объект надпись
  CButton* MyButton;  //Указатель на объект кнопка
  CEdit* MyEdit;    //Указатель на объект поле редактирования
};
CMainWnd::CMainWnd()
{
  Create(NULL,"Окно пользователя", WS_OVERLAPPEDWINDOW, rectDefault, NULL, NULL);    //Создать окно программы
  MyStatic = new CStatic();
  if (MyStatic!=NULL) 
    MyStatic->Create("MyStatic", WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(10, 10, 100, 50),this);  
  MyButton = new CButton();
  if (MyButton!=NULL) 
    MyButton->Create("MyButton", WS_CHILD|WS_VISIBLE|SS_CENTER,  CRect(120, 10, 220, 50), this, IDC_MYBUTTON);
  MyEdit = new CEdit();
  if (MyEdit != NULL) 
    MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER, CRect(240, 10, 340, 50), this, IDC_MYEDIT);
}

CMainWnd::~CMainWnd()          //Деструктор класса
{
  if (MyStatic != NULL) delete MyStatic;  //Удалить динамический объект
  if (MyButton != NULL) delete MyButton;  //Удалить динамический объект
  if (MyEdit != NULL) delete MyEdit;    //Удалить динамический объект
}
Комментарии к программе

Результат создания объектов оператором new проверяется через проверку на NULL. Если ошибка, то все действия с этим элементом отменятся. Программный код реализации элементов управления находится в DLL Windows. То есть, в компиляторе нет реализации этих функций в библиотеках (lib), там только ссылки. Все элементы управления должны иметь идентификатор – число, которое определяет этот элемент управления. Первыми двумя строками, используя #define, объявляем идентификаторы. Дальше в класс рамки окна вставляются указатели на объекты элементов управления. Это только указатели. Объекта самого нет. Каждый объект использует память и, до того как он не понадобится, хранится только указатель. В конструкторе окна создадим соответствующие объекты с помощью оператора new, а после этого вызовем функцию Create(…), которая из объекта создаст элемент управления. Заметим, что у MyStatic нет идентификатора. Он задан по умолчанию, как 0xffff.

Функция Create(…) используется очень часто и есть у многих объектов. Обычно она требует:

  1. строку для имени или надписи;
  2. стиль;
  3. размеры и положение;
  4. куда вставлять;
  5. идентификатор.
Продолжение программы. События элемента управления

Задача. Проиллюстрировать работу событий элемента управления на примере работы с мышью. При нажатии левой кнопки мыши элемент управления – кнопка должна переместиться в заданное место окна, а при нажатии правой кнопки мыши кнопка должна возвратиться в исходное место.

#include "afxwin.h"    //MFC Основные и стандартные компоненты

#define IDC_MYBUTTON 100  //Идентификатор кнопки
#define IDC_MYEDIT 102    //Идентификатор поля редактирования

class CMyButton: public CButton  //Создание нового класса
{
public:
  afx_msg void OnLButtonDown(UINT, CPoint);
  afx_msg void OnRButtonDown(UINT, CPoint);
private:
  DECLARE_MESSAGE_MAP(); //Таблица откликов кнопки
};
void CMyButton::OnLButtonDown(UINT, CPoint)
{
  MoveWindow(10, 110, 90, 30);
}

void CMyButton::OnRButtonDown(UINT, CPoint)
{
  MoveWindow(10, 40, 90, 30);
}

BEGIN_MESSAGE_MAP(CMyButton, CButton) //Таблица откликов на сообщения для кнопки
  ON_WM_LBUTTONDOWN()
  ON_WM_RBUTTONDOWN()
END_MESSAGE_MAP()

class CMainWnd : public CFrameWnd
{
public:
  CMainWnd();          //Конструктор по умолчанию
  ~CMainWnd();         //Деструктор
private:
  …
  CMyButton* MyButton;    //Указатель на объект кнопка
  …    
};
…
CMyApp theApp;
Продолжение программы. Создание строки состояния

Задача. Создать строку состояния (пока пустую). В описания включаемых файлов добавим:

#include "afxext.h"  //MFC расширения

В описание класса рамки окна:

class CMainWnd : public CFrameWnd
{
public:
  CMainWnd();  //Конструктор по умолчанию 
  int OnCreate(LPCREATESTRUCT lpCreateStruct);  
  ~CMainWnd();      // Деструктор
private:
  CStatic* MyStatic;    //Указатель на объект надпись
  CMyButton* MyButton;    //Элемент управления кнопка
  CEdit* MyEdit;      //Указатель на объект поле редактирования
  CStatusBar m_wndStatusBar;  //Класс панели состояния
  DECLARE_MESSAGE_MAP();    //Таблица откликов
};

В таблице откликов:

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)  //Таблица откликов на сообщения
  ON_WM_CREATE()        //Событие создания окна
END_MESSAGE_MAP()

Реализация объявленной процедуры:

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    return -1;
  m_wndStatusBar.Create(this);
  return 0;
}
Жанат Агайдаров
Жанат Агайдаров
Казахстан
Сергей Пузырев
Сергей Пузырев
Украина