- •О.С. Зеленський
- •Розділ 9. Структура створення додатків
- •9.1. Загальна структура додатків
- •9.2. Додатки без використання архітектури «Документ-вид»
- •9.2.1. Приклад додатку реєстрації wnd-класу вікна
- •9.2.2. Створення та видалення дочірніх вікон без використання архітектури «Документ-Вид»
- •9.2.3. Створення дочірніх вікон без використання архітектури «Документ-Вид» (переключення вікон з використанням функції ShowWindow)
- •9.3. Архітектура «Документ-Вид»
- •Idr_mainframe формат строкового ресурсу.
- •9.3.1. Приклад додатку з використанням архітектури «Документ-Вид»
- •9.3.2. Види у архітектурі «Документ-Вид»
- •9.3.3. Створення видів у архітектурі «Документ-Вид» (переключення видів з використанням функції ShowWindow)
- •9.3.4. Робота з документами та видами на прикладі додатку SingleTemplate
- •9.4. Додатки mdi, робота з шаблонами
- •9.4.1. Приклад додатку mdi з одним шаблоном
- •9.4.2. Приклад додатку mdi з декількома шаблонами
- •Контрольні питання
- •Розділ 10. Робота з базами даних з використанням об'єктів ado
- •10.1.1. Ініціалізація об'єктів com з використанням директиви #import
- •10.1.2. Підтримка класів сом
- •10.2. Об'єкт Connection
- •10.3. Об'єкт Command
- •10.4. Об'єкт Recordset
- •10.5. Об'єкт Field і колекція Fields
- •10.6. Об'єкт Error і колекція Errors
- •10.8. Коротка характеристика структури мови sql
- •10.9. Синтаксис оператора вибору Select
- •10.10. Приклад програмування об'єктів ado
- •10.11. Опис розробленого навчального пакету ado6 для роботи з базами даних access та MySql
- •Int tip_bd; // тип бд 1- ms access, 2- MySql, 3 - xml
- •Void Connect_Baza(cString str);
- •Void ErrMessage(_com_error &ce);
- •If(pConn.CreateInstance("adodb.Connection"))
- •If(pRecordset.CreateInstance("adodb.RecordSet"))
- •Void cAdo6Doc::ErrMessage(_com_error &ce)
- •Void cAdo6Doc::OnMsaccess()
- •Void cAdo6Doc::OnMysql()
- •Void cAdo6Doc::OnXmlRead()
- •Void cAdo6Doc::Connect_Baza(cString str)
- •Virtual void DoDataExchange(cDataExchange* pDx);
- •Void cAdo6Dlg::DoDataExchange(cDataExchange* pDx)
- •Void cAdo6Dlg::Struct_MySql()
- •Void cAdo6Dlg::OnSelchangeListBaza()
- •Void cAdo6Dlg::OnVibor_bd()
- •Void cAdo6Dlg::AccessOpen()
- •Void cAdo6Dlg::xmlOpen()
- •Void cAdo6Dlg::Structura_bd()
- •Void cAdo6Dlg::OnSelchangeListTab()
- •Void cAdo6Dlg::show(int kod, int kod_bd)
- •Void cAdo6Dlg::Recordset_Baza(cString str)
- •Void cAdo6Dlg::OnClose()
- •10.11.2. Формування списку бд (MySql), відкриття бази даних (ms access), відкриття xml-файлу, формування списку таблиць (MySql і ms access) та полів (MySql, ms access, xml)
- •Void cAdo6Dlg::OnSelchangeListTab()
- •1. Обрану таблицю необхідно брати в зворотні лапки "`", щоб виключити помилку в тому випадку, якщо в імені таблиці будуть зустрічатися пробіли.
- •10.11.3. Робота з sql-запитами
- •Void cAdo6Dlg::OnZapros_Select()
- •If (str_query.Mid(0,6).Compare("select"))
- •If(!baza.Left(3).Compare("otl") &&
- •Void cAdo6Dlg::Recordset_Baza(cString str)
- •Void cado6Dlg::OnZapros_Make()
- •Vr_zap.Format(" Запрос выполнен за %f сек ",conec - nach);
- •10.11.4. Видалення, сортування, пошук, фільтрація, оновлення набору записів
- •Void cado6Dlg::OnZapis_Delete()
- •Void cado6Dlg::OnCheck_Sort()
- •Void cado6Dlg::OnFind()
- •0L,adSearchForward,bb);
- •Void cado6Dlg::OnFilter()
- •Void cado6Dlg::OnVozvrat()
- •10.11.5. Переходи по записах
- •Void cado6Dlg::OnButtonFirst()
- •Void cado6Dlg::OnButtonLast()
- •Void cado6Dlg::OnButtonLeft()
- •Void cado6Dlg::OnButtonRight()
- •Void cado6Dlg::OnButtonRecno()
- •Void cado6Dlg::OnButtonPgup()
- •Void cado6Dlg::OnButtonPgdn()
- •Void cado6Dlg::OnButtonBookmark()
- •10.11.6. Запис даних до xml-файлу
- •Void cAdo6Dlg::OnButtonSave()
- •10.11.7. Кнопки, призначені тільки для роботи з otl_tab
- •Void cado6Dlg::OnZapis_Add1()
- •Void cado6Dlg::OnZapis_Add2()
- •Void cado6Dlg::OnZapis_Update1()
- •Void cado6Dlg::OnZapis_Update2()
- •Void cado6Dlg::OnFormir_bd()
- •Void cAdo6Dlg::OnValues_Fields()
- •10.12. Використання у якості джерела даних електронної таблиці Excel
- •Контрольні питання
- •Завдання
- •Розділ 11. Програмування для інтернет
- •11.1. Створення броузера
- •11.3. Використання протоколу http
- •If ((pInternetSession)
- •11.4. Використання протоколу ftp
- •Контрольні питання
- •Розділ 12. Створення елементів activex
- •12.1. Створення елементів ActiveX
- •Invalidate();
- •12.2. Тестування елемента ActiveX
- •12.4. Створення елемента ActiveX на базі стандартних елементів
- •12.5. Відображення елементів ActiveX
- •Контрольні питання
- •Розділ 13. Налагодження програм
- •Int data[5];
- •Invalidate();
- •13.3. Установка точки переривання
- •13.2. Покрокове виконання програми
- •13.4. Перевірка значень змінних під час виконання програми
- •Контрольні питання
- •Список літератури
- •Додатки
13.2. Покрокове виконання програми
Під час налагодження програм на Visual C++ часто зустрічаються рядки з викликами різних методів (наприклад, PerformWork(data)). Якщо продовжити покрокове виконання програми з такого рядка, то ви перейдете до коду виклику методу (наприклад, PerformWork(), який може бути досить довгим). Це означає, що для повернення до відладжуваного фрагменту вам доведеться пройти через весь код методу.
У цьому немає нічого поганого, якщо ви хочете налагодити викликаємий метод, ... а якщо не хочете? (Наприклад, якщо викликаний стандартний метод Visual C++?) У цьому випадку ви можете пропустити код методу, користуючись клавішею F10 для послідовного виконання своєї програми.
Якщо ви захочете пройти через код викликаного методу, користуйтеся клавішею F11.
Якщо ви опинитеся всередині викликаного методу або іншого блоку, який не хочете налагоджувати, можете вийти за його межі, натиснувши клавіші Shift+F11.
Існує й інша можливість – встановити курсор в деякій точці програми за поточним виконуваним рядком і натиснути клавіші Ctrl+F10, що призведе до виконання коду до рядка з курсором.
У нашому прикладі для покрокового виконання програми буде використовуватися клавіша F10. Натисніть F10 один раз, щоб перейти до наступного рядка програми:
void CBuggyView::OnCalculateCalculateaverage()
{
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
float Sum;
float Average;
for(int loop_index = 1; loop_index < 5; loop_index++)
{
Sum += pDoc->data[loop_index];
}
Average = Sum / (float) 5.0;
OutputString.Format(
"Среднее арифметическое пяти чисел равно: %.3f",
Average);
Invalidate();
}
Поточним стає наступний рядок програми (рис. 13.4). Саме в ньому відбувається підсумовування чисел для отримання накопичуваної суми в змінній Sum.
Рис. 13.4. Покрокове виконання програми
Щоб виконати поточний рядок, оновити значення суми і перейти до наступного рядку, ще раз натисніть клавішу F10 (рис. 13.5). До змінної Sum додано перше ціле число, а ми можемо перевірити її значення і переконатися, що все йде нормально.
Рис. 13.5. Перегляд значень змінних
13.4. Перевірка значень змінних під час виконання програми
Щоб дізнатися значення змінної Sum (в якій повинно зберігатися перше ціле число, 1), затримайте над нею курсор миші (див. рис. 13.5). Поруч з ім'ям змінної на екрані з'являється підказка зі значенням 1.07374е+008 або 1.07374x108 – це дещо більше, ніж ми очікували. Схоже, ми знайшли проблему.
Вікна Auto і Locals
Крім екранної підказки, змінна Sum зі своїм значенням відображається у вікні Auto, розташованому в лівому нижньому кутку на рис. 13.5 (зверніть увагу на обрану вкладку Auto). У цьому вікні наведені значення останніх змінних, з якими працював Visual C++; серед них є й наша змінна Sum. Крім того, ви можете клацнути на вкладці Locals і перейти до однойменного вікна, що містить значення всіх змінних (включаючи Sum), визначених у поточному методі або фрагменті коду.
Підказка. Якщо ви хочете відстежувати значення конкретної змінної під час всього виконання програми, введіть її ім'я у вікні Watch, розташованому в правому нижньому кутку вікна Visual C++. Крім того, потрібну змінну можна просто перетягнути мишею у вікно Watch.
Перегляд програми показує, що ми забули обнулити початкове значення суми. Давайте зробимо це. Перш за все завершіть сеанс налагодження командою Debug → Stop Debugging, потім відредагуйте метод і надайте змінній Sum початкове значення 0:
void CBuggyView::OnCalculateCalculateaverage()
{
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
float Sum = 0;
float Average;
for(int loop_index = 1; loop_index < 5; loop_index++)
{
Sum += pDoc->data[loop_index];
}
Average = Sum / (float) 5.0;
OutputString.Format("Среднее арифметическое пяти чисел равно: %.3f",
Average);
Invalidate();
}
Помилка з ініціалізацією виправлена. Знову запустіть програму (рис. 13.6).
Рис. 13.6. Програма buggy: друга спроба
Тепер програма повідомляє, що середнє арифметичне перших п'яти цілих чисел дорівнює 2.800. Звичайно, це набагато ближче до очікуваного значенням 3.000, але всетаки не воно. Пора повертатися до відладчику.
Знову почніть налагодження командою Build → Start Debug → Go і виконайте програму до точки переривання. Увійдіть в цикл for клавішею F10 (рис. 13.7). Затримайте курсор миші над змінною Sum, щоб переконатися, що її значення дійсно дорівнює 0.
Зі змінною Sum все нормально; давайте перевіримо значення, яке до неї додається, pDoc->data[loop_index]:
void CBuggyView::OnCalculateCalculateaverage()
{
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
float Sum = 0;
float Average;
for(int loop_index = 1; loop_index < 5; loop_index++)
{
Sum += pDoc->data[loop_index];
}
Average = Sum / (float) 5.0;
OutputString.Format(
"Среднее арифметическое пяти чисел равно: %.3f",
Average);
Invalidate();
}
Рис. 13.7. Налагодження циклу for у програмі buggy
Ми не зможемо дізнатися значення виразу pDoc-> data[loop_index], затримуючи на ньому курсор миші (незрозуміло, що саме нас цікавить – тільки pDoc або весь вираз?), але він присутній у вікні Auto у лівому нижньому кутку. Ми бачимо, що до суми додається число 2 (а не 1, як очікувалося).
Перегляд коду показує, що початкове значення змінної циклу дорівнює 1, а не 0, як належить. Зупиніть налагодження і виправте помилку:
void CBuggyView::OnCalculateCalculateaverage()
{
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
float Sum = 0;
float Average;
for(int loop_index = 0; loop_index < 5; loop_index++)
{
Sum += pDoc->data[loop_index];
}
Average = Sum / (float) 5.0;
OutputString.Format(
"Среднее арифметическое пяти чисел равно: %.3f",
Average);
Invalidate();
}
Підказка. Щоб дізнатися значення того чи іншого виразу під час виконання програми, можна виконати команду Debug → QuickWatch та ввести вираз у діалоговому вікні QuickWatch. Visual C++ вирахує його значення.
Запустіть програму (рис. 13.8). Ми домоглися бажаного результату – середнє арифметичне чисел 1-5 дорівнює 3. Вбудовані засоби налагодження Visual C++ допомогли ліквідувати помилки.
Щоб видалити з програми точку переривання, встановіть курсор на рядку з нею і натисніть клавішу F9.
Підказка. Закінчивши налагодження, слід видалити налагоджувальну інформацію з виконуваного файлу. Виконайте команду Build → Set Active Configuration та виберіть зі списку, рядок buggy - Win32 Release (за замовчуванням в програми на Visual C++ включається великий обсяг інформації, використовуваної відладчиком).
Рис. 13.8. Програма buggy після завершення налагодження
Виправлений варіант програми міститься у файлах buggyDoc.h/buggyDoc.cpp і buggyView.h/buggyView.cpp.
buggyDoc.h і buggyDoc.cpp
// buggyDoc.h : інтерфейс класа CBuggyDoc
//
/////////////////////////////////////////////////////////////////////////
#if !defined(AFX_BUGGYDOC_H__3236D78B_9951_11D0_8860_444553540000__INCLUDED_)
#define AFX_BUGGYDOC_H__3236D78B_9951_11D0_8860_444553540000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
class CBuggyDoc : public CDocument
{
protected: // Создание только при сериализации
CBuggyDoc();
DECLARE_DYNCREATE(CBuggyDoc)
// Атрибуты
public:
// Операції
public:
int data[5];
// Перевантаження
// Перевантажені віртуальні функції,
// сформовані ClassWizard-ом.
//{{AFX_VIRTUAL(CBuggyDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Реалізація
public:
virtual ~CBuggyDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Сформовані функції карти повідомлень
protected:
//{{AFX_MSG(CBuggyDoc)
// УВАГА!! Тут ClassWizard буде додавати і
// видаляти функції-члени.
// не редагуйте текст у цих блоках!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ буде вставляти додаткові
// оголошення перед попереднім рядком.
#endif
// !defined(AFX_BUGGYDOC_H__3236D78B_9951_
// 11D0_8860_444553540000__INCLUDED_)
// buggyDoc.cpp : реалізація класа CBuggyDoc
//
#include "stdafx.h"
#include "buggy.h"
#include "buggyDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////
// CBuggyDoc
IMPLEMENT_DYNCREATE(CBuggyDoc, CDocument)
BEGIN_MESSAGE_MAP(CBuggyDoc, CDocument)
//{{AFX_MSG_MAP(CBuggyDoc)
// УВАГА!! Тут ClassWizard буде додавати і
// видаляти функції-члени.
// не редагуйте текст у цих блоках!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////
// Создание/уничтожение CBuggyDoc
CBuggyDoc::CBuggyDoc()
{
// ЗРОБИТИ: додайте код конструктора
data[0] = 1;
data[1] = 2;
data[2] = 3;
data[3] = 4;
data[4] = 5;
}
CBuggyDoc:: *"CBuggyDoc()
{
}
BOOL CBuggyDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// ЗРОБИТИ: додайте код для повторної ініциалізації документа
// (документи SDI будуть використовувати його повторно)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// Сериалізація в CBuggyDoc
void CBuggyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// ЗРОБИТИ: додайте код збереження даних
}
else
{
// ЗРОБИТИ: додайте код завантаження даних
}
}
/////////////////////////////////////////////////////////////////////////
// Діагностика в CBuggyDoc
#ifdef _DEBUG
void CBuggyDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CBuggyDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////
// Команди CBuggyDoc
buggyView.h і buggyView.cpp
// buggyView.h : інтерфейс класа CBuggyView
//
/////////////////////////////////////////////////////////////////////////
#if !defined(AFX_BUGGYVIEW_H__3236D78D_9951_11D0_8860_444553540000__INCLUDED_)
#define AFX_BUGGYVIEW_H__3236D78D_9951_11D0_8860_444553540000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
class CBuggyView : public CView
{
protected: // создание только при сериализации
CBuggyView();
DECLARE_DYNCREATE(CBuggyView)
// Атрибуты
public:
CBuggyDoc* GetDocument();
// Операції
public:
// Перевантаження
// Перевантажені віртуальні функції,
// сформовані ClassWizard-ом.
//{{AFX_VIRTUAL(CBuggyView)
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
// Реалізація
public:
virtual ~CBuggyView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
CString OutputString;
// Сформовані функції карти повідомлень
protected:
//{{AFX_MSG(CBuggyView)
afx_msg void OnCalculateCalculateaverage();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // отладочная версия в buggyView.cpp
inline CBuggyDoc* CBuggyView::GetDocument()
{ return (CBuggyDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ буде вставляти додаткові
// оголошення перед попереднім рядком.
#endif
// !defined(AFX_BUGGYVIEW_H__3236D78D_9951_
// 11D0_8860_444553540000__INCLUDED_)
// buggyView.cpp : реалізація класа CBuggyView
//
#include "stdafx.h"
#include "buggy.h"
#include "buggyDoc.h"
#include "buggyView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////
// CBuggyView
IMPLEMENT_DYNCREATE(CBuggyView, CView)
BEGIN_MESSAGE_MAP(CBuggyView, CView)
//{{AFX_MSG_MAP(CBuggyView)
ON_COMMAND(ID_CALCULATE_CALCULATEAVERAGE, OnCalculateCalculateaverage)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////
// Створення/видалення CBuggyView
CBuggyView::CBuggyView()
{
// ЗРОБИТИ: додайте код конструктора
OutputString = "Выполните команду Calculate/Calculate Average";
}
CBuggyView::~CBuggyView()
{
}
BOOL CBuggyView::PreCreateWindow(CREATESTRUCT& cs)
{
// ЗРОБИТИ: Змініть клас вікна або його стилі,
// редагуючи вміст CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////
// Малювання в CBuggyView
void CBuggyView::OnDraw(CDC* pDC)
{
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(0, 0, OutputString);
// ЗРОБИТИ: додайте код для відображення даних
}
/////////////////////////////////////////////////////////////////////////
// Друк в CBuggyView
BOOL CBuggyView::OnPreparePrinting(CPrintInfo* pInfo)
{
// Стандартна підготовка
return DoPreparePrinting(pInfo);
}
void CBuggyView::OnBeginPrinting(CDC* /*pDC*/,
CPrintInfo* /*pInfo*/)
{
// ЗРОБИТИ: додайте додаткову ініціалізацію перед друком
}
void CBuggyView::OnEndPrinting(CDC* /*pDC*/,
CPrintInfo* /*pInfo*/)
{
// ЗРОБИТИ: додайте код для "зборки сміття" після друку
}
/////////////////////////////////////////////////////////////////////////
// Діагностика в CBuggyView
#ifdef _DEBUG
void CBuggyView::AssertValid() const
{
CView::AssertValid();
}
void CBuggyView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CBuggyDoc* CBuggyView::GetDocument() // не-відладочна версія
// є вбудованою
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBuggyDoc)));
return (CBuggyDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////
// Обробники повідомлень CBuggyView
void CBuggyView::OnCalculateCalculateaverage()
{
// ЗРОБИТИ: додайте код обробки команди
CBuggyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
float Sum = 0;
float Average;
for(int loop_index = 0; loop_index < 5; loop_index++)
{
Sum += pDoc->data[loop_index];
}
Average = Sum / (float) 5.0;
OutputString.Format("Среднее арифметическое пяти чисел равно: %.3f",
Average);
Invalidate();
}
На цьому завершується наше знайомство з відладчиком Visual C++. Залишається лише використовувати отримані знання на практиці.