Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Разработка Windows - приложений в среде Borland. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
просы, связанные с разработкой классов и механизмами наследова­ния, например [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. Здесь также декларируются конструктор и деструктор,
но, кроме того, щая за организацию главного окна приложения. Собственно, это и есть необходимый минимум. Объявленный в классе метод CmHelp­About() предназначен для вывода информации о программе при вы-
перегружается функция 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. Параметры командной строки функции Owl­Main аналогичны параметрам функции
Теперь рассмотрим содержимое заголовочного файла 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. Здесь как раз и устанавлива­ется в качестве буфера передачи нашего диалога переменная TWork­DlgClientData типа TWorkDlgClientXfer, описанного в заголовочном файле wrkdlgcl.h. Остальные методы класса подробно разбирались выше.
Остались два модуля
ресурсов workapp.rc и workapp.rh. Эти два модуля состоят из 500 строк, то есть в них содержится свыше поло­вины кода. В заголовочном файле workapp.rh содержатся директивы препроцессора #define, определяющие подстановки, то есть замены имен идентификаторов на числовые значения. В файле workapp.rc описываются ресурсы, в том числе и те, которых мы не создавали и пока не собираемся
использовать – меню, акселераторы, таблицы
строк, наш диалог и т.д. Большую часть этого добра создал App­Expert, так сказать про запас. Например, заготовка меню, находя-
щаяся здесь, конечно, вполне годится, но, на мой взгляд, проще и понятнее создать ресурс нового меню самому с самого начала, как это будет сделано в третьей главе.
С другой стороны, ничто не мешает нам отредактировать эти два модуля, убрав из них все «лишнее». Я бы настоятельно посове­товал, прежде чем редактировать эти файлы, хотя бы скопировать их в другую папку от греха подальше. После чего нужно закрыть ре­дактор ресурсов и отредактировать файл 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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]