
1. Об'єкти для реальних полів
Для зручності роботи з конкретним полем можна створити об'єкт-поле класу Tfield або одного з його спеціалізованих нащадків - Tstringfield. Tintegerfield. Tblobfield і так далі Об'єкт-поле створюється на етапі розробки програми за допомогою редактора полів. Якщо визначений об'єкт-поле, дістати доступ до поля можна по імені цього об'єкту. Редактор полів привласнює об'єктам-нулям імена шляхом зчеплення імені джерела даних і імені поля. даних всі замовчувані поля або тільки їх частина, можна за допомогою наступного гнойства НД: property Defaultfields: Boolean;
Значення True указує, що використовуються поля, задані за умовчанням; False - що використовуються поля, визначені за допомогою редактора полів. Якщо хоч би для одного поля НД створений об'єкт-поле, всі поля НД, для яких такі об'єкти не визначені, стають недоступними До «неіснуючих» полів звернутися виданому НЛ не можна. Знов повернувся до використання всіх полів НД можна тільки на етапі розробки програми, видаливши в редакторові полів всі визначені раніше об'єкти або додавши з його допомогою об'єкти для тих, що не дістають полів.
Для виклику редактора полів потрібно двічі клацнути на компоненті-наборі або клацнути на нім правою кнопкою миші і вибрати в контекстом меню команду Fields Editor. Заздалегідь НД має бути пов'язаний з потрібною таблицею БД: у Table мають бути визначені властивості Databasename і Table Name. у Tquery - Databasename і SQL(to є ця властивість повинна містити текст SQL-запроса, которийсоздаст НД). Btstoredproc - Datadasename і Storedprocname.
Щоб додати об'єкти-поля, клацніть у вікні редактора правою кнопкою миші і виберіть в контекстному меню команду Add Fields. У списку вікна, що відкрилося, Add Fields будуть виділені поля, для яких ще не створені об'єкти (мал. 17). Ви можете вибрати будь-яку комбінацію полів в списку і клацнути на кнопці ОК - для виділених полів будуть створені об'єкти, а вікно редактора міститиме список цих полів. Якщо потрібно створити об'єкти-поля для всіх полів, виберіть команду Add All Fields і контекстному меню редактор. Щоб видалити визначення якого-небудь об'єкту, потрібно виділити відповідне поле у вікні редактора і натиснути клавішу Delete. Якщо потрібно видалити оголошення всіх бъектов-полей, виберіть команду Select All в контекстному меню і після цього натисніть клавішу Delete.
Малюнок 17- Роботи з редактором полів
Щоб змінити властивості конкретного об'єкту-поля або написати обробник для якої-небудь пов'язаної з ним події, необхідно в редакторові полів виділити потрібне поле і, використовуючи інспектор об'єктів, встановити значення у властивість або визначити обробник події.
1. Об'єкти для підстановлювальних полів
Підстановлювальне (lookup) поле відрізняється від звичайного об'єкту-поля тим, що містить дані з іншого НД. Неодмінною умовою створення підстановлювального поля є виконання вимоги реляційного зв'язку головного ІД з таблицею підстановки: у головному ІД кожне значення якого-небудь поля повинне посилатися на один із записів в таблиці підстановки, причому по полю зв'язку в цій таблиці має бути створений унікальний індекс або первинний ключ.
Для створення підстановлювального поля потрібно викликати контекстне меню редактора полів (клацнувши в його вікні правою кнопкою миші) і вибрати в нім команду New Field. У вікні додавання нового поля (мал. 18), що з'являється після цього, потрібно ввести ім'я поля в рядку Name і вибрати в списку Турі його тип. Рядок Size заповнюється тільки для текстових полів і полів типу набору байтів. У першому випадку воно показує максимальну довжину в символах рядка, який міститиме поле (за умовчанням цей розмір дорівнює 20 символам, що може бути недостатнім в багатьох практичних випадках, тому слід проаналізувати структуру таблиці підстановки і уточнити розмір того поля, яке і міститиме інформацію для створюваного об'єкту). У другому - довжину поля в байтах. Для всіх інших типів значення в рядку Size ігнорується. Рядок Component у момент введення імені заповнюється автоматично (вона містить ім'я об'єкту-поля). Delphi ігнорує «чуже» введення в рядок Component
.
Малюнок 18-окно створення нового поля
У групі Field type слід встановити перемикач Lookup, потім розкрити список полів головної таблиці Кеу Fields і вибрати в нім посилальне поле. У списку Dataset вибирається підстановлювальний НД. у списку Lookup Keys - індексне поле підстановлювального НД, а в списку Result Field - результуюче поле: саме його значення приєднаються до полів головної таблиці.
1. Об'єкти для обчислюваних полів
Обчислювані поля не входять до складу конкретної таблиці БД, але можуть бути приєднані до НД, пов'язаному з цією таблицею. Вони призначені для відображення даних, які обчислюються в ході виконання програми зазвичай за допомогою значень з інших нулів того ж запису. Після приєднання обчислюваного поля до НД воно стає у всьому подібно до звичайних об'єктів-полів, пов'язаних з реальними полями таблиці БД, за одним виключенням: такі поля не можна редагувати, а при введенні нового запису - поміщати в них яке-небудь значення.
Для створення обчислюваного поля потрібно відкрити вікно New field (див. мал. 2.2) редактора полів і. заповнивши рядки Name, Type і Size, встановити перемикач Calculated і закрити вікно клацанням на кнопці ОК. Заповнення обчислюваних полів здійснюється в обробнику події Oncalcfields набору даних.
Обробник події для обчислення різниці між двома полями:
Ім'я модуля данних->імя обчислюваного об'екта-поля->value= Ім'я модуля данних->імя об'екта-поля1->value- Ім'я модуля данних->імя об'екта-поля2->value
Щоб побачити в сітці стовпець із значеннями нового поля, створіть для нього новий об'єкт-стовпець.
2. Об'єкти для порожніх полів
Якщо у вікні New Field встановити перемикач Data, буде створений об'єкт-поле, що не містить ніяких даних (порожнє поле). Як правило, таке поле створюється для того, щоб в сітці Dbgrid з'явився додатковий порожній стовпець, в якому програма зможе відображати довільні значення (для цього зазвичай використовується обробник події Ongettext об'єкту-поля або події Ondrawcolumncell сітки). На практиці зручніше замість порожніх полів використовувати порожні об'єкти -столбци, створювані безпосередньо в сітці Dbgrid.
3. Перевірка правильності введеного в поле значення
Для контролю за правильністю що вводяться в нулі значенні можна використовувати події Onvalidate або Onsettext об'єкту-поля. Обидві події наступають після зміни значення поля, але до його запам'ятовування в таблиці.
У обробнику Onvalidate у разі виявлення невірного значення програма повинна запобігти його запам'ятовуванню, створивши виняткову ситуацію або звернувшись до глобальної процедури Abort. Наприклад, можна написати такий обробник;
if (Ім'я модуля данних->імя обчислюваного об'екта-поля->value <0 ) {
Showmessage(« Сума не може Бути негативною!»);
Abort ();}
Проте слід врахувати, що, відмовившись від запам'ятовування невірного значення в таблиці, програма проте залишає ІД в стані редагування. Це означає, що користувач не може покинути це поле до тих пір, поки не введе в нього правильне значення.
Контрольні питання:
1. Реальні, обчислювані, підстановлювальні і порожні поля
2. Звернення до значення поля
3. Перевірка правильності введеного в поле значення
Формування текстового уявлення поля
Практична робота №9 Фільтрація даних
Мета: Вивчити властивості, методи і події компонентів, вивчити типи полів, навчитися звертатися до значення поля, проводити перевірку введеного в поле значення, формувати текстове представлення поля.
Хід роботи:
1. Зміна поточного індексу
Можливість міняти поточний індекс і у такий спосіб впливати на сортування табличних даних є відмітною особливістю компоненту Ттаble. Для зміни поточного індексу призначені властивості Indexname і Index-fieldnames. У перше потрібно помістити ім'я індексу, в друге - список індексних полів, що входить до складу індексу. Ці властивості взаємовиключні: установка значення в одне з них очищає інше. Якщо НД відкритий, зміна поточного індексу приводить до негайної зміни порядку проходження записів в таблиці.
2. Складені індекси
Складеними називаються індекси, побудовані по значеннях два і більш за поля одночасно. Такі індекси широко використовуються на практиці для прискорення пошуку потрібного запису або групи записів методами Findkey і Findnearest (див. нижчий).
Якщо в таблиці побудований індекс тільки по полю Fieldl, а потрібно відшукати записи, що містять потрібні значення в полях Fieldl і Field2, то методи Findkey і Findnearest зможуть встановити курсор лише в початок цілої групи записів, поля Fieldl в яких мають потрібні значення, але відрізняються значеннями решти полів. В цьому випадку для пошуку записів з потрібними значеннями поля Field2 доведеться послідовно проглядати таблицю, починаючи із знайденого запису. Якщо побудований складений індекс по полях Fieldl і Field2, методи Findkey і Findnearest відразу позиціонують курсор на потрібний запис і для таблиць великого розміру можуть істотно скоротити час пошуку. Delphi не має засобів пошуку по індексних виразах. Таким чином, використання таблиць dbase в додатках Delphi менш зручно, чим таблиць Paradox: якщо ви збираєтеся розробити додаток для поки що не створеної БД і вибрали традиційну архітектуру файл-серверних таблиць, обернете на цю увагу; якщо ви створюєте додаток для вже існуючої і наповненої БД, в якій використовуються таблиці dbase, має сенс подумати про передачу тих, що містяться в них даних в таблиці Paradox за допомогою компонентів Tbatchmove.
3. Фільтрація записів
Окрім описуваних нижче засобів для фільтрації даних можуть використовуватися методи Setrange, Applyrange (і супутні ним методи) в компоненті Ттablе Властивість Filter задає критерій фільтрації. В цьому випадку НД буде відфільтрований, як тільки в його властивість Filtered буде поміщене значення True.
Рядок критерію фільтрації можна ввести під час прогону програми або на етапі конструювання форми.Обробник події Onclick кнопки виглядатиме таким чином:
if (Edit1->text!=” ”)
{
Ім'я модуля данних->імя табліци-> Filter= Edit1->text;
Ім'я модуля данних->імя табліци-> Filtered = True
}
За допомогою наступної властивості програміст може визначити додаткові умови фільтрації текстових полів:
Параметри:
focaselnsensitive - фільтрація проводиться без урахування регістра букв;
fonopartialcompare - пошук проводиться на точну відповідність.
4. Вибірка записів
У більшості практично важливих випадків НД повинен містити не всі записи таблиці БД, а лише деяку їх частину, відповідну умовам відбору. Наступний метод показує в НД тільки ті записи, індексні поля яких лежать в діапазоні від Startvalues до Endvalues. Приклад обробника подій для вибірки даних за проміжок часу
Ім'я модуля данних->імя табліци->setrange([Datetimepickerl->date],[Datetimepicker2->date])
Контрольні питання:
1. Фільтрація записів
2. Індексація таблиць
Практична робота №10 Пошук в таблиці
Мета: Вивчити властивості, методи і події компонентів, вивчити типи полів, навчитися звертатися до значення поля, проводити перевірку введеного в поле значення, формувати текстове представлення поля.
Хід роботи:
Під набором даних (НД) розуміється група записів з однієї або декількох таблиць БД, доступна для компонентів-наборів Ttable, Tquery або Tstoredproc. Ці компоненти породжені від загального батьківського класу Tdbdataset, який і розглядається в цьому уроці. Таким чином, всі висловлювані тут відомості в рівній мірі відносяться до будь-якого компоненту-набору.
1. Пошук записів в наборах даних
Метод Locate шукає перший запис, що задовольняє критерію пошуку, і якщо такий запис знайдений, робить її поточною. В цьому випадку як результат повертається значення True. Якщо запис не знайдений, повертається значення False і курсор не міняє свого положення.
function Locate(const Keyfields: String;
const Keyvalues: Variant; Options: Tlocateoptions): Boolean;
Список Keyfields указує поле або декілька полів, по яких ведеться пошук. У разі декількох пошукових полів їх назви розділяються крапкою з комою. Критерії пошуку задаються у варіантному масиві Keyvalues так, що i-e значення в Keyvalues ставиться у відповідність 1-у полю в Keyfields. Параметр Options указує необов'язкові значення режимів пошуку:
locaselnsensitive - пошук ведеться без урахування можливої різниці регістра букв в текстових полях і критерії пошуку;
lopart ialkey - запис прочитався такою, що задовольняє умові пошуку, якщо вона містить частину пошукового контексту; наприклад, що задовольняють контексту «Діа» будуть визнані записи із значеннями в полі пошуку «Діалект», «ДІАЛОГ-МІФІ», «Діасофт» і так далі
Метод Locate проводить пошук по будь-якому полю незалежно від того, входить воно до складу якого-небудь індексу чи ні. Якщо поле (поля) пошуку входять в який-небудь індекс, Locate автоматично використовує його, що істотно збільшує швидкість пошуку.
Приклад обробника подій для вибірки даних за проміжок часу
Tlocateoptions opts;
if (Customer->locate("Custno", Request->queryfields->values["Custno"], opts))
2. Метод Lookup
знаходить запис, що задовольняє умові пошуку, але не робить її поточною, а повертає значення деяких її полів. Незалежно від результату пошуку запису покажчик поточного запису в НД не змінюється. На відміну від методу Locate, метод Lookup здійснює пошук тільки на точну відповідність критерію пошуку значення поля пошуку запису.
int C;
Ansistring A;
Variant V;
V = Table1->lookup("Company;State",
Vararrayof(OPENARRAY(Variant ("Blue Sports","or")))
"Custno;Addr1");
if !(Vartype(V)== varnull)
{
C = V[0];
A = V[1];
Showmessage(Inttostr(C)+ #10 + A);
}
else
Showmessage("Search unsuccessful!");
У параметрі Keyfields указується список полів, по яких необхідно здійснити пошук (якщо задається пошук по декількох полях, сусідні поля в списку розділяються крапкою з комою). Параметр Keyvalues визначає пошукові значення полів, список яких міститься в параметрі Keyfields. У параметрі Resultfields перераховуються поля, значень яких потрібно набути у разі успішного пошуку. Тип результату - Variant або варіантний масив.
Якщо є декілька пошукових полів, кожному полю в списку Keyfields ставиться у відповідність i-e значення в списку Keyvalues. Якщо пошук ведеться по одному полю, його пошукове значення можна указувати як Keyvalues безпосередньо; у разі декількох полів їх необхідно приводити до типу варіантного масиву за допомогою функції перетворення Vararrayof.
Як і в методі Locate, як пошукові поля можна указувати поля що як входять в який-небудь індекс, так і не входять в нього. Якщо в результаті пошуку запис не знайдений, метод Lookup повертає Null
3. Точний пошук
Для точного пошуку (пошуку на точну відповідність) застосовується метод Findkey. Він намагається відшукати в НД запис, у якого індексні поля відповідають значенням, вказаним в параметрі звернення. Якщо такий запис знайдений, метод Findkey повертає True і покажчик поточного запису в НД (курсор НД) встановлюється на цей запис, тобто він делаєтся поточним. Якщо знайдена група записів, що відповідають умові, поточною стає логічно перша з них. Якщо запис не знайдений, курсор НД не переміщається і метод повертає False.
Ім'я модуля данних->імя табліци-> Findkey (Datetimepickerl->date)
4. Неточний пошук
Неточний пошук (пошук на неточну, приблизну відповідність) здійснюється методом Findnearest . Він намагається відшукати в НД запис, у якого індексні поля відповідають вказаним значенням. Якщо такий запис знайдений, покажчик поточного запису в НД переміщається на неї або на наступний за нею запис залежно від значення властивості Keyexclusive. Якщо Keyexclusive = False (за умовчанням), покажчик поточного запису переміщається на неї. Якщо Кеуєхclusive = True, покажчик поточного запису переміщається на наступний запис.
Ім'я модуля данних->імя табліци-> Findnearest (Datetimepickerl->date)
Якщо запис не знайдений, покажчик поточного запису переміщається на найближчий запис з великим значенням індексу.
Контрольні питання:
1. Властивості, методи і події НД
2. Пошук в НД
Практична робота №11 Створення звітів
Мета: навчитися створювати прості і складні звіти
Хід роботи:
Для генерації звітів в C++ Builder використовується сторінка Qreport на палітрі компонентів. Цей набір компонентів дозволяє проектувати звіти на основі таблиць, запитів, списків, текстових файлів, масивів, використовуючи дизайнер форм C++ Builder.
У комплект постачання C++ Builder входять три шаблони звітів, що містяться на сторінці Forms репозітарія об'єктів: Шаблон Опис
Quickreport Mailing Labels Шаблон для створення поштових етикеток
Quickreport List Шаблон для створення простого табличного звіту
Quickreport Master/detail Шаблон для створення звіту Master/detail.
У текст модуля, пов'язаного з формою, створеною на основі цих шаблонів, що згенерував автоматично, включаються у вигляді коментарів інструкції по модифікації отриманої форми.
Створення простого звіту
Звіти Quickreport засновані на наборі горизонтальних смуг (bands). При побудові звіту на форму поміщаються декілька компонентів Qrband (спадкоємець Tpanel) різних типів.
Для створення простого звіту розмістимо на формі наступні компоненти (мал. 1):
Tqrband - компонент, що є частиною звіту, - контейнер для розміщення даних (наприклад, заголовок звіту, верхній або нижній колонтитул сторінки, верхній або нижній колонтитул групи і ін.). Компоненти Tqrband друкуються залежно від їх типу в необхідних місцях звіту, незалежно від їх взаємного розташування на формі. Найбільш часто використовувана властивість цього компоненту &ndash Bandtype, тип "смуги" (колонтитул сторінки або групи, "смуга" даних і ін.). Можливі значення: rbtitle &ndash заголовок звіту, rbpageheader &ndash верхній колонтитул сторінки, rbcolumnheader &ndash верхній колонтитул колонки в багатоколоночному звіті, rbdetail &ndash смуга з табличними даними (повторюється стільки раз, скільки рядків є в наборі даних, авляющемся основою звіту), rbpagefooter &ndash нижній колонтитул сторінки, rboverlay &ndash фон сторінки, друкується в лівому верхньому кутку кожної сторінки, rbgroupheader &ndash заголовок групи, rbsubdetail &ndash "смуга" табличних даних для Detail-таблицы, rbgroupfooter &ndash нижній колонтитул групи, rbsummary &ndash друкується в кінці звіту). Властивості Bandtype створеного нами компоненту привласнимо значення rbtitle
Tquickreport (цей компонент відповідає за перетворення форми на звіт).
Tqrlabel, поміщений на Qrband1 (цей компонент призначений для виведення статичного тексту, і його властивості Caption можна привласнити значення, рівне тексту заголовка майбутнього звіту).
Мал. 1. Створення заголовка звіту
Якщо натиснути праву клавішу миші над компонентом Quickreport1 і вибрати з контекстного меню опцію Preview Report, з'явиться вікно перегляду, в якому буде відображена сторінка звіту із створеним заголовком.
Для модифікації звіту слід змінити властивість Bandtype компоненту Qrband1 на rbdetail і додати на форму компонент Ttable. Далі потрібно встановити його властивість Database рівним імені псевдоніма, наприклад, BCDEMOS, властивість Tablename рівним імені таблиці, наприклад, CUSTOMER.DB, а потім властивість Active рівним true. Після цього потрібно додати на форму компонент Tdatasource і встановити його властивість Dataset рівним імені доданого раніше компоненту Table1, а потім встановити властивість Datasource компоненту Quickreport рівним імені створеного компоненту Datasource1. Після цього можна додати компонент Tqrdbtext на Qrband1(цей компонент призначений для виведення вмісту полів таблиці або запиту, службовця джерелом даних проектованого звіту), встановити властивість Datasource рівним імені створеного раніше компоненту Datasource1 і вибрати потрібне поле як значення властивості Datafield. Якщо є необхідність, можна додати інші компоненти Tqrdbtext і вибрати інші поля таблиці для відображення в звіті (мал. 2).
Мал. 2. Модифікація табличного звіту
Якщо тепер з контекстного меню компоненту Quickreport вибрати опцію Preview Report, можна побачити модифікований табличний звіт.
Тепер спробуємо створити звіт із заголовком звіту і колонтитулами. Для цього потрібно використовувати при створенні звіту декілька різних компонентів Tqrband.
Для створення звіту із заголовком і колонтитулами слід створити нову форму, розмістити чотири компоненти Tqrband на формі (вони отримають за умовчанням імена Qrband2...., Qrband5) і встановити їх властивості Bandtype рівними відповідно rbtitle, rbcolumnheading, rbdetail і rbpagefooter. Далі слід додати на форму компонент Ttable і встановити його властивість Databasename рівним BCDEMOS, властивість Tablename рівним Customer, а потім властивість Active рівним true. Потім потрібно додати на форму компонент Tdatasource і встановити в його властивості Dataset ім'я доданого раніше компоненту Table1 і встановити властивість Datasource компоненту Quickreport рівним імені створеного компоненту Datasource1. Потім слід додати декілька компонентів Tqrlabel як заголовок звіту і стовпців поверх відповідних компонентів Tqrband, привласнивши необхідні значення властивості Caption кожного з них.
Потім слід розмістити три компоненти Qrdbtext на компонент Qrband з властивістю Bandtype, рівним Detailband і встановити їх властивості Datasource рівними Datasource1, а властивості Datafield рівними Company, Phone і Fax. Нарешті, для відображення номера сторінки потрібно помістити компонент Tqrsysdata (цей компонент призначений для виведення відомостей, не залежних від вмісту даних, таких як номер сторінки, дата, час і ін.) на компонент Tqrband з властивістю Bandtype, рівним rbpagefooter і встановити його властивість Data рівним qrcpagenumber, а властивість Text рівним &ldquoСтр. &ldquo
Після цього форма виглядатиме, як на мал. 3.
Можна знову вибрати опцію Preview Report і проглянути зміст нового звіту.
Ріс.3. Звіт із заголовком і колонтитулами
Створення звітів "master-detail"
Перетворимо створений звіт в звіт "master-detail". Для цього слід додати компонент Ttable, встановити його властивість Databasename рівним BCDEMOS, властивість Tablename рівним ORDERS.DB, а потім встановити властивість Active рівним true. Після цього встановимо властивість Mastersource рівним Datasource1. Потім виберемо властивість Masterfields, викликавши діалогову панель для установки зв'язку master/detail (мал. 4 ) і із списку доступних індексів виберемо Custno. Потім виділимо ім'я поля Custno в обох списках полів і натиснемо кнопку Add, а кнопку OK.
Мал. 4. Установка зв'язку master/detail
Додамо на форму компонент Tdatasource, встановивши його властивість Dataset рівним Table2 . Потім додамо до форми новий компонент Tqrband (з ім'ям Qrband6). Після цього додамо компонент Tqrdetaillink, призначений для установки зв'язків між джерелами даних в звітах, і встановимо його властивість Datasource рівним Datasource2. Потім встановимо його властивість Master рівним Quickreport, а властивість Detailband рівним Qrband6. Властивість Bandtype компоненту Qrband6 автоматично набуде значення rbsubdetail.
Нарешті, помістимо два компоненти Tqrdbtext на Qrband6, встановимо їх властивості Datasource рівними Datasource2, а властивості Datafield рівними Orderno і Amountpaid. Зліва від них помістимо два компоненти Tqrlabel з назвами цих полів (мал. 5).
Мал. 5. Форма звіту "master-detail".
Виберемо опцію Preview Report з контекстного меню компоненту Quickreport для попереднього перегляду звіту (ріс.6).
Мал. 6. Звіт "master-detail".
Відзначимо, що якщо компонент Quickreport не пов'язаний з компонентом Datasource, то при друці звіту виводиться тільки одна запис з набору даних, що легко дозволяє друкувати поточний запис.
Відображення графічних і мемо-полей в звітах
Quickreport дозволяє створювати звіти з використанням будь-яких типів даних. Якщо замість визначення Datasource створити обробник події Onneeddata, можна за допомогою Quickreport надрукувати будь-які дані, міняючи властивості компонентів Tqrlabel, що у багатьох випадках використовується для друку довільної інформації (що іноді не має відношення до баз даних).
Quickreport не має власного компоненту для відображення графічних полів. Замість цього можна використовувати стандартні компоненти Timage або Tdbimage (мал. 7).
Мал. 7. Використання Tdbimage для відображення графічних полів
Слід зазначити, що графічні поля баз даних може друкувати далеко не всякий професійний генератор звітів. Наприклад, Reportsmith, що входив в комплект постачання ряду продуктів Borland, може друкувати графічні зображення, що не мають безпосереднього відношення до даних (наприклад, узяті з файлів формату *.bmp), але зовсім не графічні поля таблиць.
Для відображення мемо-полей можна використовувати компонент Tqrdbtext. Якщо вміст мемо-поля, що відображається за допомогою цього компоненту, не уміщається в один рядок, висота цього компоненту (і висота компоненту Tqrband, що містить його) в режимі попереднього перегляду і при друці звіту збільшується так, щоб усередині компоненту Tqrdbtext уміщався весь вміст memo-поля. Щоб уникнути накладення тексту, що вийшов, на інші елементи звіту при його друці, можна просто розміщувати компоненти Tqrdbtext, що відображають memo-поля, в нижній частині Tqrband (рис 7).
Мал. 7. У лівій нижній частині даного звіту компонент Tqrdbtext відображає memo-поле
Мал. 8. А ось так виглядають memo-поля в звіті
Якщо таких memo-полей декілька і вони мають бути розміщені один під одним, можна використовувати декілька компонентів Tqrband одного типу для одного запису. В цьому випадку друкуватися вони будуть в порядку їх створення.
Попередній перегляд звітів
В деяких випадках потрібний попередній перегляд звітів на етапі виконання. Для цієї мети використовується метод Preview() компоненту Tquickreport. При його виконанні на екрані з'явиться стандартна форма перегляду, зображена на мал. 8.
Якщо зовнішній вигляд стандартної форми перегляду з якої-небудь причини вас не влаштовує, можна створити свою форму попереднього перегляду за допомогою компоненту Qrpreview. Цей компонент володіє властивостями Pagenumber і Zoom, які можна використовувати для проглядання довільної сторінки звіту в довільному масштабі.
Для створення власного вікна попереднього перегляду слід на знов створеній формі розмістити компонент Qrpreview і набір елементів управління (наприклад, кнопок) для переміщення між сторінками, зміни масштабу, друку і ін. Далі слід написати код, аналогічний приведеному нижче прикладу:
void __fastcall Tform1::showpreview()
Form2->showmodal();
void __fastcall Tform1::button1click(Tobject *Sender)
Qrprinter->onpreview=showpreview;
Form4->quickreport1->preview();
Form2->showmodal();
Крім того, потрібно внести прототип функції Showpreview() у відповідний h-файл:
__published: // Ide-managed Components
Tbutton *Button1;
void __fastcall Button1click(Tobject *Sender);
void __fastcall Showpreview(void);
Приведений приклад коди показує, як пов'язати створену форму з компонентом Quickreport. Цей зв'язок досягається написанням обробника події Qrprinter->onpreview. Ця подія не має прямого відношення до компоненту Quickreport, інакше потрібно було б пов'язувати всі створені звіти з вікном перегляду. Використання події об'єкту Qrprinter зазвичай означає написання загальної для всіх звітів обробника події, після чого вікно перегляду можна використовувати для всіх наявних в додатку звітов.
Контрольниі питання:
-
Для чого створюються звіти
-
Компоненти для створення звітів
-
Як створити простий звіт
-
Як створити детальний звіт
-
Як зв’язати прикладення із звітом
Практична робота №12 Створення браузеру
Мета: навчитися створювати браузер
Хід роботи
Ми вивчимо одну з технологій створення динамічних інтерактивних Web-сайтов, що непогано зарекомендували себе, - розробці CGI- і ISAPI-приложений. Будучи далеко не єдиною технологією створення таких Web-сайтов, вона проте залишається досить популярною. У даній статті ми розглянемо приклади створення CGI- і ISAPI-приложений, що виконуються під управлінням Microsoft Internet Information Services, за допомогою C++builder 5. Про інші способи створення динамічних Web-сайтов, наприклад розробці ASP-приложений, ви можете прочитати в статті Сергія Трепаліна <Створення серверних компонентів для ASP-приложений> на цьому ж CD-ROM.
Web-приложения (звані також скриптами) є виконувані файли або бібліотеки, що виконуються під управлінням Web-сервера. Їх призначення - у відповідь на запити користувача динамічно генерувати HTML-страницы, які інтерпретуватимуться web-браузером.
Застосування Інтернету в широкому сенсі означає доступ до ресурсів, що містяться в Мережі. Будь-який ресурс Інтернету однозначно ідентифікується за допомогою адреси URL (Uniform Resource Locators), яку можна ввести у відповідному полі браузера або вибрати, клацнувши мишею на гіпертекстовому посиланні Web-страницы або іншого документа. Прикладами Інтернет-ресурсів є HTML-страницы, документи різних форматів, Java-аплети, елементи управління ACTIVEX і інші файли. Результат виконання якого-небудь застосування, керованого Web-сервером, також є ресурсом Інтернету, і якщо налаштування рівня безпеки браузера дозволяють використовувати цей ресурс, він також буде інтерпретований браузером. Відзначимо, що додатки, що виконуються під управлінням Web-серверов і є джерелом подібних ресурсів, здатні обробляти параметри, що містяться в запиті користувача, і результат їх роботи може залежати від цих параметрів.
Створити Web-приложение, що динамічно генерує подібні ресурси (зазвичай HTML-документы), можна за допомогою практично будь-якого засобу розробки - аби воно дозволяло створювати додатки для тієї операційної системи, в якій працює Web-сервер. Проте якщо ви хочете понизити трудовитрати, пов'язані із створенням таких застосувань, то має сенс звернути увагу на засоби розробки, що дозволяють їх мінімізувати. З цієї точки зору досить вдалим вибором є Borland Delphi 5 і Borland C++builder 5 (редакції Enterprise і Professional), а також Delphi 4 і C++builder 4 Enterprise, оскільки ці засоби розробки містять непогані візуальні інструменти і компоненти для створення подібних застосувань.
Приклади, що розглядаються в справжній статті, або їх аналоги, якщо це особливо не обумовлено, можна створювати за допомогою будь-якого з перерахованих вище засобів розробки. Самі приклади створені за допомогою C++builder 5 Enterprise, але, думаю, користувачам Delphi не складе особливих труднощів перенести їх код на Object Pascal.
Вивчення розробки Web-приложений ми почнемо із створення простого прикладу.
Просте Web-приложение
Для створення простого Web-приложения з головного меню середовища розробки C++builder виберемо пункт File | New і в репозітарії об'єктів виберемо піктограму Web Server Application
Далі потрібно вибрати тип додатку (виконуваний файл CGI або WIN-CGI або динамічно завантажувана бібліотека Isapi/nsapi DLL, що є функціональним розширенням для Microsoft Internet Information Services або Netscape Fasttrack). CGI-скрипт (Cgi-common Gateway Interface), будучи виконуваним файлом, запускається в окремому процесі, тоді як Isapi/nsapi DLL (динамічно завантажувана бібліотека - виконується в адресному просторі Web-сервера. Тому Isapi/nsapi DLL вимагають менше ресурсів, чим CGI-скрипты. До того ж такі бібліотеки після завантаження залишаються в пам'яті сервера, що зменшує час їх відгуку на подальші звернення до них. Проте це заважає їх відладці: після внесення до бібліотеки яких-небудь змін необхідний перезапуск Web-сервера. У зв'язку з цим при розробці Web-приложений нерідко спочатку створюється CGI-скрипт, який потім відладжується, після чого на основі наявних модулів створюється Isapi/nsapi DLL. Так ми і поступимо: виберемо опцію CGI Stand-alone executable і створимо Win32-консольноє додаток для генерації HTML-документов. В результаті отримаємо об'єкт Twebmodule, що нагадує звичайний модуль даних (мал. 2).
Мал. 2. Об'єкт Twebmodule
Розглянемо, як працює Web-приложение. Якщо Web-сервер отримує від браузера запит, відповідний специфікації CGI, він ініціює запуск CGI-приложения для його виконання. Якщо запит коректний, CGI-приложение обробляє його і генерує HTML-документ, який відсилається Web-сервером назад в браузер. Для обміну даними між браузером і сервером використовується протокол HTTP (Hypertext Transfer Protocol).
Коли Web-приложение отримує HTTP-запрос, воно створює об'єкт Twebrequest для представлення запиту і об'єкт Twebresponce для представлення відгуку, що відправляється в браузер користувача. Потім обидва об'єкти передаються об'єкту Twebmodule (мал. 3).
Мал. 3. Структура Web-приложения
Об'єкт Twebmodule містить набір об'єктів Twebactionitems, що зберігають інформацію про те, як обробляти різні призначені для користувача запити. Пізнавши запит, він вибирає потрібний з них і виконує відповідний обробник події Onaction, оброблювальний запит і динамічно генеруючу відповідь, яка передається Web-сервером в браузер користувача.
Для того, щоб додаток був працездатним, створимо хоч би один об'єкт Twebactionitem, що реалізовує відгук на призначений для користувача запит. З цією метою з контекстного меню об'єкту Twebmodule треба вибрати пункт Action Editor і натиснути кнопку Add у формі, що з'явилася. Далі можна встановити властивості Pathinfo і Default об'єкту Webactionitem1. Перша властивість є частиною URL (Uniform Resource Locator) - повного опису доступу до ресурсу (мал. 4).
Мал. 4. Структура URL
Властивість Default указує, чи виконується даний відгук, якщо параметр Pathinfo в призначеному для користувача запиті залишився порожнім (ріс.5).
Рис. 5. Редактор Действия
Теперь создадим обработчик события OnAction компонента TWebActionItem:
void __fastcall TWebModule1::WebModule1WebActionItem1Action(
TObject *Sender, TWebRequest *Request, TWebResponse *Response,
bool &Handled)
{
AnsiString продолжение следует = AnsiString("<HTML><BODY><H3>Hello!</H3>");
продолжение следует = продолжение следует + AnsiString("<BR>");
продолжение следует = продолжение следует + AnsiString("<H2>Now есть ")+ TimeToStr(Время())+
AnsiString(" </H2>");
продолжение следует = продолжение следует + AnsiString("</BODY></HTML>");
Response->Content = продолжение следует;
}
В этом обработчике события генерируется содержащая текущее время HTML-страница примерно следующего вида (рис. 6):
Рис. 6. Динамически генерируемая HTML-страница
Зробимо одне невелике, але важливе зауваження. Перед компіляцією такого застосування в С++builder в опціях проекту слід відключити опцію Use dynamic RTL на сторінці Linker. Крім того, варто відключити і опцію Build with runtime packages на сторінці Packages або помістити всі ці бібліотеки в той же каталог, що і само застосування (мал. 7).
Мал. 7. Діалогова панель Project Options
Річ у тому, що запустити таке застосування з командного рядка можна без проблем, при цьому воно звертається до RTL і <пакетів>, що знаходяться за межами каталогів Web-сервера. Проте запустити його за допомогою Web-сервера швидше за все не вдасться - всі ці файли опиняться недоступні. В цьому випадку замість очікуваного результату виконання додатку буде отримано повідомлення про помилку приблизно наступного вигляду:
CGI Error
The specified CGI application misbehaved by not returning а complete set of HTTP headers. The headers it did return are: ...
Відзначимо, що при створенні ISAPI DLL з використанням Delphi 4 або C++builder 4 в такій бібліотеці не повинно бути <пакетів> - вона обов'язково повинна складатися з одного файлу.
Після компіляції додатку можна зберегти отриманий виконуваний файл в каталозі, призначеному для Web-приложений (у разі MS Internet Information Services за умовчанням це каталог C:\inetpub\scripts). Потім можна звернутися до додатку через web-браузер, вказавши URL-приложения. Звернете увагу: зовнішньому користувачеві, що звертається до створеного застосування через браузер, не видно (і не має бути видна) структура каталогів комп'ютера, що містить Web-сервер, - замість цього йому слід вводити їх псевдоніми. Такий підхід до використання каталогів Web-сервера необхідний для забезпечення безпеки - зовнішній користувач нічого не повинен знати про файли і каталоги комп'ютера, що містить Web-сервер, крім того що йому покладене.
Запустивши додаток, можна натиснути кнопку Reload і переконатися, що текст в браузере міняється. Це означає, що сторінка генерується динамічно (мал. 8).
Мал. 8. HTML-страница, що динамічно генерується
З цього CGI-скрипта ми можемо створити ISAPI DLL. Для цього слід створити нове Web-приложение у вигляді ISAPI DLL, видалити з нього об'єкт Twebmodule, а замість нього додати інший об'єкт Twebmodule з попереднього проекту.
Створення форм і обробка призначеного для користувача введення
Відзначимо, що об'єкт Twebmodule істотно полегшує створення CGI-приложений, пов'язаних з обробкою призначеного для користувача введення (наприклад, в HTML-формах), що полягає в зміні або додаванні даних. Типовими прикладами таких застосувань є анкети, які удосталь зустрічаються на багатьох Web-серверах. Доповнимо наше застосування такою анкетою.
Для відображення в браузере форми введення даних користувачем створимо ще один компонент Twebactionitem (мал. 9):
Мал. 9. Додавання об'єкту Twebactionitem для створення HTML-формы
Встановимо властивість Default знов створеного об'єкту Twebaction рівним True. Тепер додамо в Webmodule1 компонент Tpageproducer, призначення якого - генерувати HTML-документ на основі заздалегідь заданого шаблону (мал. 10).
Мал. 10. Додавання в Webmodule1 компоненту Tpageproducer
Для створення шаблону документа можна скористатися будь-яким HTML-редактором, що підтримує створення форм, наприклад Microsoft Frontpage (мал. 11).
Мал. 11. Створення шаблону HTML-формы за допомогою Microsoft Frontpage
Початковий текст форми, представленої на мал. 11, має вигляд:
<html>
<head>
<meta http-equiv="content-type" content="text/html;
charset=windows-1251">
<meta name="generator" content="microsoft Frontpage 2.0">
<title>untitled Normal Page</title></head>
<body bgcolor="#ffffff">
<p> </p>
<form method="get">
<p>what is Your name?<font size="4">
<input type="text" size="20" name="t1"></font></p>
<p>what is Your e-mail?<font size="4">
<input type="text" size="20" name="t2"></font></p>
<p><font size="4"><input type="submit" name="b1"
value="submit"><input type="reset" name="b2"
value="reset"></font></p>
</form>
</body>
</html>
Створений документ можна зберегти у вигляді файлу (і вказати його ім'я як властивість Htmlfile компоненту Tpageproducer). Можна також скопіювати HTML-текст в буфер обміну і помістити його редактор властивості Htmldoc цього компоненту.
Тепер створимо обробник події Onaction компоненту Twebactionitem2, що згенерував нами:
void __fastcall Twebmodule1::webmodule1webactionitem2action(
Tobject *Sender, Twebrequest *Request, Twebresponse *Response,
bool &Handled)
{
Response->content=pageproducer1->content();
}
Відзначимо, що в Delphi 5 і C++builder 5 компонент Twebaction має властивість Producer, що дозволяє безпосередньо вказати, яку саме HTML-страницу потрібно генерувати при зверненні. Це у багатьох випадках позбавляє від необхідності створювати обробник події Onaction даного компоненту.
Зберігши проект, можна знову звернутися до нього за допомогою браузера, вказавши значення Pathinfo в URL (мал. 12):
Мал. 12. Тестування HTML-формы в браузере
Тепер залишилося обробити призначене для користувача введення, наприклад, динамічно згенерувавши сторінку з введеними користувачем значеннями. З цією метою додамо ще один компонент - Tpageproducer (мал. 13):
Мал. 13. Додавання компоненту Pageproducer2 для генерації
сторінки, що містить результати обробки призначеного для користувача введення
Як значення властивості Htmldoc знов створеного компоненту Pageproducer2 введемо наступний текст:
<html>
<head>
<title>thank You!</title>
</head>
<body >
<p>dear <#t1>!</p>
<p>thank you for completing this form. We have included your
e-mail address <#t2> in our mailing list. You will receive а
lot of spam from us!</p>
</body>
</html>
Даним текстом є шаблон документа. Він містить спеціальні теги, що замінюються в процесі формування HTML-страницы рядками, які, у свою чергу, можуть бути введені користувачем в створену вище форму. У нашому випадку це теги <#t1> і <#t2>. Вони є іменами полів введення в створеній раніше формі, в чому можна переконатися, проглянувши HTML-текст форми.
Для заміни спеціальних тегів слід створити обробник події Onhtmltag компоненту Pageproducer2:
void __fastcall Twebmodule1::pageproducer2htmltag(
Tobject *Sender, Ttag Tag, const Ansistring Tagstring
Tstrings *TagParams, Ansistring &ReplaceText)
{
Replacetext = Request->queryfields->values[Tagstring]+
Request->contentfields->values[Tagstring];
}
Тут Request - об'єкт Twebrequest, що згенерував додатком в результаті призначеного для користувача запиту. У властивості Queryfields (об'єкт Tstrings) цього об'єкту містяться імена параметрів і значення, введені користувачем, у вигляді Name=value (реально вони містяться в змінній оточення Query_string, створеній Web-сервером, у вигляді Name1=value1&name2=value2&:). Параметр Tagstring - рядок, що міститься в тегу, підметі заміні. Cвойство Values об'єкту Tstrings використовується, якщо рядки, що містяться в цьому об'єкті, представіми у вигляді Name=value (що і відбувається в даному випадку).
Відзначимо, що якщо в тегу <form>, що міститься в тексті форми, замість методу GET вказаний метод POST, то замість властивості Queryfields слід використовувати властивість Contentfield.
Тепер створимо ще один компонент Twebaction (із значенням властивості Pathinfo, рівним /test3) для відображення сторінки, що згенерувала за допомогою Pageproducer2, і додамо ще один обробник події Onaction:
void __fastcall Twebmodule1::webmodule1webactionitem3action(
Tobject *Sender, Twebrequest *Request, Twebresponse *Response,
bool &Handled)
{
Response->content=pageproducer2->content();
}
Виникає питання: яким чином можна ініціювати генерацію цієї сторінки після натиснення користувачем кнопки Submit у формі введення? З цією метою слід описати реакцію на її натиснення в HTML-тексте форми, тобто відредагувати властивість Htmldoc компоненту Pageproducer1:
<form method="post"
action="http://mywebserver/scripts/formproc.exe/t3">
У параметрі action указується URL ресурсу, що надається при натисненні кнопки Submit. В даному випадку це наше застосування із значенням Pathinfo, рівним /test3 (природно, ім'я Web-сервера, так само як і інші частини URL, може бути іншим).
Тепер можна знову скомпілювати і зберегти додаток. Звернувшись до нього за допомогою браузера і заповнивши форму, натиснемо на кнопку Submit. В результаті отримаємо сторінку, що згенерувала динамічно на основі введених у форму даних (мал. 14):
Мал. 14. Результат обробки призначеного для користувача введення
З цього CGI-скрипта, як і у попередньому випадку, можна створити ISAPI DLL.
Контрольні питання: