Визуальные средства разработки программных приложений
Краткое изложение материала по визуальным средствам разработки программных приложений. Рассмотрение диалоговых окон, элементов управления, переключателей, доступа к данным, обработки, анализа, технологий, библиотек, экспорта, приложений, потоков.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | шпаргалка |
Язык | русский |
Дата добавления | 26.06.2014 |
Размер файла | 285,0 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
При задании стиля ES_AUTOHSCROLL в многострочном редакторе для перехода на новую строку нужно нажимать клавишу <Enter> (т.е. появляется возможность горизонтальной прокрутки). Используя стиль окна ES_AUTOVSCROLL, в многострочное окно редактирования можно включить возможность вертикальной прокрутки.
Если стили ES_AUTOHSCROLL и ES_AUTOVSCROLL включены в многострочные управляющие окна, то можно добавить и сами полосы прокрутки.
Добавление полос прокрутки делается путем использования идентификаторов стиля окна, WS_HSCROLL и WS_VSCROLL.
Чаще всего для многострочных редакторов используется следующая комбинация стилей:
WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|
ES_MULTILINE|ES_|ES_AUTOVSCROLL|WS_HSCROLL|WS_VSCROLL
Родительские окна также могут посылать окнам редактирования сообщения
Специфических сообщений, которые родительское окно может послать окну редактирования, достаточно много. Рассмотрим наиболее часто употребляемые:
WM_CUT - для удаления с пересылкой в буфер обмена;
WM_COPY - копирования в буфер обмена;
WM_CLEAR - очищения выделенной части текста из окна редактирования;
WM_PASTE - для вставки текста из буфера обмена в окно редактирования;
EM_GETSEL - для получения начальной и конечной позиции текущего выделения текста;
EM_SETSEL - для выделения некоторого участка текста;
EM_REPLACESEL - для замены текущего выделенного текста другим текстом;
EM_GETLINECOUNT - для получения число строк многострочного редактора;
EM_LINEINDEX - для получения смещения от начала буфера до некоторой строки;
EM_LINELENGTH - для получения длины некоторой строки;
EM_GETLINE - для копирования некоторой строки в буфер программы.
Некоторые методы класса CEdit
Окна редактирования могут работать в режимах однострочного и многострочного редакторов. Приведем сначала методы, общие для обоих режимов, а затем методы для многострочного редактора.
Общие методы
Методы для получения первой и последней позиции выделенного фрагмента текста:
DWORD GetSel() const;
void GetSel(int& nStartChar, int& nEndChar) const;
Для значения типа DWORD младшее слово содержит позицию первого, старшее - последнего символа.
Методы для установки нового выделения текста, задаваемого первым и последним выделенный символ:
void SetSel(DWORD dwSelection, BOOL bNoScroll=FALSE);
или
void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll=FALSE);
Значение FALSE параметра bNoScroll должно отключать перемещение курсора в область видимости.
Метод для замены выделенного фрагмента текста на строку, передаваемую в параметре lpszNewText:
void ReplaceSel(LPCTSTR lpszNewText);
Метод для удаления выделенного фрагмента текста:
void Clear();
Метод для копирования выделенного фрагмента текста в буфер Windows:
void Copy();
Метод для переноса выделенного фрагмента текста в буфер обмена Windows (копирует в буфер и удаляет из текста):
void Cut();
Метод для вставки текста из буфера обмена, начиная с позиции, в которой находится курсор:
void Paste();
Метод для отмены последней операции, выполненной редактором:
BOOL Undo();
Если редактор однострочный, возвращается всегда неотрицательное значение, иначе неотрицательное значение возвращается лишь в случае успешной замены.
Метод для определения того, можно ли отменить последнюю операцию редактора:
BOOL CanUndo() const;
Метод для сброса флага undo (он сигнализирует о возможности отмены последней операции редактора), его вызов делает невозможным отмену:
void EmptyUndoBuffer();
Этот флаг сбрасывается автоматически при выполнении методов SetWindowText и SetHandle.
Метод для определения значения флага модификации содержимого окна:
BOOL GetModify() const;
Возвращает неотрицательное значение, если содержимое окна редактирования не модифицировалось. Информация о модификации поддерживается в специальном флаге, обнуляемом при создании окна редактирования и при вызове метода:
Метод для установки или сброса флага модификации (см. предыдущий метод):
void SetModify(BOOL bModified=TRUE);
Флаг сбрасывается при вызове метода с параметром FALSE и устанавливается при модификации содержимого окна редактирования или при вызове SetModify с параметром TRUE.
Метод для установки режима просмотра (bReadOnly=TRUE) или редактирования (bReadOnly=FALSE):
BOOL SetReadOnly(BOOL bReadOnly=TRUE);
Метод для определения символа, который при выводе пароля будет появляться на экране вместо символов, набираемых пользователем:
TCHAR GetPasswordChar() const;
Если такой символ не определен, возвращается 0. Устанавливается этот символ методом (по умолчанию используется "*"):
void SetPasswordChar(TCHAR ch);
Метод для установки максимальной длины (в байтах) текста, который может ввести пользователь:
void LimitText(int nChars=0);
Если значение параметра равно 0, длина текста устанавливается равной UINT_MAX.
Методы работы с многострочным редактором
Метод для осуществления прокрутки текста в области редактирования:
void LineScroll(int nLines, int nChars=0);
Параметр nLimes задает число строк для вертикальной прокрутки. Окно редактирования не прокручивает текст дальше последней строки. При положительном значении параметра область редактирования сдвигается вдоль текста к последней строке, при отрицательной - к первой.
Параметр nChars задает число символов для горизонтальной прокрутки. Окно редактирования прокручивает текст вправо, даже если строки закончились. В этом случае в области редактирования появляются пробелы. При положительном значении параметра область редактирования сдвигается вдоль к концу строки, при отрицательном - к началу.
Метод для определения номера первой видимой строки в области редактирования:
int GetFirstVisibleLine() const;
Метод для определения числа строк текста, находящегося в области редактирования:
int GetLineCount() const;
Если текст не вводился, возвращает 1.
Методы для копирования содержимого определенной строки в буфер:
int GetLine(int nIndex, LPTSTR lpszBuffer) const;
или
int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const;
Копирует строку с номером, равным значению параметра nIndex, в буфер, заданный параметром lpszBuffer. Первое слово в буфере должно задавать его размер. При вызове второго варианта метода значение параметра nMaxLength копируется в первое слово буфера.
Метод возвращает число в действительности скопированных байтов. Если номер строки больше или равен числу строк в буфере окна редактирования, возвращает 0. Текст копируется без каких-либо изменений, нуль-символ не добавляется.
Метод для определения номера первого символа определенной строки:
int LineIndex(int nLine=-1) const;
Неотрицательное значение параметра принимается в качестве номера строки. Значение -1 задает текущую строку. Если номер строки больше или равен числу строк в буфере окна редактирования (строки нумеруются с 0), возвращается 0.
8. Обработка сообщений. Карты сообщений
Обработка сообщений. Циклы обработки сообщений
Если и существует некоторая особенность, отличающая программирование в Windows от других областей программирования, то это сообщения. Сообщения являются тем средством, с помощью которого операционная система может дать знать приложению, что что-то произошло, например пользователь нажал клавишу на клавиатуре или щелкнул кнопкой мыши, или передвинул мышь, или подготовил принтер к выводу информации. Окно, а каждый информационный элемент на экране есть своего рода окно, также может посылать сообщения другому окну и, как правило, большинство окон реагирует на полученное сообщение тем, что пересылает его дальше, третьему окну, слегка видоизменив. Значительную помощь в организации работы с сообщениями оказывает MFC, скрывая от программиста многие подробности процесса.
Хотя операционная система и использует целые числа для идентификации событий, в тексте программы мы будем иметь дело с символьными идентификаторами. Огромное количество директив #define связывает символьные идентификаторы с соответствующими числами и позволяет программистам в разговоре между собой в кругу посвященных манипулировать словечками вроде WM_PAINT и WM_SIZE. Префикс WM означает Window Message (сообщение Windows). Фрагмент перечня сообщений представлен в листинге 3.1.
#define WM_SETFOCUS 0x0007
#define WM_KILLFOCUS 0x0008
#define WM_ENABLE 0x000A
#define WM_SETREDRAW 0x000B
#define WM_SETTEXT 0x000C
#define WM_GETTEXT 0x000D
#define WM_GETTEXTLENGTH 0x000E
#define WM_PAINT 0x000F
#define WM_CLOSE 0x0010
#define WM_QUERYENDSESSION 0x0011
#define WM_QUIT 0x0012
#define WM_QUERYOPEN 0x0013
#define WM_ERASEBKGND 0x0014
#define WM_SYSCOLORCHANGE 0x0015
#define WM_ENDSESSION 0x0016
Сообщению известно, для какого окна оно предназначено. Оно может иметь до двух параметров. Часто в эти два параметра упаковывается несколько совершенно различных величин.
Обработка разных сообщений выполняется разными компонентами операционной системы и приложения. Например, когда пользователь передвигает мышь по полю окна, формируется сообщение WM_MOUSEMOVE, которое передается окну, а окно, в свою очередь, передает это сообщение операционной системе. И уже последняя перерисовывает указатель мыши в новом месте. Когда пользователь щелкает левой кнопкой мыши на экранной кнопке, кнопка, которая также есть особый вид окна, получает сообщение WM_LBUTTONDOWN. В процессе обработки этого сообщения кнопка часто формирует новое сообщение для окна, в котором она находится, причем это сообщение гласит: "Ой, на мне щелкнули!".
Библиотека MFC позволяет программистам в подавляющем большинстве случаев полностью отстраниться от сообщений нижнего уровня, таких как WM_MOUSEMOVE и WM_LBUTTONOOWN. Программист может полностью сосредоточиться на сообщениях более высокого уровня, которые гласят что-нибудь вроде "Выбран третий элемент такого-то списка" или "Произошел щелчок на кнопке Move". Поступают такого рода сообщения в те программы, которые пишет программист, и в компоненты операционной системы точно так же, как и сообщения нижнего уровня. Единственная разница в том, что MFC берет на себя значительную часть работы по обработке сообщений низкого уровня и позволяет заметно облегчить распределение сообщений между разными классами объектов, на уровне которых и будет производиться их обработка.
Циклы обработки сообщений
Сердцем любой Windows-программы является цикл обработки сообщений (Message Loop), который практически всегда находится в функции WinMain(). Эта функция в Windows-приложениях играет ту же роль, что и функция Main () в DOS-приложениях,-- ее вызывает операционная система сразу же после загрузки приложения в память. Текст типичной функции WinMain() Представлен в листинге 3.2.
Листинг 3.2.Tипичнaя функцияWinMain()
int АРIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR IpCmdLine,
int nCmdShow) {
MSG msg;
if( !InitAppIication( hInstance))
return (FALSE);
if( !Initlnstance( hInstance,nCmdShow))
return (FALSE);
while( GetMessage( &msg, NULL, 0, 0)) {
TranslateMessage( &msg);
DispatchMessage( &msg):
} return (msg.wParam);}
В С-программах для Windows, похожих на эту, функция InitApplication() вызывает RegisterWindow(), a InitInstance() -- CreateWindow(). Затем наступает очередь цикла обработки сообщений. Он представляет собой типичную циклическую конструкцию С на базе оператора whi1е, внутри которой вызывается функция GetMessage(). Эта функция API заполняет msg кодом сообщения, которое операционная система распределила для этого приложения, и почти всегда возвращает TRUE. Таким образом, цикл повторяется снова и снова до тех пор, пока работает приложение. Единственный вариант, при котором GetMessage() возвращает FALSE, -- получение сообщения WM_QUIT.
При работе с сообщениями, поступающими с клавиатуры, некоторую часть предварительной обработки берет на себя функция API TranslateMessage(). Ее назначение состоит в следующем. Прикладной части программы нет дела до сообщений наподобие "Нажата клавиша <А>" и «Отпущена клавиша <А>". Прикладную часть интересует только то, какую литеру (символ) ввел пользователь, т.е. ее вполне удовлетворит сообщение "Введен символ А". Вот это преобразование -- нескольких сообщений о деталях процесса в одно сообщение о его сути -- и выполняет функция TranslateMessage(). Она перехватывает сообщения WM_KEYDOWN и WM_KEYUP и вместо них посылает сообщение WM_CHAR. Если пользоваться библиотекой MFC, то такие мелочи, как ввод символа А, проходят, как правило, мимо вас. Пользователь вводит текст в текстовое поле или в другой элемент управления, и забота программиста-- извлечь введенный текст из этого объекта после того, как пользователь щелкнет на ОК.
Функция API DispatchMessage() вызывает, в свою очередь, функцию WndProc() того окна, для которого предназначено сообщение. Типичная функция WndProc() в С-программе для Windows представляет собой огромный оператор switch с отдельными case для каждого сообщения, которое приложение намеревается самостоятельно обрабатывать. Текст ее приведен в листинге 3.3.
Листинг 3.3. Типичная функция WndProc()
LONG APIENTRY MainWndProc( HWND hwnd, // Дескриптоо окна.
UINT msg, //Тип сообщения.
UINT wParam, //' Дополнительная информация.
LONG IParam) //Дополнительная информация.
{
switch(msg) {
case WM_MOUSEMOVE:
// Обработка перемещения мыши.
break;
case WM_LBUTTONDOWN:
// Обработка щелчка левой кнопки мыши.
break;
case WM_ RBUTTONDOWN:
// Обработка щелчка правой кнопки мыши.
break;
case WM_PAINT :
/,/ Перерисовать окно. break;
case WM_DESTROY : // Сообщение: окно будет уничтожено.
PostQuitMessage( 0);
return 0;
break;
defauIt:
return (DefWindowProc( hwnd, msg, wParam, IParam));}
return (0);}
Вы, конечно, можете себе представить, какой длины достигает подобная функция в более или менее порядочном приложении. MFC решает проблему следующим образом--информация о сообщениях, которые должны обрабатываться, расположена поближе к функциям. которые и должны выполнять обработку. Таким образом, отпадает необходимость в огромных операторах switch, в которых сосредоточено распределение сообщений.
Карты сообщений
Использование карты сообщений (Message maps) лежит в основе подхода, который реализуется в MFC для программирования Windows-приложений. Суть его состоит в том, что от разработчика требуется только написать функции обработки сообщений и включить в свой класс карту сообщений, которая фактически скажет: "Я буду обрабатывать такое-то сообщение". После этого главная программа будет отвечать за то, чтобы сообщение было передано именно той функции, которая будет его обрабатывать.
Карта сообщений состоит из двух частей: одна-- в файле заголовка для класса .h, а другая -- в соответствующем файле реализации .срр. Они, как правило, формируются мастерами, хотя в некоторых случаях вы можете сделать это (или частично отредактировать их) и самостоятельно. В листинге 3.4 представлена часть текста файла заголовка одного из классов простого приложения ShowString.
Листинг 3.4. Карта сообщений из файла ShowString h
//{{AFX_MSG(CShowStringApp)
arx_msg void OnAppAbout();
// ВНИМАНИЕ!! Здесь ClassWizard будет добавлять и
// удалять функции-члены.
//НЕ РЕДАКТИРУЙТЕ текст в этих блоках!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
Карта сообщений для приложения Employee класса CEmployeeView:
- В файле EmployeeView.h
//{{AFX_MSG(CEmployeeView)
afx_msg void OnRecordAdd();
afx_msg void OnRecordDelete();
afx_msg void OnSortId();
afx_msg void OnSortName();
afx_msg void OnSortRate();
afx_msg void OnSortDepartment();
afx_msg void OnFilterDepartment();
afx_msg void OnFilterId();
afx_msg void OnFilterName();
afx_msg void OnFilterRate();
afx_msg void OnFileSaveAs();
afx_msg void OnRecordFind();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
Здесь объявляется функция OnAppAbout(). Специальным образом оформленный комментарий позволяет ClassWizard определить, какие именно сообщения перехватываются этим классом. DECLARE_MESSAGE_MAP -- это макрос, расширяемый препроцессором компилятора Visual C++, в котором объявляются переменные и функции, принимающие участие в этом фокусе с перехватом сообщений.
Карта сообщений в файле . срр, как показано в листинге 3.5, также достаточно проста.
BEGIN_MESSAGE_MAP(CShowStringApp, CwinApp)
//{{AFX_MSG_MAP(CshowStringApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
//}}AFX_MSG_MAP
// Стандартные команды для файловых документов.
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Стандартные команды настройки принтера.
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
Карта сообщений для приложения Employee класса CEmployeeView:
- в файле EmployeeView.cpp
BEGIN_MESSAGE_MAP(CEmployeeView, CRecordView)
//{{AFX_MSG_MAP(CEmployeeView)
ON_COMMAND(ID_RECORD_ADD, OnRecordAdd)
ON_COMMAND(ID_RECORD_DELETE, OnRecordDelete)
ON_COMMAND(ID_SORT_ID, OnSortId)
ON_COMMAND(ID_SORT_NAME, OnSortName)
ON_COMMAND(ID_SORT_RATE, OnSortRate)
ON_COMMAND(ID_SORT_DEPARTMENT, OnSortDepartment)
ON_COMMAND(ID_FILTER_DEPARTMENT, OnFilterDepartment)
ON_COMMAND(ID_FILTER_ID, OnFilterId)
ON_COMMAND(ID_FILTER_NAME, OnFilterName)
ON_COMMAND(ID_FILTER_RATE, OnFilterRate)
ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
ON_COMMAND(ID_RECORD_FIND, OnRecordFind)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Некоторые макросы карты сообщений
Макросы BEGIN_MESSAGE_MAP и END_MESSAGE_MAP, так же как DECLARE_MESSAGE_MAP в файле заголовка, объявляют члены (переменные и функции), которые программа должна использовать для того, чтобы разобраться в картах всех объектов системы. Существует довольно большой набор макросов, используемых для работы с картой сообщений. Некоторые из них перечислены ниже.
*DECLARE_MESSAGE_MAP. Используется в файле заголовка для того, чтобы объявить, что в файл собственно текста программы будет включена карта сообщений.
*BEGIN_MESSAGE_MAP. Отмечает начало карты сообщений в тексте программы.
*END_MESSAGE_MAP. Отмечает конец карты сообщений в тексте программы.
*ON_COMMAND. Используется для того, чтобы перенаправить обработку некоторой команды функции-члену класса.
· ON_CONTROL. Используется, для того, чтобы перенаправить обработку кода извещения от элемента управления, введенного программистом, функции-члену класса.
*ON_MESSAGE. Используется для того, чтобы перенаправить обработку некоторого сообщения, введенного программистом, функции-члену класса.
*ON_UPDATE_COMMAND_UI. Используется для того, чтобы перенаправить обновление, связанное с заданной командой, функции-члену класса.
*ON_NOTIFY. Используется для того, чтобы перенаправить функции-члену класса обработку заданного кода извещения, который сопровождается дополнительными данными от элемента управления.
Таким образом, если вы включаете в программу некоторый компонент карты сообщений и, когда такое сообщение возникает, происходит следующее. Функции, вызванные скрытым от вас циклом обработки сообщений, решают на основании этой таблицы, какой из объектов и какая из функций-членов этого объекта будет обрабатывать сообщение.
Что происходит с картой сообщений
Компоненты, которые добавлены в карту сообщений файла заголовка, могут быть истолкованы следующим образом: "Существует функция OnAppAbout(), которая не имеет параметров". Компонент, который добавлен в собственно текст программы (файл .срр). означает: "Когда придет сообщение от команды ID_APP_ABOUT, вызовите OnAppAbout()".
Каждое приложение имеет объект, который является наследником класса CWinApp, и имеет функцию-член Run(). Эта функция обращается к CWinThread:: Run(), которая значительно длиннее, чем WinMain(), но имеет точно такой же цикл обработки сообщений -- вызов GetMessage(), вызов TranslateMessage() и вызов DispatchMessage(). Почти все объекты-окна используют тот же самый класс окна, и ту же самую функцию WndProc(), но теперь названную AfxWndProc(). Функция WndProc(), как вы уже видели, знает дескриптор окна hWnd, для которого предназначено сообщение. Библиотека MFC, в свою очередь, содержит нечто, называемое картой дескрипторов (handle map), -- таблицу дескрипторов окон и указателей объектов. Таким образом, главная программа может, используя всю эту информацию, найти указатель на объект cWnd*. Далее она вызывает WindowProc()-- виртуальную функцию этого объекта. Кнопки или окна представления, естественно, имеют разные реализации этой функции, но волшебные свойства полиморфизма приводят к тому, что вызывается именно та реализация, которая нужна.
Функция WindowProc() вызывает OnWndMsg() -- функцию C++, которая собственно и обрабатывает сообщения. Во-первых, она проверяет, что же это было -- сообщение, команда или код извещения. Предположим, поступило сообщение. Тогда функция просматривает карту сообщений для своего класса, используя члены класса (переменные и функции), которые были установлены макросами BEGIN_MESSAGE_MAP, END_MESSAGE_MAP и DECLARE_MESSAGE_MAP. Помимо всего прочего, эти макросы организуют доступ к компонентам карты сообщений базового класса. Это означает, что если класс является производным от CView, но не перехватывает сообщений, которые обычно перехватываются базовым классом, то сообщение будет перехвачено функцией класса CView.
9. Реализация обработки сообщений в приложении с помощью ClassWizard. Виды сообщений
Как мастер СlassWizard помогает перехватывать сообщения
Читать карту сообщений в листинге программы совсем .непросто, но зато ее очень просто формировать с помощью ClassWizard. В Visual C++ версии 6.0 существуют два способа включения компонента в карту сообщений -- с помощью главного диалогового окна ClassWizard и с помощью одного из новых диалоговых окон, которые вставляют в программу обработчики сообщений или виртуальные функции.
Вкладки диалогового окна ClassWizard
Для того чтобы вывести на экран диалоговое окно мастера ClassWizard, нужно выбрать из меню View--ClassWizard или нажать <Ctrl+W>. ClassWizard имеет диалоговое окно с несколькими вкладками. Вкладка Message Maps (Карты сообщений). В верхней ее части имеется два раскрывающихся списка. В одном -- Project-- представлен проект, над которым вы в настоящее время работаете (в данном случае-- ShowString), в другом-- Class name-- класс, карта сообщений которого редактируется (в данном случае-- CShowSthngApp). Информация о карте сообщений этого класса выведена в других полях вкладки.
Ниже этих однострочных полей расположена пара многострочных окон. В том, что слева, перечислены сам класс и все команды, которые может сформировать пользовательский интерфейс. Когда в левом окне выделено имя класса, в правом перечислены все сообщения Windows, которые этот класс мог бы перехватывать. Кроме того, там же перечислены виртуальные функции, которые отвечают за обработку стандартных (наиболее распространенных) сообщений.
В правой верхней части окна находятся четыре кнопки, пользуясь которыми, можно включить новый класс в проект, новую функцию -- в существующий класс, для того чтобы перехватывать выделенное в левом окне сообщение, удалить функцию, которая ответственна за обработку выделенного сообщения, или вывести на экран текст этой функции. Типовая методика следующая -- нужно выбрать класс, сообщение и щелкнуть на кнопке Add Function с тем, чтобы добавить функцию, которая будет ответственна за обработку заданного сообщения. Ниже перечислены операции, которые будут выполнены после щелчка на Add Function.
*В конец файла текста программы включается заготовка ("скелет" -- skeleton) функции.
*В файл текста программы, в ту его часть, где размещена карта сообщений, включается новый компонент карты.
*В файл заголовка также включается новый компонент карты сообщений.
*Обновляются списки сообщений и функций-членов в окнах вкладки.
После включения новой функции щелчок на Edit Code позволит наполнить созданную ClassWizard заготовку функции содержанием соответственно тому, как планируется обрабатывать данное Сообщение. Того же результата можно достичь, сделав двойной щелчок на имени функции в списке Member Functions.
Этот список находится ниже окон списков Object IDs и Messages. В нем перечислены функции-члены текущего класса, которые связаны с определенными сообщениями. В данном случае имеются две такие функции.
* InitInstance(). Перегружает виртуальную функцию класса CWinApp -- базового класса для CShowStringApp. Эта функция помечена символом V в списке, что означает-- виртуальная функция (Virtual function).
*OnAppAbout(). Перехватывает команду ID_APP_ABOUT; помечена символом W в списке, что означает -- сообщение окна (Window message).
Функция InitInstance() вызывается после запуска приложения. Вам нет необходимости углубляться в подробности ее работы-- ClassWizard просто напоминает, что эта функция уже перегружена для данного приложения.
И наконец, ниже окна списка Member Functions выведено сообщение, напоминающее о назначении выделенного сообщения. В данном случае текст Called to implement wait cursors (Вызывается для установки курсора ожидания) -- это описание виртуальной функции DoWaitCursor().
В Visual C++ начиная с версии 5.0 предлагается новый дополнительный способ перехвата сообщений. Вместо того чтобы вызвать ClassWizard и затем не забыть найти правильное имя класса в раскрывающемся списке, нужно просто щелкнуть правой кнопкой мыши на имени класса в окне ClassView и затем выбрать пункт Add Windows Message Handler (Добавление обработчиков сообщений Windows) контекстного меню. Диалоговое окно в результате появится на экране.
В этом диалоговом окне не показаны виртуальные функции, которые перечислены в главном окне CiassWizard. Глядя на это окно, легко сообразить, что данный класс перехватывает команду ID_APP_ABOUT, но не перехватывает обновление команды (command update).
Для того чтобы добавить новую виртуальную функцию, нужно сделать двойной щелчок на имени класса в ClassView и выбрать пункт Add New Virtual Function (Добавление новой виртуальной функции) контекстного меню. Диалоговое окно в результате появится на экране.
В классе CShowStringApp уже перегружена виртуальная функция InitInstance(), но существуют и другие виртуальные функции, которые можно перегрузить. Как и на вкладке, сообщение в самом низу окна напоминает вам о назначении каждой функции. Сам же текст сообщения -- Саlled to implement wait cursors (Вызывается для установки курсора ожидания) --тот же, что и на вкладке.
Какой класс должен перехватывать сообщение
Главный фокус в работе с картой сообщений и обработкой сообщений-- решить, на какой класс возложить ответственность за перехват и обработку. Принять верное решение вы не сможете до тех пор, пока не будете четко представлять себе, для кого предназначены различные сообщения и команды типичного приложения. Обычно приходится выбирать что-нибудь из приведенного ниже списка.
*Активное представление (вид)
*Документ, представленный в нем
*Фрейм (рамка окна), который содержит активное представление
*Объект-приложение
Список сообщений
Существует почти 900 различных сообщений. Поскольку обычно для организации перехвата сообщений в приложении используется ClassWizard, представленный в нем список будет значительно короче (ведь в него отбираются только те сообщения, которые подходят для выбранного класса). Отнюдь не каждое окно может получить то или иное сообщение. Например, только класс, являющийся наследником CListBox, может получить сообщение типа LB_SETSEL, которое заставляет элемент управления типа список передвинуть подсветку на некоторый элемент списка. Префикс в имени сообщения указывает тип окна, для которого предназначено сообщение или которое его породило.
Какая разница, скажем, между ВМ-(button message) и ВN-(button notification) сообщением? ВМ-сообщение -- это сообщение, направленное объекту-кнопке, например "Действуй так, как будто на тебе щелкнули". A BN-сообщение -- это сообщение с кодом извещения, поступающего от объекта-кнопки окну, в котором эта кнопка находится и которое является "владельцем" кнопки. Это сообщение может, например, гласить: "Ой, на мне щелкнули!". То же самое справедливо для всех других модификаций сообщений, префиксы которых завершаются литерой М или N.
Иногда префикс не заканчивается буквой М. Например, СВ -- это префикс для сообщений от объекта - поля со списком, в то время как CBN является префиксом сообщения с кодом извещения, которое поле со списком передает окну-владельцу. Например, CBN_SELCHANGE-- это сообщение от поля со списком, извещающее "родителя" о том, что пользователь выбрал другой элемент списка.
10. Команды. Реализация обработки команд с помощью ClassWizard
Команды
Что такое команда? Это сообщение специального типа, которое формируется в тех случаях, когда пользователь выбирает пункт меню, щелкает на кнопке или каким-либо другим способом дает системе понять, что ему что-то от нее нужно. В прежних версиях Windows и выбор из меню, и щелчок на кнопке формировали сообщение WM_COMMAND. Наступили новые времена, и теперь только выбор из меню порождает сообщение WM_COMMAND, а щелчок на кнопке или выбор в списке порождает сообщение WM_NOTIFY с кодом извещения от элемента управления.
Все сообщения команд содержат в качестве первого параметра идентификатор ресурса -- выбранный пункт меню или кнопку, на которой щелкнули. Этот идентификатор ресурса присваивается в соответствии со стандартом на форматы подобного рода идентификаторов, например для пункта Save As меню File идентификатор будет иметь вид ID_FILE_SAVE.
Получать сообщения могут только объекты классов-наследников CWnd, а все объекты классов, порожденных от CCmdTarget, включая CWnd и CDocument, могут получать команды и извещения. Это означает, что класс, который наследует CDocument, может иметь карту сообщений, причем в ней не должно быть ни одного компонента, соответствующего сообщению, а только компоненты для команд и извещений. Тем не менее этот фрагмент программы по-прежнему называется картой сообщений.
Вам придется позаботиться о правильном выборе классов, которые будут обрабатывать все события, которые могут произойти в разрабатываемом приложении. Если пользователь изменяет размеры окна, посылается сообщение WM_SIZE, и вам, возможно, понадобится изменить масштаб изображения или выполнить еще что-нибудь с представлением в приложении. Если пользователь выбирает некоторый пункт меню, формируется команда, а это означает, что класс документа должен что-то сделать в ответ на нее.
Обновление команд
Рассмотрим, как программа выполняет блокировку определенных пунктов меню или кнопок в соответствии с контекстом задачи. Этот процесс назван обновлением команд (command updating).
Представьте себе на минуточку, что вы разрабатываете приложение и у вас возникла идея блокировать некоторые команды меню, чтобы показать, что они в данный момент недоступны. Реализовать эту прекрасную идею можно двумя способами.
Один состоит в том, чтобы организовать огромную таблицу, элементами которой будут все имеющиеся в приложении пункты меню, каждому из которых сопоставлен флаг. Состояние флага -- TRUE или FALSE -- указывает, доступен ли этот пункт меню. Как только возникает необходимость вывести меню на экран, можно быстренько просмотреть таблицу и все сразу станет ясно. При любой операции, которая может повлечь за собой изменения в статусе какого-либо пункта меню, таблица обновляется. Все это в совокупности называется подходом непрерывного обновления (continuous-updating approach).
Другой подход состоит в том, чтобы, не имея такой таблицы, перед каждым выводом меню на экран анализировать все условия, которые влияют на возможную блокировку. Он называется подходом обновления по требованию (update-on-demand approach). Именно такой подход и реализован в Windows.
Когда наступает время выводить на экран меню, конкретные объекты "знают", нужно ли блокировать связанный с ними пункт меню. Например, объект класса документа знает, был ли он модифицирован после последнего сохранения, и решает, стоит ли блокировать пункт Save меню File. Объект класса представления знает, есть ли выделенный фрагмент текста, и может решить, как поступить с пунктами Cut и Copy меню Edit. Все это означает, что комплексная задача блокировки пунктов меню в соответствии с контекстом приложения распределяется между различными объектами приложения, а не возлагается на главную вызывающую подпрограмму WndProc().
Подход, реализованный в MFC, состоит в том, чтобы использовать небольшой объект класса CCmdUI (класс интерфейса с командами пользователя -- command user interface) и предоставить ему возможность перехватывать любые сообщения ON_UPDATE_COMMAND_UI. Организовать такой перехват можно, добавив (или предоставив возможность ClassWizard добавить) макрос ON_UPDATE_COMMAND_UI в карту сообщений. Объект класса CCmdUI также используется для блокировки или разблокировки командных кнопок и других элементов управления.
Класс CCmdUI имеет следующие функции-члены.
*Enable(). Принимает аргумент TRUE или FALSE. Блокирует элемент интерфейса пользователя, если передан аргумент FALSE, в противном случае делает элемент доступным.
*SetCheck(). Включает или выключает элемент управления.
*SetRadio(). Включает или выключает элемент управления как принадлежащий к группе зависимых переключателей, из которых только один может быть включен.
*SetText(). Устанавливает текст надписи пункта меню или кнопки, если элемент управления -- кнопка.
*DoUpdate(). Формирует сообщение.
Как правило, выбор, какая из перечисленных функций-членов нужна вам для определенных целен, очевиден. Ниже приведена упрощенная версия карты сообщений объекта класса CWhoisView, производного от CFormView, который выводит информацию на экран для пользователя. Соответствующая экранная форма имеет несколько текстовых полей, и пользователь может вставлять текст в одно из них. Карта сообщений содержит компонент перехвата обновления для команды ID_EDIT_PASTE, что в тексте программы выглядит следующим образом:
BEGIN_MESSAGE_MAP(CWhoisView, CFormView)
…ON_UPDATE_COMMAND_ID(ID_EDIT_PASTE, OnUpdateEditPaste)
…END_MESSAGE_MAP()
Функция OnUpdateEditPaste(), которая перехватывает обновление, выглядит следующим образом:
void CWhoisView::OnUpdateEditPaste(CCmdUI * pCmdUI)
{pCmdUI->Enable(::IsCIipboardFormatAvailable(CF_TEXT));}
Здесь вызывается функция API ::IsCIipboardFormatAvailable(), которая проверяет, есть ли текст в системном буфере Clipboard. Дело в том, что другое приложение может загрузить из Clipboard изображение или другую нетекстовую информацию, но данное приложение такими возможностями не располагает. Поэтому, если в Clipboard содержится не текст, текстовое поле в экранной форме блокируется. Большинство функций обновления команд выглядит аналогично-- они вызывают Enable() c аргументом, который формируется в результате вызова некоторой функции, возвращающей TRUE или FALSE, или-- другой вариант-- аргумент является просто логическим выражением.
Как ClassWizard помогает перехватывать команды и их обновления
В диалоговом окне ClassWizard в списке Object IDs выделено имя класса. Ниже имеются идентификаторы всех ресурсов (меню, панелей инструментов, элементов управления и т.д.), которые могут формировать команду или сообщение при условии, что объект данного класса присутствует на экране. Если вы выделите один из них, то список связанных с ним сообщений Messages станет значительно короче.
С каждым идентификатором ресурса связаны только две строки в списке сообщений -- COMMAND и UPDATE_COMMAND_UI. Выбор первой позволяет добавить в класс функцию, которая будет обрабатывать либо ту команду меню, которую выбрал пользователь, либо щелчок на кнопке, т.е. в конечном счете обрабатывать команду. Выбор второй позволяет добавить в класс функцию, которая задает состояние пункта меню, кнопки или любого другого элемента управления перед тем, как операционная система соберется вывести его на экран, т.е. выполнить обновление команды. (Строка COMMAND выведена полужирным шрифтом, поскольку в классе CShowStringApp перехват этой команды уже запрограммирован.)
Если вы считаете нужным ввести новую функцию для перехвата команды или обновления, щелкните на кнопке Add Function. Это включит в процесс разработки еще один этап -- ClassWizard предоставит вам возможность изменять имя функции, которое он сформировал по стандартной схеме. Эта возможность оставлена для самых привередливых, поскольку стандартная схема формирования имени, как правило, не вызывает возражений даже у опытных программистов, давно имеющих дело с MFC. Имя функции обработки команды начинается с On. Оставшаяся часть формируется следующим образом-- удаляется ID и символы подчеркивания из идентификатора ресурса, а каждое слово пишется строчными литерами, кроме первого символа. Имена обработчиков обновления команд начинаются с OnUpdate, а далее используется то же преобразование идентификатора ресурса. Например, функция, которая перехватывает команду от ID_APP_EXIT, будет называться OnAppExit, а функция, которая обновляет ID_APP_EXIТ, будет называться OnUpdateAppExit.
Далеко не каждая команда нуждается в обработчике обновления. Объект класса фрейма окна выполняет некоторую работу в части блокировки элементов управления самостоятельно, безо всяких указаний на то со стороны разработчика. Пусть, скажем, у вас есть меню Network (Сеть), а в нем -- пункт Sent (Послать). Команда этого пункта меню перехватывается объектом класса документа. Если же в приложении не открыт ни один документ, этот пункт меню будет заблокирован главным окном приложения, причем блокировка организуется безо всяких усилий с вашей стороны. Для многих команд этого вполне достаточно, т.е. команда блокируется, если объект, который должен ее обрабатывать, не существует. Для других же, которые могут иметь смысл, только в случае, если что-то выбрано или выделено, схема блокировки значительно сложнее. Вот здесь и нужно участие разработчика в программировании процесса обновления команды.
11. Архитектура «Документ-представление». Классы документа и представления
Что такое класс документа
Формируя текст программы приложения с помощью AppWizard, вы имеете возможность оснастить свое детище всеми модными аксессуарами коммерческого продукта для Windows 95 -- панелью инструментов, строкой состояния, контекстным окном указателя, разнообразными меню и даже окном сообщения об авторских правах. Однако несмотря на все эти "примочки" полезность такого приложения равна нулю. Для того чтобы создать приложение, которое не только хорошо выглядит на экране, но и делает что-то полезное, вам волей-неволей придется вмешаться в текст программы, которую подготовил AppWizard. Это может быть просто или не очень просто, или даже очень сложно -- все зависит от того, что же в действительности должно делать приложение и как оно должно при этом выглядеть.
Возможно, наиболее существенным изменениям подвергнется часть подготовленной AppWizard программы, связанная с документом-- информацией, которую пользователь может сохранять в процессе работы с приложением и затем считывать, -- и с представлением -- средствами представления этой информации пользователю в процессе выполнения приложения. Положенная в основу MFC концепция документ/представление позволяет отделить данные от средств, с помощью которых пользователь имеет возможность просмотреть эти данные и манипулировать ими. Короче говоря, объекты-документы ответственны за хранение, загрузку и выгрузку данных, а объекты-представления, которые подчас представляют собой те же окна, позволяют пользователю просматривать данные на экране и редактировать их соответственно логике работы приложения. Рассмотрим основы работы MFC в части реализации концепции документ/представление.
Создавая SDI- и MDI-приложения, AppWizard изначально закладывает в них средства, ориентированные на реализацию концепции документ/представление. Это означает, что AppWizard формирует класс, производный от CDocument, и передает ему определенные задачи. Он также формирует класс представления, производный от CView, которому передает другие задачи. Давайте закажем AppWizard простейшее приложение и посмотрим, что он нам выдаст.
Выберите File--New, затем вкладку Projects. Установите имя проекта Арр1 и соответствующие каталоги для файлов проекта. Проверьте, чтобы был выбран вариант MFC AppWizard (ехе) в левом окне. Щелкните на ОК.
Пройдитесь по всем диалоговом окнам AppWizard, заказывая параметры в соответствии с приведенным ниже списком и каждый раз щелкая на Next.
Этап 1. Выберите Multiple documents.
Этап 2. Не меняйте настроек, предлагаемых AppWizard по умолчанию.
Этап 3. Не меняйте настроек, предлагаемых AppWizard по умолчанию.
Этап 4. Сбросьте все флажки, кроме Printing and print preview (Печать и предварительный просмотр распечатки).
Этап 5. Не меняйте настроек, предлагаемых AppWizard по умолчанию.
Этап 6. Не меняйте настроек, предлагаемых AppWizard по умолчанию.
На последнем этапе щелкните на кнопке Finish, и параметры выполненной настройки будут выведены в окне New Project Information (Информация о новом проекте). После щелчка на кнопке OK ClassWizard сформирует проект. В окне ClassView просмотрите список классов приложения. Создано шесть классов: CAboutDIg, CApp1App, CApp1Doc, CApp1View, CChiIdFrame и СМаinFrame.
Класс САрp1Doc представляет документ и содержит структуру данных, которыми может оперировать приложение. Организовать хранение данных в классе можно включением в него соответствующих членов-переменных. Текст файла заголовка, который AppWizard сформировал для класса CApp1 Doc, представлен в листинге 4.1.
Листинг4.1
// App1Doc.h : интерфейс класса СApplDoc
#if !defined(AFX_APP1DOC_H__528CF70C_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_)
#define AFX_APP1DOC_H__528CF70C_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
class CApp1Doc : public CDocument
{
protected: // Создаются только в случае сохранения-восстановления.
CApp1Doc();
DECLARE_DYNCREATE(CApp1Doc)
public:
public:
// Перегрузка.
// Перегрузка виртуальных функций, сформированная ClassWizard.
//{{AFX_VIRTUAL(CApp1Doc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Реализация
public:
virtual ~CApp1Doc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Карта сообщений
protected:
//{{AFX_MSG(CApp1Doc)
// ВНИМАНИЕ! ! Здесь ClassWizard будет добавлять и
// удалять функции-члены.
// НЕ РЕДАКТИРУЙТЕ текст в этих блоках!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Почти в самом начале листинга есть секция Атрибуты, за которой следует ключевое слово public. Именно здесь вам и нужно будет вставить объявления членов-переменных, в которых планируется хранить данные приложения. В приложении, которое будет рассмотрено дальше нужно будет сохранять массив объектов класса СРоint. Этот массив объявляется как член класса документа:
// Attributes
public:
CPoint m_points [100];
CPoint-- это класс MFC, который инкапсулирует информацию, имеющую отношение к точке на экране, в частности -- координаты этой точки х и у.
В тексте файла заголовка обратите внимание также на то, что класс САрр1Doc имеет две виртуальные функции-члены-- OnNewDocument() и Serialize(). MFC вызывает функцию OnNewDocument(), как только пользователь выберет команду File=>New (или соответствующую пиктограмму на панели инструментов, если таковая присутствует в приложении). Эту функцию можно использовать для выполнения всех инициализаций, необходимых новой порции данных. В SDI-приложении в таком случае закрывается открытый документ и новый пустой документ загружается в тот же самый объект класса. В MDI-приложении открывается новый пустой документ (создается новый экземпляр класса документа) в дополнение к уже существующему. Функция Serialize() используется для загрузки в файл и выгрузки из него данных, хранящихся в членах-переменных объекта класса документа.
Рассмотрим файл App1Doc.cpp:
// App1Doc.cpp : implementation of the CApp1Doc class
//
#include "stdafx.h"
#include "App1.h"
#include "App1Doc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CApp1Doc
IMPLEMENT_DYNCREATE(CApp1Doc, CDocument)
BEGIN_MESSAGE_MAP(CApp1Doc, CDocument)
//{{AFX_MSG_MAP(CApp1Doc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CApp1Doc construction/destruction
CApp1Doc::CApp1Doc()
{}
CApp1Doc::~CApp1Doc(){}
BOOL CApp1Doc::OnNewDocument()
{ if (!CDocument::OnNewDocument())
return FALSE;
return TRUE;}
/////////////////////////////////////////////////////////////////////////////
// CApp1Doc serialization
void CApp1Doc::Serialize(CArchive& ar)
{ if (ar.IsStoring())
{ }
else
{ }
}
#ifdef _DEBUG
void CApp1Doc::AssertValid() const
{
CDocument::AssertValid();
}
void CApp1Doc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CApp1Doc commands
Что такое класс представления
Как уже упоминалось, класс представления отвечает за вывод на экран данных, хранящихся в объекте класса документа, и позволяет пользователю модифицировать эти данные. Объект класса представления содержит указатель на объект класса документа, который используется для доступа к членам-переменным этого класса, где собственно и хранятся данные. Листинг 4.2 содержит текст файла заголовка, который AppWizard сформировал для класса CApplView.
Большинство программистов, имеющих дело с MFC, включают в класс документа открытые (public) члены с тем, чтобы не затруднять доступ к ним из объекта класса представления. Классический объектно-ориентированный подход, однако, требует включать в класс закрытые (private) или защищенные (protected) члены-переменные и открытые члены-функции считывания и модификации этих переменных.
// App1View.h : interface of the CApp1View class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_00C0F6B2220A
__INCLUDED_)
#define AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
class CApp1View : public CView
{
protected: // create from serialization only
CApp1View();
DECLARE_DYNCREATE(CApp1View)
// Attributes
public:
CApp1Doc* GetDocument();
// Operations
public:
// Перегрузка.
// ClassWizard генерирует перегрузку виртуальных функций
//{{AFX_VIRTUAL(CApp1View)
public:
virtual void OnDraw(CDC* pDC); // Перегружена для прорисовки
// в этом представлении.
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CApp1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Сформированные функции карты сообщений
protected:
//{{AFX_MSG(CApp1View)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in App1View.cpp
inline CApp1Doc* CApp1View::GetDocument()
{ return (CApp1Doc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ будет вставлять дополнительные объявления
// непосредственно перед предыдущей строкой
#endif // !defined(AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_
00C0F6B2220A__INCLUDED_)
Почти в самом начале текста имеется секция открытых атрибутов, в которой объявлена функция GetDocument(), возвращающая указатель на объект класса CApplDoc. Если, работая с классом представления, вы пожелаете получить указатель на объект класса документа, нужно будет вызвать эту функцию и она вернет вам требуемый указатель. Например, для того чтобы добавить объект класса СРоint в массив таких объектов, который является членом класса документа, можно использовать следующий оператор:
GetDocument()->m_points[x] = point;
Можно сделать то же самое, запомнив указатель, возвращаемый GetDocument(), в локальной переменной, а затем уже использовать ее для доступа к данным документа:
pDoc = GetDocument();
pDoc-> m_points[x] = point;
Второй вариант имеет смысл, если вы будете неоднократно использовать сохраненный указатель в функции или если выражение в форме GetDocument()-> переменная кажется вам сложным для восприятия в тексте программы.
В распространяемой (release) версии приложения функция GetDocument() объявлена как встроенная (inline). В смысле производительности программы нет никакой разницы в обеих формах обращения к членам объекта документа. Но в смысле читабельности текста программы второй вариант, несомненно, имеет преимущество. Встроенные функции расширяются в скомпилированной программе также, как и макросы, но, в отличие от макросов, компилятор при работе со встроенными функциями выполняет проверку типов аргументов.
Обратите внимание на то, что как класс представления, так и класс документа перегружают часть функций-членов своих базовых классов. Функция OnDraw() является одной из важнейших среди всех виртуальных функций, она является именно тем инструментом, с помощью которого производится рисование в окне приложения. Что касается других функций, то MFC вызывает PreCreateWindow() перед тем, как создается и присоединяется к объекту класса окон MFC окно Windows. Эта функция дает возможность модифицировать такие атрибуты окна, как положение и размер. Функция OnPreparePrinting() используется для модификации диалогового окна Print перед его выводом на экран. Функция OnBeginPrinting() дает шанс создать GDI-объект, такой как кисть или перо, который необходим для выполнения некоторых задач в процессе печати. И наконец, в функции OnEndPrinting() можно уничтожить любой объект, созданный функцией OnBeginPri nting().
...Подобные документы
Современные средства информационных технологий для разработки пользовательских приложений. Ввод и вывод информации. Встроенные диалоговые окна. Использование элементов управления, встраиваемых на рабочие листы. Создание диалоговых окон пользователей.
учебное пособие [2,1 M], добавлен 27.04.2011Обзор программных средств разработки приложений и обоснование выбора языка программирования. Классификация приложений для работы с базами данных. Функциональная структура базы данных с указанием назначения программных модулей, руководство пользователя.
дипломная работа [645,3 K], добавлен 21.11.2010Средства и технологии разработки приложений баз данных. Компоненты управления доступом к БД. Описание программного окружения доступа к данным. Механизм получения и отправки данных. Специфика связи внутреннего представления с интерфейсом приложения.
презентация [29,4 K], добавлен 19.08.2013Web-дизайн, web-страница, основы строения сайта. Текстовые редакторы для разработки Web приложений. Стандартные средства разработки для Unix систем. Профессиональные среды разработки и их ответвления. Визуальные редакторы для разработчиков Web.
курсовая работа [1,4 M], добавлен 12.08.2015Устройство веб-приложений, преимущества их построения. Характеристика технологий веб-программирования, используемых на стороне сервера и на стороне клиента. Формирование и обработка запросов, создание интерактивного и независимого от браузера интерфейса.
контрольная работа [76,4 K], добавлен 08.07.2014Структурные подразделения и отделы организации, ее технические программные средства. Разработка приложений обработки данных на ассемблере, языке программирования высокого уровня. Тестирование и оптимизация программных модулей. Разработка документации.
отчет по практике [175,0 K], добавлен 30.09.2022Вопросы программирования в Maple версий 6-11 и разработка приложений. Рассматривает эффективные приемы программирования и разработки приложений для многих разделов техники, математики, физики, для решения которых пакет не имеет стандартных средств.
монография [4,8 M], добавлен 13.03.2008Преимущества операционной системы Android. Проектирование интерфейса приложений. Визуальные редакторы и средства кроссплатформенной разработки. Оптимизация игрового процесса, выбор фреймворка и библиотек. Классификация и характеристика игр по жанрам.
дипломная работа [2,6 M], добавлен 10.07.2017Сущность языков разметки и этапы проектирования. Общая характеристика бесплатных приложений для работы с кодом в текстовом формате. Особенности визуальных редакторов и суть платных приложений. Стандартные средства разработки для Unix систем и их замена.
курсовая работа [49,6 K], добавлен 04.06.2013Архитектура операционной системы Android, набор библиотек для обеспечения базового функционала приложений и виртуальная машина Dalvik. Объектно-ориентированный язык программирования Java как инструмент разработки мобильных приложений для ОС Android.
дипломная работа [1,6 M], добавлен 08.07.2015Разработка критериев оценки экрана веб-приложений. Основные подходы к защите веб-приложений. Анализ российских нормативных документов. Зарубежная практика выбора экрана веб-приложений. Разработка и обоснование общих требований к механизмам защиты.
дипломная работа [68,7 K], добавлен 04.08.2016Разработка приложений на платформе Win32 для исследования взаимодействия между процессами через отображение файла в память. Модель приложений "клиент - сервер". Описание алгоритма работы программы-клиента и программы-сервера. Результаты работы приложений.
курсовая работа [869,3 K], добавлен 18.05.2014Жизненный цикл программного продукта. Современные среды разработки приложений. Защита информации в базах данных. Особенности разработки приложения с помощью среды Delphi 7. Проверка программного модуля на предмет соответствия стандартам кодирования.
отчет по практике [589,0 K], добавлен 18.05.2017Приложение для организации и контроля разработки программного обеспечения, сокращающее сроки проектирования программных продуктов и оптимизирующее данный процесс. Технологии создания приложений на платформе .NET. Алгоритм получения и обновления списка.
дипломная работа [861,9 K], добавлен 27.11.2014Проектирование системы управления базами данных. Особенности реализации в MS SQL. Разработка пользовательского интерфейса. Тестирование и отладка приложения. Руководство пользователя и системного администратора. Анализ и методы разработки приложений.
курсовая работа [867,9 K], добавлен 16.07.2013Средства разработки, ориентированные на конкретные СУБД. Наиболее известные приложения на основе Eclipse Platform. Проект NetBeans IDE, его возможности. KDevelop — свободная интегрированная среда разработки для UNIX-подобных операционных систем.
реферат [107,5 K], добавлен 14.04.2014Преимущество построения Web-приложений для поддержки стандартных функций браузера. Настройка проекта Web-приложения. Создание и изменение исходных файлов. Изменение файла JavaServer Pages по умолчанию. Основные проблемы при выполнении Web-приложений.
контрольная работа [362,8 K], добавлен 10.11.2013Подходы и алгоритмы автоматизации тестирования. Анализ специфики работы с локальными и веб-приложениями, внедрение автоматических тестов в процесс контроля качества приложений Global XB, GCube и Thistle. Оптимальный инструмент разработки скриптов.
дипломная работа [1,5 M], добавлен 15.01.2012Знакомство с этапами разработки трёх приложений для системы семейства Linux с использованием языка программирования С++. Анализ особенностей операционной системы Ubuntu 12.10. Характеристика способов тестирования команд с помощью стандартных средств.
контрольная работа [732,1 K], добавлен 06.08.2013Основные принципы написания оконных приложений с графическим интерфейсом на языке Java в среде Eclipse. Управление компоновками компонентов: показ диалоговых окон, вывод графической информации. Структура приложения и размещение элементов интерфейса.
лабораторная работа [1,1 M], добавлен 01.05.2014