Создадим программу, которая будет считать символы с клавиатуры и отображать их в клиентском окне. Для этого будем обрабатывать сообщение Windows WM_CHAR. Свяжем с ним функцию OnChar(UINT nChar, UINT nRepCnt, UINT nFlags ). Назовем программу Key. Будем создавать ее с помощью MFC Application Wizard, интерфейс
Этапы написания программы
1. Подготовка буфера для хранения символов
Определим в классе CKeyDoc, прототип которого содержится в заголовочном файле KeyDoc.h, строку-объект StringData класса MFC CString. Для этого добавим следующий код:
class CKeyDoc : public CDocument
{
……
DECLARE DYNCREATE(CKeyDoc)
Public:
CString StringData;
……
};
Проинициализируем переменную пустой строкой " ". Это делается в конструкторе объекта документа, расположенном в файле KeyDoc.cpp.
Конструктор объекта документа CKeyDoc:
CKeyDoc::CKeyDoc()
{
// TODO:
StringData="";
}
2. Чтение символов с клавиатуры
При нажатии клавиши Windows посылает сообщение WM_CHAR. Его надо связать с методом OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) объекта вида. Для этого используем утилиту Class View
CKeyView (нажмем правой кнопкой по имени класса в окне утилиты Class View ) $$\to$$ выберем пункт Properties.WM_CHAR. Раскрываем список действий в пустом поле напротив названия сообщения нажатием левой кнопкой мыши. Выбираем единственный вариант <Add> OnChar. Мастер автоматически создаст обработчик OnChar и откроет файл KeyView.cpp для редактирования тела метода.3. Сохранение символа в документе
Введенный символ находится в параметре nChar и его необходимо сохранить в строковом объекте StringData.
Обработчик OnChar:
void CKeyView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CKeyDoc *pDoc = GetDocument(); //Получение указателя на объект документа
ASSERT_VALID(pDoc); //Проверка указателя
if(!pDoc)
return;
pDoc->StringData += char(nChar); //Обновление строки символов
Invalidate(); //Вызов метода OnDraw
}
Макрос ASSERT_VALID проверяет, что полученный указатель действительно ссылается на документ (иначе ошибка).
4. Отображение текста
Вывод будем осуществлять в методе OnDraw( класса вида. Для вызова метода OnDraw используется функция Invalidate.
Метод OnDraw:
void CKeyView::OnDraw(CDC *pDC)
{
…
pDC->TextOut(0,0,pDoc->StringData);
}
Скомпилируем и запустим программу.
Усложним задачу. Потребуем, чтобы текст выводился в центре клиентской области окна. Для решения поставленной задачи изменим метод OnDraw.
Измененный метод OnDraw:
void CKeyView::OnDraw(CDC* pDC)
{
CKeyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect; //Переменная для хранения размеров клиентской области
GetWindowRect(rect); //Получение размеров клиентской области
int x=rect.Width()/2; //Задание координаты X центра клиентской области
int y=rect.Height()/2; //Задание координаты Y центра клиентской области
CSize size = pDC->GetTextExtent(pDoc->StringData); //Определение размеров выводимой строки в пикселях
x -= size.cx/2; //Сдвиг координаты X на половину длины выводимой строки влево
y -= size.cy/2; //Сдвиг координаты Y на половину высоты выводимой строки вверх
pDC->TextOut(x,y,pDoc->StringData); //Вывод строки в центр клиентской области
}
Напишем программу, которая будет создавать курсор, в выбранной произвольной точке клиентской области и выводить текст с указанной позиции. Создадим WM_CHAR. Чтобы создать курсор, необходимо знать его размеры (обычно высота равна высоте символа, а ширина 1/8 ширины символа). Курсор будем создавать в методе OnDraw. Чтобы определить размеры курсора, необходимо получить данные из структуры TEXTMETRIC. Для этого необходимо создать объект типа TEXTMETRIC и заполнить его поля, используя метод GetTextMetrics(tm) . Но сначала добавим в прототип класса CMouseView следующие переменные
void CMouseView::OnDraw(CDC* pDC)
{
CMouseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
TEXTMETRIC textmetric; //Переменная для хранения информации о шрифте
pDC->GetTextMetrics(textmetric); //Получение информации о шрифте
CSize size=pDC->GetTextExtent(pDoc->StringData); //Получение размеров выводимой строки в пикселях
CreateSolidCaret(textmetric.tmAveCharWidth/8,textmetric.tmHeight); //Создаём курсор
CaretPosition.x=size.cx; //Присваивание x корд. конца
CaretPosition.y=0; //Присваивание y корд.
SetCaretPos(CaretPosition); //Задаем позицию курсора
ShowCaret(); //Вывод на экран курсора
pDC->TextOut(0,0,pDoc->StringData);
}
Рассмотрим задачу вывода строки с места, на который указывает указатель мыши. Свяжем сообщение WM_LBUTTONDOWN с методом OnLButtonDown(UINT nFlags, CPoint point) . Параметр Cpoint (объект класса CPoint) содержит текущие координаты указателя мыши. Для очистки строкового объекта используется метод Empty() класса CString.
Обработчик нажатия левой кнопки мыши OnLButtonDown:
void CMouseView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
x=point.x; //Запоминаем координату X места где была нажата левая кнопка мыши
y=point.y; //Запоминаем координату Y места где была нажата левая кнопка мыши
CMouseDoc* pDoc = GetDocument(); //Получаем указатель на объект документа
ASSERT_VALID(pDoc); //Проверяем правильность указателя
pDoc->StringData.Empty(); //Очищаем выводимую строку
Invalidate(); //Вызываем OnDraw
CView::OnLButtonDown(nFlags, point);
}
В методе класса OnDraw сделаем изменения:
CaretPosition.x=x+size.cx; //Присваивание x корд. конца CaretPosition.y=y; …… pDC->TextOut(x,y,pDoc->StringData);
Скомпилируем и запустим приложение.
В этом параграфе будем рассматривать работу с меню с помощью редактора ресурсов на примере создания простой программы.
Создание меню
ID_FILE_PRINTWELCOME.В меню File появилась команда, но она не работает (не подключена). Для того чтобы программа реагировала на выбор только что созданного пункта меню, свяжем с ним обработчик.
Class View вызовем свойства класса CMenuView.ID_FILE_PRINTWELCOME и раскроем ветку.COMMAND и выберем "Add" OnFilePrintwelcome.Создадим переменную типа CString и инициализируем в объекте документа. Добавим код, выделенный жирным, в прототип класса CMenuDoc.
public: virtual ~CMenuDoc(); CString StringData;
Проинициализируем переменную в конструкторе:
StringData="";
Напишем код обработчика OnFilePrintwelcome
void CMenuView::OnFilePrintWelcome()
{
CMenuDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
pDoc->StringData="Добро пожаловать в меню.";
Invalidate();
}
Добавим следующую строку в метод OnDraw:
pDC->TextOut(0,0,pDoc->StringData);
Усложним задачу. Создадим полномасштабную ветку меню с собственными подменю. Добавим в меню пункт Demo.
Если в начало ввести , то первая буква меню будет подчеркнута. Пусть это буква D, тогда Alt+D - это клавишный ускоренный вызов. Добавим подменю в пункте Submenus. Выделим пункт Submenus, в раскрывшейся слева вкладке Type Hear введем имя первого элемента подмею. Добавим в подменю еще оди пункт. Получим:
Создание акселератора
Акселератор - сочетание клавиш для выбора команды меню. Чтобы добавить акселератор, сделаем следующее:
ID_SUBMENUS_SUB1.VK_F5 из списка в поле Key.Добавление кнопок на панель инструментов
Создадим кнопку на панели для команды Sub1
IDR_MAINFRAMEID_SUBMENUS_SUB1.Добавим код для пункта Sub1. Для этого вызовем свойства класса CMenuView из утилиты Class View. Перейдем к списку событий Events. Раскроем вкладку ID_SUBMENUS_SUB1 и добавим обработчик.
void CMenuView::OnSubmenusSub1()
{
CMenuDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
pDoc->StringData="Меню 1";
Invalidate();
}
Тоже можно сделать и для Sub2.
Создадим программу, которая будет выводить диалоговое окно в ответ на выбор пользователем пункта Show Dialogs в меню File. В диалоговом окне создадим текстовое поле и кнопку. При нажатии на кнопку в текстовое поле должна заноситься символьная строка. Символьную строку изменим и при выходе из диалогового окна в клиентской области выведем измененную символьную строку.
Создание диалогового окна
Создадим класс диалогового окна на основе созданного только что ресурса:
Связывание обработчиков с элементами диалоговых окон
При нажатии на кнопку в текстовом поле должна появиться строка "Текст в диалоговом окне". Свяжем сообщение о нажатии на кнопку с обработчиком этого сообщения
ID_BUTTON1 и добавим обработчик OnBnClickedButton1.Связывание переменных с элементами диалоговых окон
Visual C++ позволяет связывать переменные класса с элементами диалоговых окон. Создадим переменную m_text для хранения строки текстового поля с помощью мастера:
Control ID: IDC_EDIT1, в поле Category: Value, Variable type : CString, Variable name: m_text.Обработчик OnButton1:
void CDlg::OnBnClickedButton1()
{
m_text="Текст в диалоговом окне";
UpdateData(false);
}
Обмен информацией между переменной и элементом IDC_EDIT1 осуществляется в специальном методе, включенном в класс диалогового окна:
void CDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_text);
}
Код этого метода генерируется мастером, изменять его вручную не рекомендуется. Вызов метода UpdateData(BOOL) с параметром false заносит в текстовое поле значение переменной m_text. Вызов с параметром true присваивает переменной m_text содержимое текстового поля.
Переопределение метода для кнопки Ok
Переопределение необходимо, если поле редактировалось и необходимо сохранить текущее содержимое текстового поля. Для того чтобы переопределить метод, вызовем свойства класса CDlg, перейдем к списку виртуальных функций, нажав кнопку Overrides. Выберем метод OnOk().
void CDlg::OnOK()
{
UpdateData(true);
CDialog::OnOK();
}
Отображение диалогового окна
Чтобы класс вида мог работать с членами класса CDlg, необходимо включить в него Dlg.h - заголовочный файл класса CDlg:
#include "Dlg.h"
В методе OnFileShowdialogs() создадим новый объект класса CDlg и отобразим его, пользуясь методом DoModal(). Далее добавим в класс документа переменную StringData типа CString и присвоим ей значение переменной m_text. Выведем значение переменной StringData в клиентском окне в левом верхнем углу.
Обработчик OnFileShowdialogs:
void CDialogView::OnFileShowdialogs()
{
CDlg dlg;
int result=dlg.DoModal();
if(result==IDOK)
{
CDialogDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
pDoc->StringData=dlg.m_text;
Invalidate();
}
}
Добавим в метод OnDraw строку:
pDC->TextOut(0,0,pDoc->StringData);
Использование диалогового окна в качестве главного
Создадим диалоговое окно в качестве главного и выведем в нем, по нажатию на кнопку, текстовое сообщение.
Создадим программу BaseDialog.
CDialog ).Создавать класс диалогового окна в этом случае не надо. Его создал уже автоматически Application Wizard. Рассмотрим общий способ работы с элементами управления - будем рассматривать их как объекты:
Обработчик OnButton1:
void CBaseDialogDlg::OnButton1()
{
m_edit.SetWindowText(CString("Диалоговое окно!"));
}
Флажок - управляющий элемент, который позволяет выбрать один или несколько вариантов. Переключатели осуществляют выбор одного из нескольких элементов.
Флажки
Создадим диалоговое окно с тремя флажками и текстовым полем, в котором будет отображаться информация о выбранном флажке. Создадим программу Maps на основе диалогового окна (Dialog based). Редактор диалоговых окон: Удалить надпись "TODO …", и добавить три флажка и текстовое поле. Флажки надо выстроить в виде столбца. Текстовое поле расположим внизу. Названия флажков - Flag 1, Flag 2, Flag 3.
Выравнивание элементов в редакторе диалоговых окон:
Нажать на Ctrl и, не отпуская ее, щелкнуть на каждом из флажков. Последний из выбранных флажков будет служить "эталоном" (он выделен синими маркерами).
Связывание флажков с кодом программы:
С помощью Class View каждый флажок свяжем со своим обработчиком ( OnCheck1(), OnCheck2(), OnCheck3() ). Создадим переменную m_text и свяжем ее с текстовым полем.
void CMapsDlg::OnCheck1()
{
m_text="Выбран 1 флажок";
UpdateData(false);
}
void CMapsDlg::OnCheck1()
{
m_text=" Выбран 2 флажок ";
UpdateData(false);
}
void CMapsDlg::OnCheck1()
{
m_text=" Выбран 3 флажок ";
UpdateData(false);
}
Переключатели
Создать диалоговое окно с тремя переключателями и текстовым полем, в котором будет отображаться информация о выбранном переключателе. Создадим программу Radios на основе диалогового окна (Dialog based). Редактор диалоговых окон: Удалить надпись "TODO …" , и добавить три переключателя и текстовое поле. Переключатели надо выстроить в виде столбца и внизу текстовое поле. Названия переключателей: Radio 1, Radio 2, Radio 3.
void CRadiosDlg::OnRadio1()
{
m_text="Выбран 1 переключатель";
UpdateData(false);
}
void CRadiosDlg::OnRadio2()
{
m_text=" Выбран 2 переключатель";
UpdateData(false);
}
void CRadiosDlg::OnRadio3()
{
m_text=" Выбран 3 переключатель";
UpdateData(false);
}
Совместное использование флажков и переключателей
Создать диалоговое окно с тремя флажками, тремя переключателями и текстовым полем, в котором будет отображаться информация о выбранном варианте. Использовать групповые поля. Групповые поля предназначены для группировки элементов - как визуальной, так и функциональной. Все переключатели внутри группового поля работают совместно.
Создадим программу Choice на основе диалогового окна (Dialog based). Редактор диалоговых окон: Удалить надпись "TODO …" , и добавить две группы флажков и переключателей и одно текстовое поле. Названия переключателей - Math, Gum, Inf, Bio, флажки - Math, Phys, Hist, Bio. Создадим для каждого переключателя свой обработчик - OnRadio1(),…, OnRadio4(). Для текстового поля введем переменную m_text. Свяжем с флажками переменные, которые будут изменять состояния флажков. Эти переменные будут представлять весь элемент. Зададим нужное состояние флагов в обработчиках для каждого переключателя.
void CChoiceDlg::OnRadio1()
{
m_check1=true;
m_check2=true;
m_check3=false;
m_check4=true;
m_text="85 ball";
UpdateData(false);
}
void CChoiceDlg::OnRadio2()
{
m_check1=false;
m_check2=true;
m_check3=true;
m_check4=true;
m_text="70 ball";
UpdateData(false);
}
void CChoiceDlg::OnRadio3()
{
m_check1=true;
m_check2=true;
m_check3=true;
m_check4=false;
m_text="83 ball";
UpdateData(false);
}
void CChoiceDlg::OnRadio4()
{
m_check1=true;
m_check2=true;
m_check3=false;
m_check4=true;
m_text="70 ball";
UpdateData(false);
}
Список - управляющий элемент, представляющий пользователю перечень из нескольких строк. (Выделить -1 клик, выбрать - 2 клика.) Комбинированное поле - сочетание текстового поля, раскрывающегося списка и кнопки, с помощью которой пользователь открывает список. Бегунок - управляющий элемент. Чаще всего применяется для ввода числовых величин - например, интенсивности цвета.
Создадим список и выведем выбранную строку в текстовое поле. Создадим программу Lists на основе диалогового окна, добавим список, текстовое поле и 2 надписи ("Дважды щелкните по строке" и "Вы выбрали"). Управляющие элементы можно отображать и в обычном окне (недиалоговым). В этом случае нельзя воспользоваться редактором WISIWYG.
Создание объекта для работы со списком
Variable name: m_list.Инициализация данных в списке
Для инициализации данных используем метод OnInitDialog() и метод AddString(…) объекта m_list. Внесем список группы.
BOOL CListsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_list.AddString("Васильев Н.И.");
…
m_list.AddString("Яковлева Е.А.");
…
}
Замечание: Если сортировка не нужна, то сделать клик правой кнопкой мыши в редакторе диалоговых окон и вызвать Properties->Sort = false.
Обработка двойных кликов в списках
При двойном клике заносится текст выбранной строки в текстовое поле. Создадим переменную m_text типа CString, связанную с текстовым полем, и обработчик OnDblclkList1(). Для определения выбранной строки будем использовать метод GetCurSel(). Это метод класса CListBox. Он возвращает индекс строки, которую пользователь дважды кликнул левой кнопкой мыши. Содержимиое строки получим при помощи метода GetText(…) класса CListBox.
void CListsDlg::OnDblclkList1()
{
m_list.GetText(m_list.GetCurSel(),m_text);
UpdateData(false);
}
Создадим программу Combos на основе диалогового окна. Создадим комбинированное поле и текстовое поле. Добавим переменные m_combo типа CComboBox, связанную с элементом управления комбинированное поле, и m_text типа CString, связанную с текстовым полем. Комбинированные поля инициализируются в методе OnInitDialog():
BOOL CCombosDlg::OnInitDialogs()
{
CDialog::OnInitDialog();
m_combo.AddString("Васильев Н.И.");
…
m_combo.AddString("Яковлева Е.А.");
m_combo.SetCurSel(0); //Выбор первой строки списка
…
}
Программа должна сообщать, какую строку списка выбрал пользователь. Комбинированное поле генерирует событие CBN_SELCHANGE. Добавим обработчик этого события в класс диалогового окна.
Properties (Класс диалогового окна)->Events->IDC_COMBO1->CBN_SELCHANGE->OnSelchangeCombo1()
Обработчик OnSelchangeCombo1:
void CComboDlg::OnSelchangeCombo1()
{
m_combo.GetLBText(m_combo.GetCurSel(),m_text);
UpdateData(false);
}
Создадим программу Slider на базе диалогового окна. Добавим текстовое поле, две надписи ("координата бегунка" и "движение") и бегунок (ему присвотся идентификатор IDC_SLIDER1 ) и, связанную с ним, переменную m_slider типа CSliderCtrl. При инициализации бегунка необходимо задать его интервал. Эта величина определяет возможные позиции бегунка от крайнего левого до крайнего правого положения. В примере бегунок принимает значения от 1 до 100. Эти значения задаются методами SetRangeMin(…) и SetRangeMax(…) класса CSliderCtrl. Второй параметр этих методов показывает, нужно ли перерисовывать ползунок после изменения интервала. Передавая значение false, мы отказываемся от перерисовки.
BOOL CSliderDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_slider.SetRangeMin(1, false);
m_slider.SetRangeMax(100, false);
m_text="1"; //Связываем переменную с содержимым текстового поля и присваем значение 1
UpdateData(false);
…
}
Обработка сообщений бегунка
При перемещении бегунка элемент посылает сообщение WM_HSCROLL. Добавим его обработчик. Нам необходимо перехватывать сообщения с кодом SB_THUMBPOSITION, посылаемые при перемещение бегунка. Выведем в текстовом поле его новую позицию. Создадим переменную m_text, связанную с содержимым текстового поля, и присвоим ей значение параметра обработчика OnHScroll(). Объект m_text относится к классу CString, а параметр имеет целый тип. Для представления целого числа в виде текстовой строки воспользуется методом Format() класса CString.
void CSliderDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if(nSBCode == SB_THUMBPOSITION)
{
m_text.Format("%ld",nPos);
UpdateData(false);
}
else CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
Сериализация - процесс записи (чтения) объектовов и данных на диск (с диска).
Рассмотрим сериализацию как CString ), так и нестандартных. Если в программе отсутствует документ, на который можно возложить выполнение файловых операций (программы на базе диалоговых окон), то работают с классом MFC CFile.
Рассмотрим программу Writer, которая будет записывать на диск введенную строку, а затем, по требованию пользователя, загружать ее из файла.
void CWriterView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
//TODO:
CWriterDoc *pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData += char(nChar);
Invalidate();
}
Отобразим данные в OnDraw:
pDC->TextOut(0,0,pDoc->StringData);
Класс документа (файл WriterDoc.cpp) содержит встроенный метод Serialize(CArchive ar) . В этом методе происходит сериализация объекта StringData. Методу Serialize(CArchive ar) передается ссылка на объект ar класса CArchive. Работа с объектом ar практически не отличается от работы с потоками cout и cin.
if(ar.IsStoring()) ar<<StringData; else ar>>StringData;
Чтобы сообщить приложению об изменении данных (заносим новый символ), вызовем в OnChar(...) метод объекта документа SetModifiedFlag(). Если будет сделана попытка выхода из программы без сохранения данных, то приложение выведет диалоговое окно с предложением сохранить данные.
Добавим строку в метод OnChar(...): Д
pDoc->SetModifiedFlag();
При создании нового документа следует стереть старое содержимое StringData и обновить вид программы новыми данными документа.
Метод OnNewDocument:
BOOL CWriterDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
StringData="";
UpdateAllViews(NULL);
return TRUE;
}
Создадим пользовательский класс и организуем сериализацию его объектов. Пусть класс содержит строковую переменную (типа CString ). Кроме этого в классе должен быть реализован конструктор, три метода для работы со строками: AddText() - добавление текста в конец строки, DrawText() - вывод текста в констексте устройства и - очистка (стирание содержимого) строки .
Алгоритм организации сериализации нестандартных объектов
Serialize() класса CObject.Serialize(), добавить в проект новый файл .cpp и определить в нем метод Serialize().Реализуем пользовательский класс CData, наследуемый от CObject. Для этого создадим заголовочный файл Data.h и включим его в проект.
class CData: public CObject
{
private:
CString data;
DECLARE_SERIAL(CData);
public:
CData(){data=CString("");}
void AddText(CString text){data+=text;}
void DrawText(CDC* pDC) {pDC->TextOut(0, 0, data);}
void ClearText(){data="";}
void Serialize(CArchive archive);
};
Подключим Data.h в файл SerializerDoc.h, для этого добавим в начало файла строку:
#include "Data.h"
В классе документа введем переменную типа CData
… public: CData DataObject; …
Добавим в документ вида метод OnChar(…) и используем методы объекта DataObject.
void CSerializerView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CSerializerDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc)
return;
pDoc->DataObject.AddText(CString(char(nChar)));
Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}
Метод OnDraw:
void CSerializerView::OnDraw(CDC* pDC)
{
CSerializerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DataObject.DrawText(pDC);
}
Добавим в проект новый файл Data.cpp и определим Serialize(CArchive archive)
#include "stdafx.h"
#include "SerializerDoc.h"
void CData::Serialize(CArchive archive)
{
CObject::Serialize(archive); // Вызов метода Serialize() базового класса (CObject)
if(archive.IsStoring())archive<<data;
else archive>>data;
}
IMPLEMENT_SERIAL(CData, CObject, 0)
Макрос IMPLEMENT_SERIAL содержит дополнительные методы, ипользуемые Visual C++ для сериализации. Чтобы выполнить сериализацию для объекта DataObject класса CData, следует вызвать его метод Serialize(…) внутри метода Serialize(…) документа.
void CSerializerDoc::Serialize(CArchive ar)
{
DataObject.Serialize(ar);
// if (ar.IsStoring())
//{
// TODO: add storing code here
//}
//else
//{
// TODO: add loading code here
//}
}
Некоторые методы класса CFile:
| Метод | Назначение |
|---|---|
Abort |
Закрывает файл, игнорируя любые предупреждения и ошибки |
Close |
Закрывает файл и удаляет объект |
GetLength |
Получает длину файла |
GetPosition |
Получает текущую позицию файлового указателя |
Open |
Производит открытие файла с возможностью проверки ошибок |
Read |
Читает данные из файла с текущей позиции |
Remove |
Удаляет заданный файл |
Rename |
Переименовывает заданный файл |
Seek |
Перемещает файловый указатель в заданную позицию |
SeekToBegin |
Перемещает файловый указатель в начало файла |
SeekToEnd |
Перемещает файловый указатель в конец файла |
SetLength |
Изменяет длину файла |
Write |
Записывает данные в файл с текущей позиции |
Режимы открытия файлов в конструкторе класса CFile:
| Константа | Назначение |
|---|---|
CFile::modeCreate |
создает новый файл |
CFile::modeNoTruncate |
Комбинируеся с modeCreate - если создаваемый файл уже существует, он не обрезается до нулевой длины |
CFile::modeRead |
Открывает файл только для чтения |
CFile::modeReadWrite |
Открывает файл для чтения - записи |
CFile::modeWrite |
Открывает файл только для записи |
CFile::typeBinary |
Устанавливает двоичный режим |
CFile::typeText |
Устанавливает текстовый режим со специальной обработкой пар символов конца/перевода строки |
Задача: Написать программу, которая на базе диалогового окна по нажатию кнопки записывает в заданный файл на диске некоторый текст и считывает этот текст в тектовое поле в обратном порядке.
Создадим на базе диалогового окна программу . Создадим 4 текстовых записи, длина каждой записи 20 символов. Реализуем эти записи в программе как массив из 4-х символьных строк OutString.
… protected: HICON m_hIcon; char OutString[4][20]; …
Добавим в диалоговое окно необходимые управляющие элементы - два текстовых поля и кнопку. Для кнопки создадим функцию обработчик, создадим также две переменные m_text1 и m_text2 и свяжем их с текстовыми полями. Имя кнопки: Write and Read.
BOOL CFilerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
strcpy(OutString[0], "Иллюстрация ");
strcpy(OutString[1], "работы ");
strcpy(OutString[2], "с ");
strcpy(OutString[3], "файлами ");
m_text1 = CString(OutString[0]) + CString(OutString[1]) + CString(OutString[2]) + CString(OutString[3]);
UpdateData(false);
}
Для записи данных в файл будем использовать класс CFile. При нажатии на кнопку будет создаваться и открываться для записи файл data.txt. Запись будем производить с помощью метода Write(…), для чтения используем методы Read(…) и Seek(…) класса CFile.
void CFilerDlg::OnButton1()
{
UpdateData(true);
CFile OutFile("data.txt",CFile::modeCreate | CFile::modeWrite); //Создание обекта
OutFile.Write(m_text1.GetBuffer(), m_text1.GetLength()); //Запись данных в файл
OutFile.Close(); //Закрытие файла
CFile InFile("data.txt",CFile::modeRead);
ULONGLONG pos = InFile.SeekToEnd();
while(pos != CFile::begin)
{
char buf;
InFile.Seek(--pos,CFile::begin);
int n = InFile.Read(buf,1);
m_text2+=CString(buf);
}
UpdateData(false);
InFile.Close();
}
Создадим программу для построения алгебраических фракталов и рассмотрим на ее примере работу с растровыми изображениями на основе класса CImage. Алгебраические фракталы строятся на основе алгебраических формул, при этом по алгоритму производится последовательность преобразований исходных данных, и результаты очередного шага зависят от предыдущего. Будем строить фрактальное множество, заданное формулой: zn+1=zZnn+c, где : zn, c - комплексные числа, а - номер текущей итерации, z0=0. Для того чтобы получить изображение (фрактал), надо произвести определенное количество итераций для точки комплексной плоскости.
Алгоритм
Создание приложения
Напишем программу, реализующую данный алгоритм. Создадим CChildView (заголовочный файл ChildView.h):
public: CImage imgOriginal; //Объект класса CImage CRect m_ClientRect; //Переменная для хранения размеров клиентской области double m_LeftBound; double m_RightBound; double m_TopBound; double m_BottomBound; COLORREF m_ColorTable[16]; //Таблица цветов const unsigned int m_MaxIter; //Константа - максимальное число итераций
Проведем необходимую инициализацию в конструкторе (исходный файл ChildView.cpp ):
CChildView::CChildView(): m_MaxIter(256),
m_RightBound(0), m_LeftBound(-1.5),
m_TopBound(0.5), m_BottomBound(-0.5)
{
//Создание таблицы цветов
m_ColorTable[0] = RGB(128,0,0);
m_ColorTable[1] = RGB(255,0,0);
m_ColorTable[2] = RGB(255,128,128);
m_ColorTable[3] = RGB(255,128,192);
m_ColorTable[4] = RGB(255,0,255);
m_ColorTable[5] = RGB(128,0,255);
m_ColorTable[6] = RGB(0,0,255);
m_ColorTable[7] = RGB(0,0,128);
m_ColorTable[8] = RGB(0,128,128);
m_ColorTable[9] = RGB(0,255,0);
m_ColorTable[10] = RGB(128,255,128);
m_ColorTable[11] = RGB(255,255,128);
m_ColorTable[12] = RGB(255,255,0);
m_ColorTable[13] = RGB(255,128,0);
m_ColorTable[14] = RGB(255,128,64);
m_ColorTable[15] = RGB(128,64,0);
}
Добавим в класс CChildView с помощью мастера обработчик изменения размеров окна OnSize.
void CChildView::OnSize(UINT nType, int cx, int cy)
{
GetClientRect(m_ClientRect);
}
Добавим в класс CChildView функцию для построения фрактала. В прототип класса (файл CChildView.h ) добавим строку:
public: void BuildFractal();
Определим ее в файле ChildView.cpp
Функция BuildFractal:
void CChildView::BuildFractal()
{
imgOriginal.Destroy();
imgOriginal.Create(m_ClientRect.right,m_ClientRect.bottom,24);
double f_Dx = (m_RightBound - m_LeftBound)/m_ClientRect.right;
double f_Dy = (m_TopBound - m_BottomBound)/m_ClientRect.bottom;
Complex c0(m_LeftBound,m_TopBound);
for(int i = 0; i < m_ClientRect.right; i++)
{
for(int j = 0; j < m_ClientRect.bottom; j++)
{
Complex z0(0,0);
int n_Iter = 0;
while(n_Iter < m_MaxIter z0.Abs() < 4)
{
z0 = pow(z0,z0) + z0*z0*z0 + c0;
n_Iter++;
}
imgOriginal.SetPixel(i,j,m_ColorTable[n_Iter%16]);
c0 -= Complex(0,f_Dy);
}
c0 = Complex(c0.GetRe(),m_TopBound);
c0 += f_Dx;
}
}
В данной функции используются методы класса CImage: Destroy() - для удаления растрового изображения из объекта, Create(int nWidth, int nHeight, int nBPP) - для создания растрового изображения с размерами nWidth и nHeight и глубиной цвета nBPP, SetPixel(int x, int y, COLORREF color) - для закрашивания одного пикселя изображения. Также используется класс Complex, его полный исходный код приведен в приложении. Чтобы его использовать, нужно добавить в программу с помощью утилиты Solution Explorer файлы Complex.h и Complex.cpp в проект и добавить в файл ChildView.cpp следующую строку:
#include "Complex.h"
Построение и вывод изображения на экран будем производить по двойному клику левой кнопкой мыши. Обработчик OnLButtonDblClick (файл CChildView.cpp):
void CChildView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
BuildFractal();
Invalidate();
CWnd::OnLButtonDblClk(nFlags, point);
}
Обработчик OnPaint (файл CChildView.cpp):
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
if(!imgOriginal.IsNull())
imgOriginal.StretchBlt(dc,0,0,imgOriginal.GetWidth(),imgOriginal.GetHeight(),SRCCOPY);
}
Функция StretchBlt копирует изображение объекта класса CImage в контекст устройства, переданный ей в качестве параметра. Чтобы сохранить полученное изображение, обработаем пункт меню Save.
Обработчик OnFileSave:
void CChildView::OnFileSave()
{
CString strFilter;
HRESULT hResult;
//Строка с поддерживаемыми расширениями
strFilter = "Bitmap image|*.bmp|JPEG image|*.jpg|GIF image|*.gif|PNG image|*.png||";
//Создание стандартного диалога сохранения
CFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,strFilter);
hResult = (int)dlg.DoModal(); //Вызов диалога сохранения
if (FAILED(hResult)) return;
//Создание строки с путем и полным именем файла, в который будет производиться сохранение
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if (dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1 : strExtension = "bmp"; break;
case 2 : strExtension = "jpg"; break;
case 3 : strExtension = "gif"; break;
case 4 : strExtension = "png"; break;
default : break;
}
strFileName = strFileName + '.' + strExtension;
}
//Сохранение
hResult = imgOriginal.Save(strFileName);
if (FAILED(hResult))
{
CString fmt;
fmt.Format("Save image failed:\n%x", hResult);
::AfxMessageBox(fmt);
return;
}
}
Для сохранения изображения используется метод класса CImage: Save, которому необходимо передать строку с путем и именем файла.
Для использования класса CImage и математических формул, необходимо добавить в файл stdafx.h строки:
#include <atlimage.h> #include <cmath>
Программа готова. Скомпилируем и запустим. В результате должно получиться следующее изображение:рис 4.1
(рис 4.1) Изображение после компиляции программы
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.