Среда, 08.01.2025, 20:48
Главная Регистрация RSS поиск
Приветствую Вас, Гость
Меню сайта
Категории раздела
HTML [44]
Visual C++ и MFC [21]
c++ [78]
php [19]
Javascript [15]
C# [51]
загрузки [0]
XNA [10]
создание игр с помощью xna
Наш опрос
Каким языком программирования вы увлекаетесь
Всего ответов: 2420
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Реклама
Главная » Статьи » Visual C++ и MFC

Практический пример
Практический пример

Любая теория полезна тогда, когда ее возможно применить на практике. Давайте, вместе рассмотрим практический пример, посвященный изученному материалу. Предположим, что Заказчик ставит перед нами следующую задачу:

Задача

Разработать приложение, которое переводит числа из одной системы исчисления (восьмиричной, десятичной, шестнадцатиричной) в другую.

Анализ задачи

Н-да, Заказчик оказался не многословным... Давайте детальней вникнем в суть поставленной задачи. Известно, что существуют разнообразные системы исчислений. Возникает первый вопрос: "Что такое система исчисления?". Мы привыкли использовать в повседневной жизни десятичную систему исчисления, т.е. с помощью цифр от 0 до 9 мы можем представить любое число. Однако, десятичная система исчисления не единственная в мире. К примеру, широкое распространение в программировании имеют восьмиричная (0,1,2,3,4,5,6,7) и шестнадцатиричная системы исчислений (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F). Скорее всего, Вы сталкивались с различными системами исчисления при работе со стандартной программой Windows "Калькулятор" (calc.exe). Нам необходимо написать приложение, которое бы преобразовавало числа из одной системы исчисления в другую, например: 1AB (шестнадцатиричная система исчисления) в десятичной системе исчисления равняется 427, а в восьмиричной = 653.

Для преобразования чисел из десятичной(10) системы исчисления в восьмиричную(8) и шестнадцатиричную(16) удобно использовать метод Format класса CString. Таким образом практически с минимальными усилиями мы получаем требуемый результат. Важным вопросом является преобразованиее 16 в 10 и 8 в 10. Здесь нам прийдется разработать свой алгоритм преобразования, о котором мы говорили на занятии. Вопрос связанный с преобразованиями: 16 в 8 и 8 в 16 решается практически моментально, если мы сможем преобразовать 16 в 10 и 8 в 10. Другими словами, если необходимо сделать преобразование 16 в 8 мы выполним преобразование 16 в 10, а затем 10 в 8.

Подготовка формы

Начнем, пожалуй с того, что создадим с помощью MFC AppWizard (exe) приложение основанное на диалоговом окне. Предпологаем, что у Вас уже не возникает вопрос: "А как это сделать?", иначе советуем еще раз рассмотреть первое занятие посвященное Visual C++ & MFC.

Если Вы создали приложение, то перед Вами должна предстать следующая картина:

Давайте, чуть-чуть подредактируем нашу форму. Перенесем статический текст вверх, разместим на форме Edit Box (текстовое поле) и четыре Radio Button (радио-кнопка). Также, удалим кнопку Cancel. Теперь добавим немного косметики, т. е. подровняем элементы управления относительно формы. После всех преобразований Ваша форма должна принять следующий вид:

Пойдем дальше... Щелкнем правой кнопкой мыши на форме диалогового окна и выберем пункт Properties (тоже самое: пункт меню View->Properties). В появившемся диалоговом окне Dialog Properties щелкните на кнопке Keep Visible (отмечена стрелкой). Окно свойств будет оставаться постоянно видимым на экране.

Выделим первый Radio Button. Для этого щелкнем левой кнопкой мыши на переключателе Radio1. В окне Dialog Properties включим переключатель Group, что позволит сгруппировать расположенные на форме радио-кнопки. Таким образом, из всех радио-кнопок сможет быть активной толко одна!

Щелкним закладку Styles и выберим переключатель Flat - немного изящности нашему приложению не помешает. Также выберим каждый из Radio Button и дадим ему соответсвующий заголовок (с помощью поля Caption), в точности так, как показано на рисунке. Обратим наш взгляд на Edit Box. Щелкнем на нем левой кнопкой мыши и в окне Dialog Properties выберем переключатель Uppercase и в списке Aligh text выберем значение Right.

Почти все, но статическому тексту дадим более осмысленное название, к примеру "Введите число". В конечном итоге, Ваша форма примет следующий вид:

Вы можете откомпилировать проект и посмотреть что получилось. Сейчас, наше приложение содержит только интерфейс, который не имеет практической поддержки. Другими словами, мы сделали то, что мог бы сделать каждый, имея навыки работы в Windows и абсолютно ничего не зная о программировании. Теперь слово за программированием...

Реализация алгоритма

Итак, интерфейс пользователя оформлен! Уже часть дела сделана. Сейчас нам необходимо, связать группу радио-кнопок с переменной. Для этого, давайте, снова щелкнем левой кнопкой мыши на Radio Box с заголовком 8 и нажмем комбинацию клавиш Ctrl+W (запуск MFC ClassWizard). В ClassWizard выберите вкладку Member Variables. Убедитесь что в списке Class name выбран класс диалогового окна и щелкнете на идентификаторе IDC_RADIO1 и нажмите кнопку Add Variable...(если что-то не понятно - смотрите рисунок).

В появившемся диалоговом окне укажите имя переменной: m_Radio и нажмите кнопку Ok.

Проделав вот такие нехитрые движения, мы с Вами связали поле m_Radio с группой переключателей Radio Box. Пойдем дальше... Нам также необходимо объявить указатель на класс CEdit, для того чтобы иметь возможность обратиться к Edit Box как к элементу управления. Щелкнем левой кнопкой мыши на вкладке Class View. Раскроем дерево классов и правой кнопкой мыши щелкнем на классе диалогового окна CConvertDlg. В появившемся меню выберим пункт Add Member Variable...

Перед Вами откроется диалоговое окно, в котором необходимо указать тип и имя создаваемой переменной. В верхнем текстовом поле введем CEdit*, а в нижнем m_pEdit и не забудем установить переключатель в режим Private, так как показано на рисунке:

Аналогичным образом, добавьте к классу диалогового окна поле short int m_LastMode и функцию: void ConvertValue(). Поле m_LastMode будет содержать предпоследний выбор системы исчисления пользователем, а функция ConvertValue() позволит преобразовать число из одной системы исчисления в другую.

Перейдем к коду. Поскольку все дополнения касаются только класса диалогового окна, то здесь приведены только заголовочный файл и файл реализцаии соответсвующего класса. Все дополнения произведенные в классе диалогового окна сгенерированного AppWizard-ом выделены жирным шрифтом.

Заголовочный файл:

// ConvertDlg.h : header file
//

#if !defined(AFX_CONVERTDLG_H__1E772CD7_1464_413E_848C_263E366397A8__INCLUDED_)
#define AFX_CONVERTDLG_H__1E772CD7_1464_413E_848C_263E366397A8__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CConvertDlg dialog

class CConvertDlg : public CDialog
{
// Construction
public:
 CConvertDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
 //{{AFX_DATA(CConvertDlg)
 enum { IDD = IDD_CONVERT_DIALOG };
 int m_Radio;
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CConvertDlg)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 HICON m_hIcon;

 // Generated message map functions
 //{{AFX_MSG(CConvertDlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg void OnRadio1();
 afx_msg void OnRadio2();
 afx_msg void OnRadio3();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
private:
 short int m_LastMode;
 void ConvertValue();
 CEdit* m_pEdit;
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations 
//immediately before the previous line.

#endif 

Файл реализации:

// ConvertDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Convert.h"
#include "ConvertDlg.h"

// в примере используется функция double pow(double, double)
//поэтому необходимо подключить библиотеку math
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
 CAboutDlg();

// Dialog Data
 //{{AFX_DATA(CAboutDlg)
 enum { IDD = IDD_ABOUTBOX };
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAboutDlg)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 //{{AFX_MSG(CAboutDlg)
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
 //{{AFX_DATA_INIT(CAboutDlg)
 //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAboutDlg)
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 //{{AFX_MSG_MAP(CAboutDlg)
 // No message handlers
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CConvertDlg dialog

CConvertDlg::CConvertDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CConvertDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CConvertDlg)
 m_Radio = -1;
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 m_pEdit=NULL;
}

void CConvertDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CConvertDlg)
 DDX_Radio(pDX, IDC_RADIO1, m_Radio);
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CConvertDlg, CDialog)
 //{{AFX_MSG_MAP(CConvertDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_RADIO1, OnRadio1)
 ON_BN_CLICKED(IDC_RADIO2, OnRadio2)
 ON_BN_CLICKED(IDC_RADIO3, OnRadio3)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CConvertDlg message handlers

BOOL CConvertDlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Add "About..." menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
 CString strAboutMenu;
 strAboutMenu.LoadString(IDS_ABOUTBOX);
 if (!strAboutMenu.IsEmpty())
 {
 pSysMenu->AppendMenu(MF_SEPARATOR);
 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 }
 }

 // Set the icon for this dialog. The framework does this automatically
 // when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE); // Set big icon
 SetIcon(m_hIcon, FALSE); // Set small icon
 
 //установим переключатель на десятичную систему исчисления
 //поле m_Radio связано с группой радио-кнопок
 //присваивая значение от 0 до 2 (как всегда отсчет с нуля), 
 //мы выбираем нужную радио-кнопку
 m_Radio=m_LastMode=1;
 UpdateData(FALSE);
 
 SetDlgItemText(IDC_EDIT1,"0");
 //получим указатель на Edit Box (напоминаем, что его идентификатор IDC_EDIT1)
 m_pEdit=(CEdit*) GetDlgItem(IDC_EDIT1);
 //установим ограничение на количество вводимых символов
 //максимальный диапазон данных типа UINT может быть 
 //4294967295 
 m_pEdit->SetLimitText(10);
 //установим стиль позволяющий вводить только цифры
 m_pEdit->ModifyStyle(0,ES_NUMBER,0);

 return TRUE; // return TRUE unless you set the focus to a control
}

void CConvertDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
 CAboutDlg dlgAbout;
 dlgAbout.DoModal();
 }
 else
 {
 CDialog::OnSysCommand(nID, lParam);
 }
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CConvertDlg::OnPaint() 
{
 if (IsIconic())
 {
 CPaintDC dc(this); // device context for painting

 SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

 // Center icon in client rectangle
 int cxIcon = GetSystemMetrics(SM_CXICON);
 int cyIcon = GetSystemMetrics(SM_CYICON);
 CRect rect;
 GetClientRect(&rect);
 int x = (rect.Width() - cxIcon + 1) / 2;
 int y = (rect.Height() - cyIcon + 1) / 2;

 // Draw the icon
 dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
 CDialog::OnPaint();
 }
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CConvertDlg::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CConvertDlg::ConvertValue()
{
 
 //получим данные о произведенном выборе
 UpdateData(TRUE);
 //если пользователь щелкнул на том же самом переключателе - выход из функции
 if (m_Radio==m_LastMode) return;
 
 
 CString sNumber;//здесь будет храниться содержимое Edit Box
 m_pEdit->GetWindowText(sNumber);//Получаем содержимое Edit Box
 
 CString sNewValue;//вспомогательный объект
 int i=0, z=0,Sum=0;
 //i - счетчик
 //z - будет содержать цифру, полученную в результате 
 //преобразования из одной системы в другую
 //Sum - будет содержать полное число в ДЕСЯТИЧНОЙ системе исчисления (с.и.)

 switch(m_LastMode){
 
 //была шестнадцатиричная с.и.
 case 2: 
 sNumber.MakeReverse();//производим "переворот" строки
 for (;i<sNumber.GetLength();i++)//пройдемся по всем ЦИФРАМ числа
 {
 if (isdigit(sNumber.GetAt(i)))//если это символ от '0' до '9'
 {
 sNewValue=sNumber.GetAt(i);//то запоминаем символ в строке
 z=atoi(sNewValue);//преобразовуем строку в цифру
 }
 else //если это не символ в диапазоне от '0' до '9'
 if (isxdigit(sNumber.GetAt(i)))//то это должен быть символ от 'A' до 'Z'
 switch (sNumber.GetAt(i)){//проверим какой именно это символ
 case 'A':z=10;break;
 case 'B':z=11;break;
 case 'C':z=12;break;
 case 'D':z=13;break;
 case 'E':z=14;break;
 case 'F':z=15;break;
 }
 else //внештатная ситуация, пользователь ввел "чужой" символ
 {
 MessageBox("You had entered wrong symbol!\rTake care friend...","Illegal symbol",MB_OK|MB_ICONHAND);
 Sum=0;
 break;
 }
 //полученное число z * на 16 (так как с. и. шестнадцатиричная)
 //в степени i (так как важен порядок цифр в числе)
 Sum+=int(z*int(pow(16,i))); 
 }
 if (m_Radio==0)//если пользователь выбрал 8 с.и.
 sNewValue.Format("%o",Sum);//то преобразуем в 8
 else sNewValue.Format("%u",Sum);//иначе, преобразуем в 10 с.и.
 break;
 
 //была десятичная с. и.
 case 1: switch(m_Radio){
 case 0:sNewValue.Format("%o",atoi(sNumber));break;//в восмиричную систему исчисления
 case 2:sNewValue.Format("%X",atoi(sNumber));;break;//в шестнадцатиричную систему исчисления
 }
 break;
 
 //была восьмиричная с. и.
 case 0: sNumber.MakeReverse();
 for (;i<sNumber.GetLength();i++)
 {
 sNewValue=sNumber.GetAt(i);
 z=atoi(sNewValue);
 if (z>7){
 MessageBox("You had entered wrong symbol!\rTake care friend...","Illegal symbol",MB_OK|MB_ICONHAND);
 Sum=0;
 break;
 }
 Sum+=int(z*int(pow(8,i)));
 }
 if (m_Radio==2)//16
 sNewValue.Format("%X",Sum);
 else sNewValue.Format("%u",Sum);
 break;
 }
 
 m_pEdit->SetWindowText(sNewValue);//обрадуем Edit Box новым содержимым
 m_LastMode=m_Radio;//запомним текущий выбор 
}

void CConvertDlg::OnRadio1() //в восмиричную систему исчисления
{
 //установим ограничение на количество вводимых символов
 //максимальный диапазон данных типа UINT может быть 
 //37777777777
 m_pEdit->SetLimitText(11);
 //установим стиль, позволяющий вводить только цифры
 m_pEdit->ModifyStyle(0,ES_NUMBER,0);
 ConvertValue();
}

void CConvertDlg::OnRadio2() //в десятичную систему исчисления
{
 //установим ограничение на количество вводимых символов
 //максимальный диапазон данных типа UINT может быть 
 //4294967295 
 m_pEdit->SetLimitText(10);
 //установим стиль, позволяющий вводить только цифры
 m_pEdit->ModifyStyle(0,ES_NUMBER,0);
 ConvertValue();
}

void CConvertDlg::OnRadio3() //в шестнадцатиричную систему исчисления
{
 //установим ограничение на количество вводимых символов
 //максимальный диапазон данных типа UINT может быть 
 //0xffffffff
 m_pEdit->SetLimitText(8);
 //СНИМИМ стиль позволяющий вводить только цифры,
 //ИНАЧЕ пользователь не введет ABCDEF
 m_pEdit->ModifyStyle(ES_NUMBER,0,0);
 ConvertValue(); 
}
Категория: Visual C++ и MFC | Добавил: slava (26.09.2009)
Просмотров: 10454 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]