Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Разработка Windows - приложений в среде Borland. Учебное пособие
.pdf
просы, связанные с разработкой классов и механизмами наследования, например [2,4,5], а также почитать [6,8], где рассматриваются
классы библиотек OWL и MFC. Библиотеки библиотек OWL и MFC
во многом аналогичны и являются, по сути, надстройкой над WinApi
[9,10]. В папке BC5\BIN\EXAMPLES\EXAMPLES есть примеры
различных проектов, изучив которые можно довольно многое для
себя прояснить.
Итак, посмотрим, что же находится в
workapp.cpp, workapp.h, wrkdlgcl.cpp, wrkdlgcl.h, workapp.rc и
workapp.rh. Начнем с заголовочного файла workapp.h. В нем приводится описание классов главного окна приложения TSDIDecFrame
(фрейма) и класса приложения (директивы препроцессора и комментарии опустим):
class TSDIDecFrame : public TDecoratedFrame {
public:
TSDIDecFrame(TWindow* parent, const char far* title,
TWindow* clientWnd, bool trackMenuSelection
= false, TModule* module = 0);
~TSDIDecFrame();
};
Видно, что наш класс TSDIDecFrame фрейма окна является на-
следником класса OWL TDecoratedFrame – окно с панелью инструментов. В классе определен конструктор и
реть файл workapp.cpp, мы увидим, что деструктор пуст, а в конструкторе помимо заголовка окна выбирается в качестве клиентского
окна окно нашего диалога TWorkDlgClient, описанное в файлах
wrkdlgcl.h и wrkdlgcl.cpp.
Далее описывается наш класс приложения TWorkApp:
class TWorkApp : public TApplication {…};
Класс TWorkApp является наследником базового класса OWL –
TApplication. Здесь также декларируются конструктор и деструктор,
но, кроме того,
щая за организацию главного окна приложения. Собственно, это и
есть необходимый минимум. Объявленный в классе метод CmHelpAbout() предназначен для вывода информации о программе при вы-
перегружается функция InitMainWindow, отвечаю-
21
файлах нашего проекта
деструктор. Если посмот-

боре соответствующего пункта меню. Однако меню у нас пока не
подключено, а сам метод пуст. Строка DECLARE_RESPONSE_TABLE(TWorkApp) – декларирует таблицу откликов, связывающую идентификаторы (например, пунктов меню или командных
кнопок) с нужными функциями обработчиками, являющимися методами класса.
И, наконец, в этот файл мы поместили описание нашей струк-
туры staff.
Теперь кратко
cpp. В начале приводится таблица откликов:
DEFINE_RESPONSE_TABLE1(TWorkApp, TApplication)
//{{TWorkAppRSP_TBL_BEGIN}}
EV_COMMAND(CM_HELPABOUT, CmHelpAbout),
//{{TWorkAppRSP_TBL_END}}
END_RESPONSE_TABLE;
В данном случае в таблице откликов макрос EV_COMMAND
связывает идентификатор команды меню CM_HELPABOUT с функцией отклика (функция обработчик) CmHelpAbout, объявленной в
нашем приложении – в классе TWorkApp. Как уже говорилось выше,
меню у нас пока все равно не подключено.
Далее в файле определяются методы
TWorkApp, объявленные в файле workapp.h. Обратите внимание на
инструкции:
frame->SetIcon(this, IDI_SDIAPPLICATION);
frame->SetIconSm(this, IDI_SDIAPPLICATION);
в коде функции InitMainWindow. Переменная frame является указателем на главное окно приложения, а методы SetIconSm и SetIcon
устанавливают иконки (идентификатор IDI_SDIAPPLICA-TION –
стандартная иконка) для главного окна и систем навигации
WINDOWS (проводник) соответственно. Именно в это место можно
добавить команды
жения окна, подключить акселераторы («горячие клавиши») и т.п.
Данные вопросы подробно обсуждаются в третьей главе. Например,
чтобы окно появлялось в левом верхнем углу экрана, нужно добавить операторы:
рассмотрим реализацию классов – файл workapp.-
классов TSDIDecFrame и
подключения меню, изменения размеров и поло-
22

frame-> Attr.X = 0;
frame-> Attr.Y = 0;
В конце файла находим код:
int OwlMain(int , char* [])
{
TWorkApp app;
return app.Run();
}
При использовании OWL точкой входа является функция Owl-
Main (аналогично main в консольном приложении). В функции соз-
дается экземпляр нашего приложения и вызывается метод Run, который и осуществляет все необходимые действия, в частности, вызов InitMainWindow. Параметры командной строки функции OwlMain аналогичны параметрам функции
Теперь рассмотрим содержимое заголовочного файла wrkdlgcl.h.,
опять же опуская директивы препроцессора и комментарии. В самом
начале находится объявление структуры TWork-DlgClientXfer. Переменная этого типа декларируется в модуле wrkdlgcl.cpp и предназначена для обмена данными с элементами диалогового окна (буфер
передачи). Подробнее организация и использование буфера обмена
обсуждается в третьей главе в разделе
мена (передачи)». Затем в файле wrkdlgcl.h приводится описание
класса окна нашего диалога TWorkDlgClient:
class TWorkDlgClient : public TDialog {…};
являющегося наследником класса OWL TDialog. Помимо конструктора и деструктора, здесь эксперт классов (ClassExpert) добавил поля, являющиеся указателями на те элементы диалога, которым нами
были присвоены имена (созданы объектные переменные); далее
объявлены методы, которые будут вызваны
диалога. В конце файла декларируется таблица откликов данного
класса.
В начале модуля wrkdlgcl.cpp определяется соответствующая
таблица откликов, в которой для событий BN_CLICKED (щелчок
мышкой) идентификаторы кнопок «добавить», "<<" и ">>" связыва-
main.
«Обмен данными. Буфер об-
при нажатии кнопок
23

ются с заданными функциями обработчиками. Далее в файле определяются методы класса TWorkDlgClient, объявленные в файле
wrkdlgcl.h. Обратите внимание на инструкцию:
SetTransferBuffer(&TWorkDlgClientData);
в конструкторе класса TWorkDlgClient. Здесь как раз и устанавливается в качестве буфера передачи нашего диалога переменная TWorkDlgClientData типа TWorkDlgClientXfer, описанного в заголовочном
файле wrkdlgcl.h. Остальные методы класса подробно разбирались
выше.
Остались два модуля
ресурсов workapp.rc и workapp.rh. Эти два
модуля состоят из 500 строк, то есть в них содержится свыше половины кода. В заголовочном файле workapp.rh содержатся директивы
препроцессора #define, определяющие подстановки, то есть замены
имен идентификаторов на числовые значения. В файле workapp.rc
описываются ресурсы, в том числе и те, которых мы не создавали и
пока не собираемся
использовать – меню, акселераторы, таблицы
строк, наш диалог и т.д. Большую часть этого добра создал AppExpert, так сказать про запас. Например, заготовка меню, находя-
щаяся здесь, конечно, вполне годится, но, на мой взгляд, проще и
понятнее создать ресурс нового меню самому с самого начала, как
это будет сделано в третьей главе.
С другой стороны, ничто не мешает нам отредактировать эти
два модуля, убрав из них все «лишнее». Я бы настоятельно посоветовал, прежде чем редактировать эти файлы, хотя бы скопировать их
в другую папку от греха подальше. После чего нужно закрыть редактор ресурсов и отредактировать файл workapp.rc как текст – выбрать в
окне проекта файл workapp.rc, вызвать его контекстное меню
и выбрать пункт → View → Text Edit, а после редактирования закрыть его и сохранить. Попробуйте оставить строчки:
#if !defined(WORKSHOP_INVOKED)
# include <windows.h>
#endif
#include "workapp.rh"
// Application ICON
//
IDI_SDIAPPLICATION ICON "applsdi.ico"
24

// Client Dialog
//
IDD_CLIENT DIALOG 6, 15, 243, 130
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION "Dialog Client"
FONT 8, "MS Sans Serif"
{
CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE |
WS_TABSTOP, 184, 108, 50, 14
CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD |
WS_VISIBLE | WS_TABSTOP, 184, 92, 50, 14
CONTROL "имя", IDC_STATICTEXT1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12,
11, 36, 11
CONTROL "", IDC_EDIT1, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_TABSTOP, 56, 9, 76, 13
CONTROL "должность", IDC_STATICTEXT2, "static", SS_LEFT | WS_CHILD |
WS_VISIBLE, 12, 31, 40, 13
CONTROL "", IDC_EDIT2, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_TABSTOP, 56, 28, 76, 13
CONTROL "оклад", IDC_STATICTEXT3, "static", SS_LEFT | WS_CHILD | WS_VISIBLE,
12, 49, 40, 13
CONTROL "", IDC_EDIT3, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_TABSTOP, 56, 47, 76, 13
CONTROL "0", IDC_STATICTEXT4, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 88,
103, 16, 12
CONTROL "добавить", IDC_BUTTON1, "button", BS_PUSHBUTTON | BS_CENTER |
WS_CHILD | WS_VISIBLE | WS_TABSTOP, 184, 4, 52, 13
CONTROL "<<", IDC_BUTTON2, "button", BS_PUSHBUTTON | BS_CENTER |
WS_CHILD | WS_VISIBLE | WS_TABSTOP, 64, 99, 16, 17
CONTROL ">>", IDC_BUTTON3, "button", BS_PUSHBUTTON | BS_CENTER |
WS_CHILD | WS_VISIBLE | WS_TABSTOP, 104, 99, 16, 17
}
Здесь оставлен ресурс иконки и нашего диалога со всеми эле-
ментами управления. Затем можно отредактировать модуль work-
app.rh, оставив директивы:
//
// Application specific definitions:
#define IDI_SDIAPPLICATION 1001 // Application icon
//
// Help menu commands.
#define CM_HELPABOUT 2009
//
// Client Dialog
#define IDD_CLIENT 2000
25

#define IDC_STATICTEXT1 101
#define IDC_EDIT1102
#define IDC_STATICTEXT2 103
#define IDC_EDIT2104
#define IDC_STATICTEXT3 105
#define IDC_EDIT3106
#define IDC_STATICTEXT4 107
#define IDC_BUTTON1 108
#define IDC_BUTTON2 109
#define IDC_BUTTON3 110
Идентификатор CM_HELPABOUT оставлен, чтобы не пришлось
редактировать файл workapp.cpp. Все оставшиеся директивы теперь
должны быть понятны. Размер файлов уменьшен в10 раз!
Попробуйте запустить проект. Возможно, все работает, а если
нет – восстановите предусмотрительно скопированные Вами файлы
ресурсов.
Д
ОРАБОТКА ПРОЕКТА. ДОПОЛНИТЕЛЬНЫЕ ЭЛЕМЕНТЫ
ИНТЕРФЕЙСА
Созданное нами приложение недостаточно функционально.
Поддерживаются только операция ввода новой записи и просмотр
записей. Не реализованы функции удаления записей, работы с файлами, сортировки, поиска и т.д. Однако, прежде всего, стоит обратить внимание на тот факт, что самой востребованной является задача вывода в окно нужной записи. Даже
в нашем проекте, по сути,
только заготовке программы, соответствующие операции уже дублируются в функциях-обработчиках BNClickedPrev и BNClicked-
Next. Поэтому желательно реализовать задачу отображения записи в
виде отдельной функции – методе класса диалога TWorkDlgClient.
Для этого добавьте в интерфейс соответствующего класса в мо-
дуле wrkdlgcl.h, например, после строчки:
void BNClickedNext();
объявление нового метода:
void ShowRecord();
26

а в конец файла wrkdlgcl.cpp описание этого метода:
void TWorkDlgClient:: ShowRecord ()
{
char buff[20];
EditName -> SetText(crew[iCur].name);
EditJob -> SetText(crew[iCur].job);
wsprintf(buff,"%i",crew[iCur].pay);
EditPay -> SetText(buff);
wsprintf(buff,"%i",iCur+1);
StaticNum -> SetText(buff);
}
Теперь можно упростить созданные ранее функции-обработ-
чики BNClickedPrev и BNClickedNext:
void TWorkDlgClient:: BNClickedPrev()
{
// INSERT>> Your code here.
if(iCur <= 0) return;
iCur--;
ShowRecord ();
}
void TWorkDlgClient:: BNClickedNext ()
{
// INSERT>> Your code here.
if(iCur >= iMax-1) return;
iCur++;
ShowRecord ();
}
Замечание: Вообще говоря, можно обойтись без проверки существования нужной записи в этих функциях, если воспользоваться
возможностью блокировки соответствующих кнопок. Подобные во
просы рассматриваются в четвертой главе в разделе «Изменение
свойств элементов из программы».
-
27

Рассмотрение деталей реализации будет нагляднее, если использовать в качестве базового проекта относительно простую программу. Поэтому стоит зафиксировать полученные к данному моменту результаты и сохранить копию проекта в отдельной папке,
назвав её, например, «Заготовка». Напоминаю, что при переносе
проекта в другую папку (на другой компьютер) следует скопировать
рассмотренные выше 10 файлов: Work.ide, Work.apx, WorkApp.def,
WorkApp.cpp, WorkApp.h, WrkDlgCl.cpp, WrkDlgCl.h, WorkApp.rc,
WorkApp.rh и applsdi.ico. Не забудьте, что если проект не называется
work, имена файлов будут другими.
Следующий момент, на котором стоит остановиться, связан с
тем фактом, что некоторые вводимые пользователем данные должны быть выбраны из заранее известного набора значений (перечисляемый тип). Например, пол может быть только мужской или женский, а должности сотрудников соответствовать штатному расписанию и т.п. Для того чтобы избежать возможных
ошибок и ограничить фантазию пользователя, удобно воспользоваться такими элементами управления, как список или комбинированный список.
Выберите на панели инструментов элемент Combo Box
(комбинированный список) и поместите его в окне диалога
справа от поля, предназначенного для задания должности:
Сделайте недоступным редактируемое поле EditJob, предназна-
ченное для ввода должности: (Properties → вкладка General → фла-
28

жок Disabled). Теперь это поле доступно только из программы. Выберите тип комбинированного списка – Dropdown List (Properties →
вкладка ComboBox). Это ограничит действия пользователя только
возможным выбором из списка. В разделе Vertical Scroll задайте –
Auto (вертикальная линейка прокрутки появляется по мере необходимости). Через ClassExpert задайте программное имя списка
(ClassExpert → идентификатор списка → Add instance variable → и
введите
ошибка:
ный ClassExpert код. Откройте файл wrkdlgcl.h, найдите в начале
файла в структуре TWorkDlgClientXfer (это буфер обмена данными) строчку:
и перенесите ее, например, в начало структуры, перед инструкцией
TWorkDlgClient (в начале файла) переместите строчку
имя ComboJob).
Замечание: При попытке выполнить приложение возможна
Чтобы устранить ее достаточно отредактировать сгенерирован-
TComboBoxData ComboJob;
char EditName[ 255 ];
Далее откройте файл wrkdlgcl.cpp и в конструкторе класса
ComboJob = new TComboBox(this, IDC_COMBOBOX1, 1);
29

в начало, перед инструкцией (порядок создания объектов в конструкторе и порядок соответствующих полей в буфере обмена должны
совпадать):
EditName = new TEdit(this, IDC_EDIT1, 255);
Теперь нужно заполнить наш список должностей. Выберите
список в редакторе ресурсов, вызовите ClassExpert, в панели событий Events раскройте список виртуальных методов → Virtual Func-
tions, выберите функцию SetupWindow и перегрузите её – контекстное меню → Add handler.
Обратите внимание, что при перегрузке методов имя функции
задавать не нужно – оно предопределено – SetupWindow. В нижней
панели ClassExpert появится заготовка нужного метода:
void TWorkDlgClient::SetupWindow()
{
TDialog::SetupWindow();
// INSERT>> Your code here.
}
После комментария // INSERT>> Your code here введите инструкции:
30
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
