instrum viz prog


Лекція № 1Тема: «Знайомство з мовою Object Pascal»
 
План
1. Відомості про візуальне програмування2. Типи даних в Object Pascal3. Математичні функції Object Pascal4. Структура програми на Object Pascal5. Область видимості змінних 
1. Відомості про візуальне програмуванняСкільки існує програмування, стільки існують у ньому й тупиків, у які воно постійно потрапляє й з яких, зрештою, доблесно виходить. Один з таких тупиків або криз був не так давно пов'язаний з розробкою графічного інтерфейсу користувача. Програмування вручну вікон, кнопок, меню, обробка подій миші й клавіатури, включення в програми зображень і звуку вимагало усе більше й більше часу програміста. У ряді випадків увесь цей сервіс починав займати до 80-90% об'єму програмних кодів. Причому вся ця праця нерідко пропадала майже впусту, оскільки через деякий час мінявся загальноприйнятий стиль графічного інтерфейсу, і все доводилося починати заново.
Вихід із цієї ситуації був знайдений завдяки двом підходам. Перший з них - стандартизація багатьох функцій інтерфейсу, завдяки чому з'явилася можливість використовувати бібліотеки, наявні, наприклад, в Windows. Зокрема, з'явився API Windows - інтерфейс, у якому описана безліч функцій, причому від версії до версії набір функцій розширюється, внутрішній опис функцій удосконалюється, але форми виклику функцій не змінюються. У підсумку, при зміні стилю графічного інтерфейсу (наприклад, при переході від Windows 3.x до Windows 95, а потім до Windows 2000) додатки змогли автоматично пристосовуватися до нової системи без якого-небудь перепрограмування. У результаті з’явилися прекрасні умови для розв'язання однієї з найважливіших задач удосконалювання техніки програмування – повторного використання кодів. Одного разу розроблені вами форми, компоненти, функції могли бути згодом неодноразово використані вами або іншими програмістами для рішення інших задач. Кожний програміст одержав доступ до наробітків інших програмістів і до величезних бібліотек, створених різними фірмами. Причому була забезпечена сумісність програмного забезпечення, розробленого на різних алгоритмічних мовах.
Другим революційним кроком, що кардинально полегшили життя програмістів, виявилася поява візуального програмування, що виникло в Visual Basic і знайшло блискуче втілення в Delphi і C++Builder фірми Borland.
Візуальне програмування дозволило звести проектування користувацького інтерфейсу до простих і наочних процедур, які дають можливість за хвилини або годинни зробити те, на що раніше йшли місяці роботи. У сучасному вигляді в Delphi це виглядає так.
Ви працюєте в Інтегрованому Середовищі Розробки (ІСР або Integrated development environment - IDE) Delphi. Середовище надає вам форми (у додатку їх може бути декілька), на яких розміщаються компоненти. Звичайно це віконна форма, хоча можуть бути й невидимі форми. На форму за допомогою миші переносяться й розміщаються піктограми компонентів, наявні у бібліотеках Delphi. За допомогою простих маніпуляцій ви можете змінювати розміри й розташування цих компонентів. При цьому ви увесь час у процесі проектування бачите результат - зображення форми й розташовані на ній компонентів. Вам не треба мучитися, багаторазово запускаючи додаток і вибираючи найбільш удалі розміри вікна й компонентів. Результати проектування ви бачите, навіть не компілюючи програму, негайно після виконання якоїсь операції за допомогою миші.
Але достоїнства візуального програмування не зводяться тільки до цього. Найголовніше полягає в тому, що під час проектування форми й розміщення на ній компонентів Delphi автоматично формує коди програми, включаючи в неї відповідні фрагменти, що описують даний компонент. А потім у відповідних діалогових вікнах користувач може змінити задані за замовчуванням значення якихось властивостей цих компонентів і, при необхідності, написати оброблювачі якихось подій. Тобто проектування зводиться, фактично, до розміщення компонентів на формі, завданню деяких їх властивостей і написанню, при необхідності, оброблювачів подій.
Компоненти можуть бути візуальні, видимі при роботі додатка, і невізуальн, що виконують ті або інші службові функції. Візуальні компоненти відразу відображаються на екрані в процесі проектування в такому ж вигляді, у якому їх побачить користувач під час виконання додатка. Це дозволяє дуже легко вибрати місце їх розташування і їх дизайн - форму, розмір, оформлення, текст, колір і т.д. Невізуальні компоненти відображаються на формі в процесі проектування у вигляді піктограм, але користувачеві під час виконання вони не не доступні, хоча й виконують для нього за кадром досить корисну роботу.
У бібліотеки візуальних компонентів Delphi включено багато типів компонентів, і їх номенклатура дуже швидко розширюється від версії до версії. Наявного вже зараз цілком достатньо, щоб побудувати практично будь-який складний додаток, не удаючись до створення нових компонентів. При цьому навіть недосвідчений програміст, що робить свої перші кроки на цьому поприщі, може створювати додатки, які виглядають цілком професійно.
Окремо треба сказати про одну з головних задач Delphi – розробку додатків для роботи з базами даних. У цій області Delphi займає самі передові позиції, працюючи з будь-якими системами керування базами даних.
У цілому Delphi – чудовий інструмент, як для починаючих програмістів, так і для асів програмування. (початок) 
2. Типи даних в Object PascalМова Object Pascal вимагає, щоб усі використовувані в тексті програми змінні були попередньо описані в спеціальному розділі опису змінних, який починається із ключового слова VAR.
При описі кожної змінної вказується її тип. Тип змінної визначає тип інформації, яку змінна може зберігати.
Типи змінних в Object Pascal розділяють на кілька груп.
 
Цілі типи даних
Цілі типи даних використовуються для представлення цілих чисел. Вони належать до цілих порядкових типів. Нижче наведена таблиця, у якій перелічуються ці типи для Delphi і даються діапазони їх змін.
Тип Діапазон значень Вимоги до пам'яті в байтах Знаковий( чи може зберігати негативні числа)
Byte 0 : 255 1 немає
Word 0 : 65535 2 немає
Longword 0 : 4294967295 4 немає
Shortint -128:127 1 так
Smalllnt -32768 : 32767 2 так
Cardinal 0 : 4294967295 4 немає
Integer -2147483648 : 2147483647 4 так
Longlnt -2147483648 : 2147483647 4 так
Родовими типами ( тобто такими, що забезпечують максимальну продуктивність) серед перелічених є Integer і Cardinal. Арифметичні операції над цілими числами повертають тип Integer.
Якщо намагатися збільшити значення змінної, що вже має максимальне для даного типу значення, то відбудеться циклічний перехід до мінімального значення. Аналогічно при спробі зменшити мінімальне значення відбудеться перехід до максимального значення. Наприклад, оскільки тип Shortint може приймати значення тільки в діапазоні від -128 до 127, то код
 
var i:shortint;
i:=127;
i:=i+2;
 
дасть у результаті I = -128.
Для вимикання цієї можливості виконайте команду Project – Options і на закладці Compiler установіть прапорець Range Checking. Після цього в подібних ситуаціях буде виводитися на екран повідомлення про помилку.
 
Дійсні типи даних
Дійсні типи даних призначені для зберігання чисел, що мають дробову частину. Нижче наведена таблиця, у якій перелічуються ці типи для Delphi і даються діапазони їх змін.
Тип Діапазон значень Число значущих розрядів Вимоги до пам'яті у байтах
Real48 ±2.9*10-39 ? ±1.7*1038 11-12 6
Real ±5.0*10-324 ? ±1.7*10308 15-16 8
Single ±1.5*10-45?±3.4*1038 7-8 4
Double ±5.0*10-324?±1.7*10308 15-16 8
Extended ±3.6*10-4932?±1.1*104392 19-20 10
Comp -263: 262 19-20 8
Currency -922337203685477.5808 : 922337203685477.5807 19-20 8
Родовим (тобто таким, що забезпечує максимальну продуктивність) є тип Real. Найменшу продуктивність забезпечує тип Real48, що зберігається тільки для зворотної сумісності з більш ранніми версіями язика.
Тип Extended має максимальну точність, але можуть виникати проблеми з його переносимістю на інші платформи.
Тип Comp є цілим, а не дійсним числом. Цей тип залишений тільки для зворотної сумісності з більш ранніми версіями язика, оскільки його можливості перекриваються цілим типом Int64.
Тип Currency використовується для представлення грошових величин. При операціях з величинами типу Currency мінімізуються помилки округлення, що дуже важливо для грошових розрахунків.
 
Символьні типи даних
Символьні типи призначено для зберігання одного символу. Нижче наведена таблиця символьних типів. Наявність двох різних типів - Ansichar і Widechar пов'язане із двома різними множинами символів: ANSI, кожний символ якого займає 1 байт, і Unicode, кожний символ якого займає 2 байта. Перші 256 символів у цих множинах однакові й відповідають символам ASCII від 0 до 255.
Тип Розмір у байтах Що може зберігати
Char 1 Один символ ANSI
Widechar 2 Один символ Unicode
Родовим (тобто таким, що забезпечують максимальну продуктивність) є тип Char.
 
Строкові типи
Рядки являють собою послідовність символів. Нижче наведена таблиця типів рядків.
Тип рядка Максимальна довжина Використовується для
String або 255, або до ~2 Гб символів ANSI або Unicode
Widestring -230(~1 Гб) символів Unicode, у серверах СОМ і інтерфейсах
Родовим є тип String.(початок)  
 
3. Математичні функції Object PascalДля виконання розрахунків в Object Pascal є стандартні функції. Усі ці функції описані в модулі Math.tpu, що входить в Object Pascal. Для використання функцій необхідно підключити модуль Math у розділі Uses.
 
Математичні функції
Функція Опис
Abs(X) модуль числа
Ceil(X) округлення до найменшого цілого
Exp(X) експонента
Floor(X) округлення до найбільшого цілого
Frac(X) дробова частина аргументу
Inrange (Avalue, Amin, Amax) визначає, чи лежить Avalue у діапазоні Amin - Amax
Int(X) ціла частина аргументу
Ln(X) натуральний логарифм від X
Log10(X) десятковий логарифм від X
Logn (N, X) логарифм від X по основі N
Max(A, B) максимум двох чисел
Min(A, B) мінімум двох чисел
Pi число Пі: 3.1415926535897932385
Power(X, Y) возведення X у довільну ступінь Y
Roundto(X, Adigit) округлення X до Adigit цифр
Sqr(X) квадрат аргументу
Sqrt(X) квадратний корінь
Trunc(X) повертає цілу частину дійсного виразу
 
Тригонометричні й гіперболічні функції
Функція Опис
Arccos(X) арккосинус
АrсСоshХ) арккосинус гіперболічний
Arcsin(X) арксинус
Arcsinh(X) арксинус гіперболічний
Arctan(X) арктангенс
Arctanh(X) арктангенс гіперболічний
Cos(X) косинус
Cosh(X) косинус гіперболічний
Cotan(X) котангенс
Sin(X) синус
Sinh(X) синус гіперболічний
Tan(X) тангенс
Tanh(X) тангенс гіперболічний (початок)   
4. Структура програми на Object PascalПрограма, яку будує Delphi у процесі проектування вами додатка, заснована на модульному принципі. Сама головна програма виходить гранично простою і короткої. Вона складається з оголошення списку використовуваних модулів і декількох операторів, які створюють об'єкти тих форм, які ви розробили, і запускають виконання додатка.
Принцип модульності дуже важливий для створення надійних додатків, які відносно легко модифікуються. Чітке дотримання принципів модульності в сполученні із принципом приховання інформації дозволяє усередині будь-якого модуля проводити якісь модифікації, не зачіпаючи при цьому інших модулів і головну програму.
Усі об'єкти компонентів розміщаються в об'єктах – формах. Для кожної форми, яку ви проектуєте у своєму додатку, Delphi створює окремий модуль. Саме в модулях і здійснюється програмування задачі. В оброблювачах подій об'єктів – форм і компонентів, ви поміщаєте всі свої алгоритми.
У процесі проектування додатка Delphi автоматично створює код головної програми й окремих модулів. У модулі ви вводите свій код, створюючи оброблювачі різних подій. Але головну програму, як правило, ви не чіпаєте й навіть не бачите її текст. Тільки у виняткових випадках вам треба щось змінювати в тексті головної програми, яка генерується Delphi.
Не перевантажуйте головну програму додатка ніяким додатковим кодом. (початок)  
 
5. Область видимості зміннихКожна форма зберігати свій код у вигляді файлу модуля, оформленого за правилами оформлення модулів в Turbo Pascal. Кожний модуль може мати безліч підпрограм (процедур і функцій), що виконують різні функції. При написанні програми може виникнути необхідність обміну даними між різними підпрограмами модуля.
Реальний проект Delphi може складатися з декількох форм, а значить із декількох модулів. Під час роботи програми може виникнути необхідність в обміні даними між різними формами проекту.
В обох випадках обмін інформацією можна виконати за допомогою змінних. При цьому в першому випадку змінні будуть доступні для підпрограм конкретного модуля, а в другому – для підпрограм усіх модулів проекту.
У модульному програмування існує поняття «області видимості змінних». Воно означає, що залежно від того, у якому місці описана змінна, вона може бути «видима» різним елементам програми:
- змінна, описана усередині підпрограми, доступна тільки в коді цієї підпрограми;
- змінна, описана усередині модуля в розділі Implementation, доступна в коді будь-якої підпрограми поточного модуля;
- змінна, описана усередині модуля в розділі Interface, доступна в коді будь-якої підпрограми будь-якого модуля проекту.(початок) 
Питання для самоконтролю
1. У чому проявлявся тупик розробки графічного інтерфейсу? Як він був обійдений?
2. Які цілі й речовинні типи даних Object Pascal ви знаєте? Дайте їхню характеристику
3. Які символьні й строкові типи Object Pascal ви знаєте? Приведіть 10 будь-яких математичних функцій Object Pascal
4. Опишіть основні принципи побудови програм в Delphi. Що означає область видимості змінних? Які змінні із точки зору області видимості ви знаєте? Як їх описати?
Лекція № 2
Тема: «Характеристика проектів Delphi. ІСР розробника»
 
План
1. Структура проекту в Delphi, основні файли проектів2. Створення й збереження нового проекту3. Завдання облікової інформації проекту4. Робота в ІСР Delphi5. Основні настроювання ІСР Delphi 
1. Структура проекту в Delphi, основні файли проектів
Проект Delphi складається з форм, модулів, установлень параметрів проекту і т.д. Уся ця інформація розміщається у файлах. Багато із цих файлів автоматично створюються Delphi, коли ви будуєте ваш додаток. Ресурси, такі, як бітові матриці, піктограми і т.д., перебувають у файлах, які ви отримуєте з інших джерел або створюєте за допомогою численних інструментів і редакторів ресурсів, наявних у вашому розпорядженні. Крім того, компілятор також створює файли.
Коли ви проектуєте ваш додаток, Delphi створює наступні файли:
 
Файл проекту (.dpr) Цей текстовий файл використовується для зберігання інформації про форми й модулі. У ньому містяться оператори ініціалізації й запуску програми на виконання.
Файл модуля (.pas) Кожній створюваній вами формі відповідає текстовий файл модуля, використовуваний для зберігання коду. Іноді ви можете створювати модулі, не пов'язані з формами. Багато з функцій і процедур Delphi зберігаються в модулях.
Файл форми (.dfm) Це двійковий або текстовий файл, який створюється Delphi для зберігання інформації про ваші форми. Кожному файлу форми відповідає файл модуля (.pas).
Файл параметрівпроекту (.dfo) У цьому файлі зберігаються установки параметрів проекту.
Файл ресурсів (.res) Цей бінарний файл містить використовувану проектом піктограму та інші ресурси.
Файли резервних копій(.~dp, .~df, ~pa) Це відповідно файли резервних копій для файлів проекту, форми й модуля. Якщо ви щось безнадійно зіпсували у своєму проекті, можете відповідно змінити розширення цих файлів і в такий спосіб повернутися до попереднього не зіпсованого варіанта.
 
Наступна група файлів створюється компілятором:
 
файл, що виконується (.ехе) Є автономним файлом, що виконується, для якого більше нічого не потрібно, якщо тільки ви не використовуєте бібліотеки, що містяться в DLL, OCX і т.д., а також якщо ви не використовуєте підтримку пакетів часу виконання
Об'єктний файлмодуля (.dcu) Це відкомпільований файл модуля (.pas), який компонується в остаточний файл, що виконується.
 
І, нарешті, інші файли Windows, які можуть використовуватися Delphi:
 
Файли довідки (.hlp .chm) Це стандартні файли довідок Windows, які можуть бути використані вашим додатком Delphi.
Файли зображень або графічні файли (.wmf, .bmр, .ico) Ці файли зазвичай використовуються в додатках Windows для створення привабливого й дружнього користувацького інтерфейсу.
 
Головною частиною вашого додатка є файл проекту (.dpr), що містить код мовою Object Pascal, з якого починається виконання вашої програми і який забезпечує ініціалізацію інших модулів. У більшості випадків ви можете створити закінчений додаток Delphi, так і не глянувши на цей файл. Він створюється й модифікується Delphi автоматично в процесі вашої розробки додатка. Ім'я, яке ви даєте файлу проекту, коли зберігаєте його, стає іменем файлу, що виконується.
Усі зміни файлу проекту при додаванні нових форм, зміні імен форм і т.п. підтримуються Delphi автоматично. Якщо вам необхідно подивитися вихідний файл проекту, треба виконати команду Project - View Source. Але звичайно це вам не потрібно. Не треба без особливої потреби змінювати файл проекту. Це може привести до неузгодженості використовуваних імен і до інших неприємностей. (початок) 
2. Створення й збереження нового проекту
Розмову про створення нового проекту почнемо з однієї важливої поради: заведіть собі за правило відводити для кожного нового проекту новий підкаталог (папку Windows). Зручна структура каталогів суттєво полегшує роботу над проектами. Зв'язана ця порада з тим, що якщо поміщати кілька проектів в один каталог, то ви заплутаєтеся в тому, які файли до якого проекту належать. Розміщення проектів у різних каталогах позбавить вас надалі від багатьох неприємностей.
Якщо у вас виникає кілька варіантів виконання проекту, а звичайно так і буває, то бажано усередині каталогу проекту створювати підкаталоги для кожного варіанта. Зручна структура каталогів суттєво полегшує роботу над серйозними проектами.
Новий каталог ви можете створити засобами Windows перед початком проекту, або створювати його можна у вікні стандартного діалогу збереження файлів за допомогою відповідної швидкої кнопки.
 
Створення нового проекту
Почати новий проект можна декількома способами. Можна виконати команду File - New - Application. Ще один шлях - команди File - New - Other. При виборі цієї команди відкривається вікно New Items (нові елементи).
Це вікно є вітриною Депозитарію об'єктів (Object Repository) - сховища зразків компонентів, форм, фреймів і проектів. Ви можете й самі створювати якісь свої форми, компоненти, фрейми, проекти й включати їх у Депозитарій.
У нашому випадку ми прагнемо відкрити новий проект. Це можна зробити, клацнувши на піктограмі Application (додаток), яка розташована на сторінці New (новий). Піктограма Application створює додаток з порожньою формою.
Ви можете також скористатися й деякими іншими варіантами додатків, піктограми яких розташовані на сторінці Projects. Щоб одержати пояснення по об'єктах, що містяться в Депозитарії, можна клацнути у вікні правою кнопкою миші й з випливаю чого меню вибрати форму відображення View Details (подробиці). Форма відображення зміниться, і ви зможете побачити короткі пояснення пропонованих вам варіантів.
Можливість користуватися готовими проектами з Депозитарію виглядає, безумовно, привабливої. Але я б не радив захоплюватися цими можливостями. Користуючись не порожніми ескізами додатків і форм, ви завжди ризикуєте, що в них виявляться якісь, не замічені вами особливості, які не дозволять додатку працювати так, як вам хотілося б. До того ж, додаток буде виглядати стандартним, позбавленим індивідуальності. Коли ви освоїтеся з Delphi, краще весь додаток робити самому, починаючи з порожньої форми. А проекти з Депозитарію, так само як і приклади, що поставляються з Delphi, корисно подивитися, вивчити, випробувати, перенести якісь прийоми програмування до своїх додатків, але не більш того.
 
Збереження проекту, його повторне відкривання
Першу дію, яку я рекомендував би вам виконати після створення нового проекту - зберегти його. Після того, як ви створили додаток з порожньою формою, відразу збережіть його в потрібному каталозі. І протягом роботи над проектом частіше виконуйте збереження.
Якщо ви починаєте роботу з того, що зберігаєте проект, і надалі регулярно повторюєте збереження, ви можете не побоюватися будь-яких несподіванок типу збою комп'ютера або Delphi, викликаних технічними причинами або неприпустимими діями вашого власного ще не налагодженого додатка при його запуску. Але є й ще аргумент на користь негайного збереження проекту й модулів. У багатовіконних додатках, які будуть розглянуті пізніше, це дозволяє відразу задати модулям імена, які будуть використовуватися в програмі для взаємних посилань модулів один на одного. Якщо ви не виконали відразу збереження форми, то змушені спочатку посилатися на її ім'я за замовчуванням, а надалі змінювати ці посилання.
Зберегти проект можна командою File - Save All. Зручно також використовувати відповідну швидку кнопку. При першому збереженні Delphi запитає у вас ім'я файлу модуля, а потім - ім'я файлу Проекту треба мати на увазі, що Delphi не допускає однакових імен модулів і проектів. Імена файлів повинні бути різними. Завжди при збереженні проектів і модулів задавайте осмислені імена файлів.
Чому не варто погоджуватися при збереженні з іменами, пропонованими Delphi за замовчуванням - Projectl, Unitl і т.п.? По-перше, ім'я файлу проекту буде надалі іменем вашого виконуваного модуля. Напевно, не дуже добре буде віддавати замовникові проект із такою дивною назвою, як Projectl.
По-друге, ім'я файлу модуля буде й іменем самого модуля. У проекті з одним модулем ім'я Unitl, можливо, не так уже й страшно. Але якщо у вас у проекті буде кілька модулів, те чи навряд вам буде зручно увесь час пам'ятати, що таке Unitl, а що таке Unit5. Крім того, уявіть собі, що ви на якийсь час припинили роботу над своїми проектами, а потім знову її відновили. Або супровід ваших проектів здійснюється не вами, а кимось іншим. Ви упевнені, що легко буде розібратися в численних Projectl і Unitl незрозумілого призначення?
При розробці простих прототипів проектів зручно задавати імена файлів проектів і модулів однаковими, розрізняючи їх тільки префіксом «Р» або «U» відповідно. Наприклад, файл проекту – Peditor1, файл модуля – Ueditor1. Це спрощує розуміння того, які файли до якого варіанта проекту відносяться, оскільки на початкових стадіях проектування у вас може з'явитися кілька альтернативних варіантів того самого проекту.
Отже, рекомендації зі створення нового проекту зводяться до наступного.
Створіть новий каталог для свого нового проекту.
Створіть новий проект командою File - New - Application.
Відразу збережіть проект і файл модуля командою File - Save All.
У наступних сеансах роботи ви можете відкрити збережений проект командою File - Open Project. Але якщо ви працювали із проектом недавно, то багато зручніше відкрити його командою File - Reopen. А ще зручніше скористатися стрілочкою поруч із відповідною для цієї команди швидкою кнопкою. В обох випадках відкривається вікно, у якому ви легко знайдете кілька проектів, з якими працювали останнім часом, а також ряд файлів, з якими ви працювали.
Є ще більш зручний спосіб автоматично відкривати при завантаженні Delphi той проект, з яким ви працювали в попередньому сеансі. Для цього треба виконати команду Tools - Environment Options. У діалоговому вікні, що відкрилося, треба перейти на сторінку Preferences і включити індикатор Desktop групи опцій Autosave options. Тоді при кожному запуску Delphi буде завантажуватися ваш останній проект попереднього сеансу й будуть відкриватися всі вікна, які були відкриті в момент попереднього виходу з Delphi. Це дуже зручно, якщо ви маєте намір продовжувати роботу над тим же проектом.
Ви можете зберегти свій проект у Депозитарії. Згодом з появою схожої задачі ви можете запозичити його звідти, щось у ньому змінити й у такий спосіб заощадити собі багато часу. (початок) 
3. Завдання облікової інформації проекту
На заключній стадії проектування, коли основні задачі розробки вже вирішені, необхідно провести ряд робіт з оформлення вашого додатка:
Розробити для вашого проекту файл довідки;
Задати облікову інформацію про версію вашого програмного продукту;
Продумати питання про установку додатка на комп'ютерах користувачів. Можливо, що для цього буде потрібно створити спеціальну програму установки;
Якщо ви сподіваєтеся на поширення вашого додатка за рубежем (у тому числі й у близькому зарубіжжі), то необхідно вирішити задачу інтернаціоналізації вашої програми.
Поки зупинимося тільки на одному завданні - задаванні в додатку інформації про версію продукту, його призначенні й т.п. Така інформація повинна бути включена в будь-який програмний продукт, розповсюджуваний серед користувачів. Втім, і для самого себе корисно вказувати подібну інформацію, щоб не заплутатися в численних версіях розроблювального додатка.
Для завдання або перегляду цієї інформації треба виконати команду Project - Options і у вікні, що відкрилося, перейти на сторінку Version Info. Зазначена на даній сторінці інформація заноситься у виконуваний файл і стає доступна користувачеві, коли він, працюючи в Windows, клацає правою кнопкою миші на піктограмі вашого додатка й вибирає команду Властивості. Тоді в діалоговім вікні, що відкрилося, на сторінці Версія користувач може побачити інформацію про ваш додаток.
Основна опція сторінки Version Info вікна опцій проекту - Include version information. Якщо вона не встановлена, то всі вікна сторінки доступні тільки для читання. Це дозволяє просто подивитися інформацію про версію вашого минулого додатка, якщо, звичайно, ви подбали про те, щоб увести її в додаток. Якщо ж ви встановите опцію Include version information, то всі вікна сторінки стануть доступні для введення інформації.
Вікна групи Module Version Number дозволяють вам задати номер версії, що складається із чотирьох цифр, розділених крапками. Наприклад, 2.3.1.0. Цей номер користувач бачить у верхній частині вікна. Індикатор Auto-increment build number дозволяє автоматизувати зміну останньої із цих цифр. Якщо ви включили цей індикатор, остання цифра буде збільшуватися на одиницю щораз, коли ви будете виконувати команду Project - Build All. При інших командах компіляції цифра змінюватися не буде.
Група індикаторів Module Attributes указує призначення версії. Ці індикатори можна заповнювати для себе в чисто інформаційних цілях, наприклад: Debug Build - налагодження, Pre-Release - версія не для комерційного використання, DLL - проект DLL, Special Build - версія отримана в стандартному режимі компіляції, Private Build - версія побудована не в стандартному режимі компіляції.
Вікно Language указує кодову сторінку системи користувача, яка потрібна для запуску додатка, тобто вказує мову. Вікно Language заповнюється автоматично залежно від установленої в системі кодової сторінки.
Список Key/Value містить у собі стандартні відомості про програмний продукт: Companyname (Виробник), Filedescription (Опис), Fileversion (Версія продукту), Internalname (Внутрішнє ім'я), Legalcopyright (Авторські права), Legaltrademarks ( Товарні знаки), Originalfilename (Вихідне ім'я файлу), Productname (Назва продукту), Productversion (Версія продукту), Comments (Коментар). Переміщаючи курсор у цьому вікні, користувач може читати те, що ви занесли в список Key/Value. Загалом кажучи, для комерційного продукту всі рядки списку, крім Legalcopyright, Legaltrademarks і Comments, повинні заповнюватися, а ці три рядки можуть заповнюватися при необхідності. (початок) 
4. Робота в ІСР Delphi
Інтегроване Середовище Розробки (Integrated Development Environment – IDE, надалі ми будемо використовувати для неї абревіатуру ІСР) - це середовище, у якім є все необхідне для проектування, запуску й тестування додатків і де все націлене на полегшення процесу створення програм. ІСР інтегрує в собі редактор кодів, відладчик, інструментальні панелі, редактор зображень, інструментарій баз даних - все, із чим доводиться працювати. Ця інтеграція надає розроблювачу гармонічний набір інструментів, що доповнюють один одного. Більше того, як ви побачите надалі, вам надана можливість розширювати меню ІСР, включаючи в нього необхідні вам додаткові програми, у тому числі й власні. Результатом є зручне для вас середовище швидкої розробки складних прикладних програм.
Запустіть Delphi, вибравши піктограму Delphi у розділі меню Windows Пуск - Програми. Коли ви клацнете на піктограмі Delphi, перед вами відкриється основне вікно Інтегрованого Середовища Розробки. Загалом вікна всіх версій Delphi достатньо подібні.
У верхній частині вікна ІСР ви бачите смугу головного меню. Її склад трохи різниться від версії до версії й, крім того, залежить від варіанта Delphi, з яким ви працюєте.
Нижче смуги головного меню розташовано дві інструментальні панелі. Ліва панель містить два ряди швидких кнопок, що дублюють деякі найбільше часто використовувані команди меню. Права панель містить палітру компонентів бібліотеки візуальних компонентів. Палітра компонентів містить ряд сторінок, закладки яких видні в її верхній частині.
В основному полі вікна ви можете бачити ліворуч два вікна: зверху - Дерево Об'єктів (Object Treeview), під ним - Інспектор Об'єктів (Object Inspector). Вікно Дерево Об'єктів буде відображати ієрархічний зв'язок візуальних і невізуальних компонентів і об'єктів вашого додатка. А Інспектор Об'єктів - це основний інструмент, за допомогою якого ви надалі будете задавати властивості компонентів і оброблювачі подій. Праворуч від цих вікон ви можете бачити вікно порожньої форми, готової для переносу на неї компонентів. Під ним розташоване вікно Редактора Кодів. Звичайно воно при першому погляді на екран невидимо, тому що його розмір дорівнює розміру форми й вікно Редактора Кодів практично повністю перекривається вікном форми.
 
Палітра компонентів
Палітра компонентів - це вітрина тієї бібліотеки компонентів, з якої ви працюєте. Палітра дозволяє згрупувати компоненти відповідно до їхнього змісту й призначенням. Ці групи або сторінки постачені закладками. Ви можете змінювати комплектацію сторінок, уводити нові сторінки, переставляти їх, вносити на сторінки розроблені вами шаблони й компонента і т.д.
Оскільки число сторінок в Delphi велике й не всі закладки видні на екрані одночасно, у правій частині палітри компонентів є дві кнопки зі стрілками, спрямованими вліво й вправо. Ці кнопки дозволяють переміщати відображувану на екрані частину палітри. На деяких сторінках розташоване стільки компонентів, що вони не містяться у видимій частині сторінки. У цих випадках на кінцях сторінки з'являються додаткові кнопки, що дозволяють переміщатися уздовж сторінки.
Щоб перенести компонент на форму, треба відкрити відповідну сторінку бібліотеки й указати курсором миші необхідний компонент. При цьому кнопка-покажчик, розміщена в лівій частині палітри компонентів, придбає вид не натиснутої кнопки. Це значить, що ви перебуваєте в стані, коли збираєтеся помістити компонент на форму. Помістити обраний компонент на форму дуже просто - треба зробити клацання мишею в потрібному місці форми.
Є й інший спосіб помістити компонент на форму - досить зробити подвійне клацання на піктограмі компонента, і він автоматично розміститься в центрі вашої форми. Якщо ви вибрали компонент, а потім змінили ваш намір розміщати його, вам досить нажати кнопку покажчика. Це перерве процес розміщення компонента, і програма повернеться в нормальний режим, у якому ви можете вибирати інший компонент або виконувати якусь команду.
 
Вікно форми
Основою майже всіх додатків Delphi є форма. Її можна розуміти як типове вікно Windows. Форма є основою, на якій розміщаються інші компоненти.
Форма має ті ж властивості, що властиві іншим вікнам Windows. Вона має керуюче меню у верхньому лівому куті, смугу заголовка, що займає верхню частину, кнопки розгортання, згортання й закриття вікна у верхньому правому куті. Можна змінити вигляд вікна, забравши в ньому якісь кнопки або всю смугу заголовка, зробивши його вікном з незмінними розмірами й т.п.
Під час проектування форма покрита сіткою із крапок: У вузлах цієї сітки розміщаються ті компоненти, які ви поміщаєте на форму. Під час виконання додатка ця сітка, звичайно, не видна.
У деяких випадках при розробці якогось модуля форма може виявитися взагалі непотрібною. Але зазвичай вся робота в Delphi проводиться саме на формі.
Коли ви помістили на формі якісь компоненти, ви можете отримати по них контекстну довідку. Для цього виділіть компонент, що цікавить вас, і натисніть клавішу F1. Якщо ви клацнете на самій формі й натиснете клавішу F1, вам буде показана довідка по класу форми.
 
Вікно Редактора Коду
Однієї з найбільш важливих частин середовища Delphi є вікно Редактора Коду.
У редакторі застосовується виділенням кольором і шрифтом синтаксичних елементів. Жирним шрифтом виділяються ключові слова Object Pascal. Синім курсивом виділяються коментарі.
У заголовку вікна Редактора Коду відображається ім'я поточного файлу, з текстом якого ви працюєте. У верхній частині вікна ви можете бачити також закладки або ярлички, що вказують поточні відкриті файли. Додатки Delphi можуть використовувати багато вихідних файлів, і закладки допомагають вам переходити від одного з них до іншого.
У вікно Редактора Коду, як і в інші вікна Delphi, вбудована контекстна довідка. Щоб одержати довідку по якомусь слову коду (ключовому слову, написаному імені функції й т.п.), досить установити курсор на це слово й нажати клавішу F1. Вам буде показана відповідна тема довідки, вбудованої в Delphi.
 
Інспектор Об'єктів
Інспектор Об'єктів (Object Inspector) забезпечує простий і зручний інтерфейс для зміни властивостей об'єктів Delphi і керування подіями, на які реагує об'єкт.
Вікно Інспектора Об'єктів має дві сторінки. У верхній частині вікна є список, що випадає, усіх компонентів, розміщених на формі. У ньому ви можете вибрати той компонент, властивості й події якого вас цікавлять.
Сторінка властивостей (Properties) Інспектора Об'єктів показує властивості того об'єкта, який виділений вами. Клацніть на вікні порожньої форми, і на сторінці властивостей Інспектори Об'єктів ви зможете побачити властивості форми. Ви можете змінювати ці властивості.
Сторінка подій (Events) становить другу частину Інспектора Об'єктів. На ній зазначені всі події, на які може реагувати обраний об'єкт. Для написання оброблювача потрібної події клацніть два рази праворуч від назви події. Відкриється вікні редактора коду із заготовкою процедури, у якій потрібно ввести код оброблювача.
Користуючись Інспектором Об'єктів, ви можете одержати контекстну довідку по властивостях або подіях. Для цього виділіть у вікні Інспектора Об'єктів властивість, що цікавить вас, або подію й натисніть клавішу F1. (початок) 
5. Основні настроювання ІСР Delphi
Настроювання інструментальних панелей
Delphi надає досить широкі можливості настроювання інструментальних панелей ІСР. Наприклад, ви може зробити якісь із панелей, які вам зараз не потрібні, невидимими. Для цього виконайте в Delphi команду View - Toolbars або просто клацніть на будь-якій панелі правою кнопкою миші. Ви побачите меню, що містить індикатори окремих панелей. Ви можете включити, наприклад виключений за замовчуванням індикатор панелі Internet. А можете, навпаки, виключити якісь із індикаторів (наприклад, індикатор Custom, відповідний до панелі, яка за замовчуванням містить тільки кнопку довідки). Надалі в будь-який момент командою View - Toolbars ви можете знову відновити установку індикатору й панель стане видимою.
Розділ меню Customize дозволяє настроїти склад окремих панелей. Такі ж настроювання можна здійснити, вибравши аналогічний розділ з контекстного меню, яке з'являється, якщо ви клацнете на панелі правою кнопкою миші.
 
Настроювання палітри компонентів
Викликати настроювання палітри компонентів можна клацанням правої кнопки миші на палітрі й вибором команди Properties з випливаю чого меню. Можна виконати для цього команду Component - Configure Palette. Можна також виконати команду Tools - Environment Options. При такому виклику настроювання треба перейти в діалоговім вікні на сторінку Palette.
Опції вікна дозволяють працювати зі сторінками палітри. Для цього треба перейти у вікно Pages і нажати кнопку Add, щоб додати нову сторінку, кнопку Rename, щоб перейменувати сторінку, кнопку Delete, щоб видалити сторінку (вона повинна бути до цього моменту порожньої), кнопки Move Up або Move Down, щоб змінити послідовність сторінок у палітрі. Втім, послідовність простіше змінювати, просто перетаскуючи мишею в лівій панелі сторінку на нове місце в списку.
Перейшовши у вікно Components, ви можете змінювати склад сторінок, перетаскуючи мишею компонентів з однієї сторінки на іншу або роблячи кнопкою Hide якісь компоненти невидимими.
 
Настроювання Інспектора Об'єктів
Для настроювання треба виконати команду Tools - Environment Options і потім перейти на сторінку Object Inspector.
Список Speedsettings дозволяє провести швидке настроювання Інспектора Об'єктів на один зі стилів: Custom (замовлений), Default (за замовчуванням), Delphi 5 (як в Delphi 5), Visual Studio (як в Visual Studio). Втім, при будь-якому стилі ви можете зробити настроювання окремих властивостей Інспектора Об'єктів. Якщо вам не сподобалася зроблене вами настроювання, ви можете в будь-який момент повернутися до настроювання, вибравши стиль Default.
 
Загальні настроювання середовища
Багатосторінкове вікно настроювання викликається командою Tools - Environment Options.
Сторінка Preferences – це сторінка загальних настроювань середовища проектування в Delphi. Зверніть увагу на сторінці Preferences на опції, що визначають, що зберігається при виході з Delphi - розділ Desktop contens, і опції Autosave options.
Якщо ви включите опцію Project Desktop, то при черговому запуску Delphi завантажиться ваш останній проект і відкриються всі вікна, які були відкриті в момент виходу з Delphi. Це дуже зручно, якщо ви маєте намір продовжувати роботу над тим же проектом. При включенні цієї опції конфігурація вікон запам'ятовується також у кожному проекті, тому якщо ви згодом відкриєте якийсь проект, з яким працювали раніше, те відновиться конфігурація всіх вікон, які були відкриті в момент закінчення роботи.
Сторінка Designer містить опції, що визначають сітку форми і ярлички компонентів. (початок) 
Питання для самоконтролю
1. Які типи файлів можуть використовуватися в проектах Delphi? Наведіть їх розширення й дайте характеристику
2. Опишіть принципи створення нового проекту, збереження проекту. Які способи відкриття проекту ви знаєте? Як настроїти середовище Delphi на автоматичне відкриття останнього проекту?
3. Що таке облікова інформація проекту? Як її настроїти? Для чого потрібна палітра компонентів Delphi? Як її можна настроїти?
4. Що таке інспектор  об'єктів у середовищі Delphi? Як його настроїти? Опишіть як виконати загальні настроювання середовища розробки Delphi?
Лекція № 3
 
Тема: «Форми, діалоги»
План
1. Поняття форми2. Робота з формами3. Властивості, методи й події форм4. Проектування вікон зі змінюваними розмірами5. Процедури й функції виклику діалогових вікон 
1. Поняття форми
Основним елементом будь-якого додатка є форма - контейнер, у якому розміщаються інші візуальні й невізуальні компоненти. З погляду користувача форма - це вікно, у якому він працює з додатком. Кожній новій формі, що вводиться в додаток, відповідає свій модуль (Unit), що описує цю форму як клас, якісь додаткові константи, змінні, функції й процедури. Розглянемо деякі властивості, методи й події форм.
Звичайно скільки-небудь складний додаток містить кілька форм. Головна форма відрізняється від інших рядом властивостей. По-перше, саме цій формі передається управління на початку виконання додатка. По-друге, закриття користувачем головної форми означає завершення виконання додатка. Головною у вашому додатку може бути зовсім не та форма, яка була спроектована першої.
Змінити прийняті за замовчуванням умови щодо форм можна у вікні опцій проекту, яке викликається командою Project - Options. У вікні опцій проекту (Project Options) треба вибрати сторінку Forms. У верхньому списку Main forms можна вибрати головну форму серед наявних у проекті.
Відкриття форм як модальних використовується в більшості діалогових вікон. Модальна форма припиняє виконання процедури, що її викликала, доти, поки користувач не закриє цю форму. Модальна форма не дозволяє також користувачеві перемкнути фокус курсором миші на інші форми даного додатка, поки форма не буде закрита. Тобто користувач повинен виконати запропоновані йому дії перш, ніж продовжити роботу. (початок) 
2. Робота з формами
У багатьох випадках ваш проект буде містити не одну, а кілька форм. Крім того, ви, може бути, захочете прибрати з нового проекту порожню форму й включити замість неї іншу, розроблену раніше вами або кимось іншим. Наприклад, якщо ви для якогось свого проекту розробили форму, що запитує пароль користувача, або форму з інформацією про програму й вашим красивим логотипом, то не має смислу в новому проекті створювати їх заново. Форму з паролем ви могли б взяти з минулого додатка взагалі без яких-небудь змін, а у формі інформації про програму вам досить змінити тільки ім'я програми.
Для всіх форм, що включаються в проект, навіть якщо у вашім проекті всього одна форма, задавайте унікальні імена (властивість Name), змінюючи встановлені Delphi за замовчуванням. Це суттєво полегшить вам повторне використання ваших форм, тому що дозволить уникнути дублювання імен при включенні колишньої форми в новий проект.
 
Включення в проект форм
Включення в проект нової форми може проводитися різними способами.
Якщо ви прагнете включити нову порожню форму, вам досить виконати команду File - New - Form або натиснути відповідну швидку кнопку.
Тепер розглянемо випадок, коли вам потрібно включити у свій проект форму, розроблену раніше вами або кимось ще для іншого проекту. Отут можливі кілька варіантів дій, що мають різні наслідки.
Можна включити готову форму в проект командою Project - Add to Project або відповідної швидкою кнопкою. При цьому, якщо форма, що включається, має те ж ім'я, яке має одна із уже наявних у проекті форм (наприклад, Form1, якщо ви не звикли змінювати імена форм, прийняті Delphi за замовчуванням), те ви отримаєте попередження виду: "The project already contains a form or module named Form1" (Проект уже містить форму або модуль із іменем Form1). У результаті форма відкриється, але в проект не включиться.
Урахуйте, що форма, що міститься в одному додатку й включена описаним способом в інший додаток, стає загальною для обох додатків. Якщо ви зробите в ній якісь зміни, а потім перекомпілюєте обидва додатка, то внесені зміни відіб'ються на обох додатках.
Cпільне володіння кількома додатками однієї й тою же формою має свої плюси й мінуси.
 
Створення окремої копії форми
Щоб уникнути спільного володіння формою декількома додатками, після того, як ви включили в новий додаток форму з іншого додатка, перейдіть у вікно Редактора Коду в модуль цієї форми й виконайте команду File - Save As, зберігши модуль у каталозі нового додатка й, якщо хочете, під іншим ім'ям (ім'я змінювати не обов'язково). У цьому випадку різні додатки будуть використовувати зовсім різні копії однієї форми й зміни однієї з них не торкнуться інших додатків. (початок) 
3. Властивості, методи й події форм
Кожна форма в Delphi має набір властивостей, методів і подій.
Властивості форми задають її зовнішній вигляд і поведінку. Задавати властивості форми можна при проектуванні або в коді програми за допомогою команди:
 
ім'я_форми.властивість:=значення;
 
Наведемо список найбільш використовуваних властивостей форми
 
Властивість Опис
Align Задає вирівнювання форми на екрані. Може або прив'язати форму до краю екрана ( altop- до верхнього краю; albottom- до нижнього краю; alleft- до лівого краю; alright- до правого краю; alclient-розтягує форму на весь екран; alcustom-форма розміщається там, де її встановили при проектуванні й не може бути переміщена)
Alphablend При значенні true використовує ступінь прозорості форми, задану властивістю Alphablendvalue. Спрацьовує в системах, починаючи з Windows 2000, для процесорів, починаючи з Pentium 90.
AlphaBlendvalue Визначає при Alphablend = true ступінь прозорості форми. При значенні 255 виходить звичайна непрозора форма; при значенні 0 форма зовсім не видима. Якщо треба зробити прозорими окремі області форми, слід використовувати властивості Transparentcolorvalue і Transparentcolor.
Autoscroll Значення true, прийняте за замовчуванням, визначає, що якщо при обраному користувачем розмірі вікна не всі компоненти поміщаються в ньому, на формі будуть у процесі виконання автоматично з'являтися смуги прокручування. При значенні false, зменшуючи розмір вікна, користувач може втратити доступ до компонентів, що не помістилися в його клієнтській області.
Autosize Значення true визначає, що розмір форми автоматично підганяється під розмір наявних компонентів
Borderlcons Визначає перелік кнопок в заголовку вікна форми.
Borderstyle Визначає стиль бордюру форми й можливість користувача змінювати розмір форми.
Caption Назва форми, відображається в заголовку вікна
Clientheight Висота клієнтської області форми в пікселях.
Clientwidtht Горизонтальний розмір клієнтської області форми в пікселях.
Color Колір фона форми
Cursor Покажчик миші при наведенні на форму
Enabled Значення true визначає, що доступ до форми дозволений
Font Параметр шрифту для всіх компонентів форми
Height Висота форми в пікселях
Hint Текст спливаючої підказки
Icon Визначає піктограму, яка буде відображатися при згортанні вікна форми. Якщо піктограма не задана, за замовчуванням буде відображатися піктограма Delphi.
Left Відстань форми від лівого краю екрана в пікселях
Name Ім'я форми, по якому до форми можна звернутися в коді програми
Position Визначає розмір і положення вікна при запуску додатка.
Screensnap Введене в Delphi 7, забезпечує захоплення форми при її переміщенні до краю екрана: якщо користувач переміщає вікно форми, наближаючи його до краю екрана на відстань, менше Snapbuffer, то при відпусканні її форма зрушиться так, що буде притиснута до відповідного краю екрана.
Snapbuffer Введене в Delphi 7, визначає відстань у пікселях, яке викликає захоплення форми при її переміщенні до краю екрана при Snapbuffer = true
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Top Відступ форми від верхнього краю екрана в пікселях
TransparentColor При значенні true робить прозорим колір, зазначений властивістю Transparentcolorvalue.
TransparentColorvalue Указує колір на формі й у компонентах, який робиться прозорим при Transparentcolor = true. Наприклад, можна розмістити на формі панель, установити в ній Color = clred, задати у формі Transparentcolorvalue = clred і встановити Transparentcolor в true. На формі під час виконання з'явиться прозоре вікно. А якщо ви при цьому встановите для форми Color = clred, те стане прозорою клієнтська область форми й буде видна тільки смуга заголовка й компоненти, пофарбовані в інші кольори. Властивість працює, тільки починаючи з Windows 2000. Для того щоб регулювати прозорість усієї форми, використовуйте властивості Alphablend і АlphaBlendValue.
Visible Визначає видимість форми. За замовчуванням рівно false, але для головної форми додатка в момент її створення робиться рівним true. Якщо ви програмно встановите в деякий момент Visible для головної форми рівним false, то форма зникне з екрана, зі смуги завдань і навіть із диспетчера завдань Windows (залишиться тільки в диспетчерові завдань на сторінці процесів). 
Width Ширина форми в пікселях
Windowstate Визначає стан вікна: wsnormal – нормальне, wsminimized – згорнуте, wsmaximized – розгорнуте на весь екран.
 
Методи форми визначають дії, які можна виконає над формою. Для виклику потрібного методу використовують команду:
 
ім'я_форми.метод;
 
Приведемо перелік методів форм
 
Метод Опис
Close Закриває вікно форми. Якщо метод застосовується до головної форми додатка, додаток завершується. Закривання вікна може бути перерване в оброблювачах подій ОnCloseQuery і Onclose.
Getformimage Повертає зображення клієнтської області форми. Це зображення можна, наприклад, занести в буфер обміну оператором Clipboard.Assign(Getformimage) і потім перенести в якийсь документ, наприклад, у документ Word.
Free Закриває форму й звільняє займану нею пам'ять.
Hide Робить форму невидимої, установлюючи значення її властивості Visible в false. Форма в момент застосування методу повинна мати значення Visible = true.
Print Друкує клієнтську область форми, заносячи її образ, отриманий методом Getformimage, у контекст принтера.
Release Закриває форму й звільняє займану нею пам'ять. Для форми генеруються всі події, властиві формі, що закривається. Для форм треба використовувати саме цей метод, а не метод Free.
Setfocus Передає фокус формі і її активному компоненту.
Show Робить форму видимою
Showmodal Робить форму видимою й модальною.
 
Форма, як і будь-який об'єкт, може реагувати на події, які генеруються користувачем або іншими об'єктами програми. Для кожної такої події можна написати підпрограму, яка виконається при настанні події.
Приведемо події форми.
 
Подія Опис
Onactivate Подія наступає, коли форма стає активною, тобто одержує фокус, наприклад, при клацанні на ній.
Onclose Подія наступає при закритті форми після події Onclosequery. В оброблювачі можна вказати, що розуміється під закриттям форми, або скасувати закриття.
Onclosequery Перша подія при закритті форми. У його оброблювачі можна перервати закриття
Oncreate Перша подія при створенні форми. У його оброблювачі можна настроїти форму і її компоненти.
Ondeactivate Подія наступає, коли форма перестає бути активної, тобто втрачає фокус
Ondestroy Остання подія при закриванні форми й видаленні її з пам'яті. У його оброблювачі слід очистити пам'ять від об'єктів, створених в оброблювачі Oncreate.
Onhide Подія настає перед тим, як форма стає невидимою.
Onpaint Подія настає перед промальовуванням форми.
Onresize Подія настає щораз, коли форма змінює свій розмір
Onshow Подія настає перед тем, як форма стає видимою.
 
Часто програма складається з множини форм, і форми звертаються одна до одної. Кожна форма має власний файл модуля, у якому зберігається її опис і всі її підпрограми.
Щоб одна форма могла посилатися на іншу форму необхідно підключити модуль потрібної форми в розділі Uses.
Для цього використовують кілька способів:
перейдіть у код форми й після ключового слова Implementation додайте команду
виконаєте команду File – Use Unit і в списку виберіть ім'я модуля, який належить формі, на яку ви прагнете послатися (початок)4. Проектування вікон зі змінюваними розмірами
Вирівнювання компонентів - властивість Align
Якщо проектується вікно, розміри якого користувач може змінювати під час виконання додатка, то необхідно вжити заходів, щоб компоненти у вікні при цьому теж змінювали свої розміри або місце розташування, рівномірно розподіляючись по площі вікна й не залишаючи порожніх місць.
У багатьох компонентів є властивість Align – вирівнювання. За замовчуванням воно рівно alnone. Це означає, що ніяке вирівнювання не здійснюється. Але його можна задати рівним аltор, або albottom, або alleft, або alright, що буде означати, що компонент повинен займати всю верхню або нижню, або ліву, або праву частину клієнтської області компонента-контейнера. Під клієнтською областю розуміється вся вільна площа форми або іншого контейнера, у якій можуть розміщатися включені в цей контейнер компонента. Можна також задати властивості Align компонента значення alclient, що приводить до заповнення компонентом усієї вільної клієнтської області. У всіх цих випадках розміри компонента будуть автоматично змінюватися при зміні розмірів контейнера.
 
Зміна місця розташування й розмірів компонентів
Віконні компоненти Delphi мають властивість Anchors - прив'язку до батьківського компонента при зміні розмірів останнього. Ця властивість являє собою множину, яка може містити наступні елементи:
 
акТор Верхній край компонента прив'язаний до верхнього краю батьківського компонента.
akleft Лівий край компонента прив'язаний до лівого краю батьківського компонента.
akright Правий край компонента прив'язаний до правого краю батьківського компонента.
akbottom Нижній край компонента прив'язаний до нижнього краю батьківського компонента.
 
Якщо в множині Anchors присутні прив'язки до протилежних сторін батьківського компонента, то при зміні розмірів батьківського компонента відбувається розтягання або стиснення дочірнього компонента, оскільки відстані від сторін батьківського компонента витримуються. Стиснення може відбуватися аж до повного зникнення зображення даного компонента.
За замовчуванням прив'язка здійснюється до лівого й верхньому краям батьківського компонента. Т.ч. за замовчуванням властивість Anchors рівно [akleft, aktop]. Якщо задати у властивості Anchors прив'язку до протилежних сторін батьківського компонента, то при зміні розмірів батьківського компонента будуть мінятися розміри й даного компонента.
 
Обмеження меж зміни розмірів вікон і компонентів
Усі розглянуті раніше методи зміни розмірів панелей і компонентів на них мають загальний недолік: при надмірному зменшенні користувачем розмірів вікна якісь компоненти можуть зникати з поля зору. Іноді до некрасивих з погляду естетики результатам приводить і надмірне збільшення розмірів вікна. Хотілося б мати засоби, що обмежують користувача в його маніпуляціях з вікном й не дозволяють йому надмірно зменшувати й збільшувати розміри вікна.
Таким засобом є властивість Constraints, що дозволяє задавати обмеження на припустимі зміни розмірів. Властивість має чотири основні підсвойства: Maxheight, Maxwidth, Minheight і Minwidth - відповідно максимальна висота й ширина й мінімальна висота й ширина. За замовчуванням значення всіх цих підсвойств рівні 0, що означає відсутність обмежень. Але завдання кожному із цих властивостей позитивного значення приводить до відповідного обмеження розміру заданим числом пікселів.
Щоб якісь компоненти не зникали з поля зору, можна задати їм обмеження мінімальної висоти й довжини. Таким чином, можна підтримувати нормальні пропорції окремих частин вікна. Можна задати обмеження на мінімальні й максимальні розміри форми, тобто всього вікна. (початок) 
5. Процедури й функції виклику діалогових віконПроцедури Showmessage
У додатках часто доводиться відображати різні прості діалогові вікна, щоб дати користувачеві якісь вказівки або поставити нескладне запитання, на яке можливий один зі стандартних відповідей: так, ні, відмінити, перервати. У закінченому додатку бажано ці вікна проектувати самому, забезпечуючи єдність стилю всіх вікон додатка, написи на кнопках і т.п. Але при розробці прототипу майбутнього проекту й у процесі налагодження зручно користуватися готовими діалоговими вікнами.
Найпростішої з таких процедур є Showmessage, що відображає вікно повідомлення із кнопкою ОК. Вона має вигляд:
 
showmessage(текст);
 
Команда видає модальне вікно з текстом і кнопкою ОК. Заголовок вікна збігається з іменем виконуваного файлу додатка.
Команда може видати текстову константу:
 
showmessage(‘добрий ранок’);
 
При видачі числового значення його потрібно попередньо конвертувати в текст за допомогою спеціальних функцій:
 
inttostr(ціле число)
floattostr(речовинне число)
 
Приклад.
var a:integer; b:real;
begin
    a:=15;
    b:=12.36;
    showmessage(‘a=’+intotstr(a));
    showmessage(‘b=’+floattostr(b));
 
Метод Tapplication.Messagebox
Метод оголошений у такий спосіб:
 
application.messagebox(текст, заголовок, прапорці)
 
Він відображає діалогове вікно із заданими кнопками, повідомленням і заголовком і дозволяє проаналізувати відповідь користувача.
Параметр Текст являє собою текст повідомлення, яке не може перевищувати 255 символів. Для довгих повідомлень здійснюється автоматичний перенос тексту. Параметр Заголовок являє собою текст заголовка вікна. Він теж не може перевищувати 255 символів, але не переноситься. Так що довгий заголовок приводить до появи довгого й не дуже гарного діалогового вікна.
Параметр Прапорці являє собою безліч прапорців, що визначають вигляд і поведінку діалогового вікна. Цей параметр може комбінуватися операцією додавання по одному прапорцю з наступних груп.
 
Прапорці кнопок
Прапорець Значення
MB_ABORTRETRYIGNORE Кнопки Abort (Стоп), Retry (Повтор) і Ignore (Пропустити)
МВ_ОК Кнопка ОК. Цей прапорець прийнятий за замовчуванням
MB_OKCANCEL Кнопки ОК і Cancel (Скасування)
MB_RETRYCANCEL Кнопки Retry (Повтор) і Cancel (Скасування)
MB_YESNO Кнопки Yes (Так) і No (Немає)
MB_YESNOCANCEL Кнопки Yes ( До), No (Немає) і Cancel (Скасування)
 
Прапорці піктограм у діалоговому вікні
Прапорець Піктограма
MB_ICONEXCLAMATION, MB_ICONWARNING Знак оклику (зауваження, попередження)
MB_ICONINFORMATION,MB_ICONASTERISK Літера «I» у колі (підтвердження)
MB_ICONQUESTION Знак запитання (очікування відповіді)
MB_ICONSTOP,MB_ICONERROR, MB_ICONHAND Знак хреста на червоному колі (заборона, помилка)
 
Прапорці, що вказують кнопку за замовчуванням
Прапорець Кнопка
MB_DEFBUTTONl Перша кнопка. Це прийняте за замовчуванням
MB_DEFBUTTON2 Друга кнопка
МВ_ DEFBUTTON3 Третя кнопка
MB_DEFBUTTON4 Четверта кнопка
 
Прапорці модальності
Прапорець Пояснення
MB_APPLMODAL Користувач повинен відповісти на запит, перш ніж зможе продовжити роботу з додатком. Але він може перейти у вікна іншого додатка. Він може також працювати зі спливаючими вікнами даного додатка. Цей прапорець прийнятий за замовчуванням
MB_ SYSTEMMODAL Те ж саме, що MB APPLMODAL, але вікно діалогу відображається в стилі WS_EX_TOPMOST, тобто завжди залишається поверх інших вікон, навіть якщо користувач перейшов до інших додатків. Використовується для попередження про серйозні помилки, що вимагають негайного втручання
 
Якщо функція використовується для видачі запиту, то проаналізувати відповідь користувача можна за допомогою констант:
 
Значення Чисельне значення Пояснення
IDABORT 3 Обрана кнопка Abort (Стоп)
IDCANCEL 2 Обрана кнопка Cancel (Скасування) або натиснута клавіша Esc
IDIGNORE 5 Обрана кнопка Ignore (Пропустити)
IDNO 7 Обрана кнопка No (Немає)
IDOK 1 Обрана кнопка ОК
IDRETRY 4 Обрана кнопка Retry (Повтор)
IDYES 6 Обрана кнопка Yes (Так)
 
Наприклад, при виході із програми часто видається запит на підтвердження даної операції. Для видачі такого запиту потрібно в події форми Closequery ввести код:
 
if application.messagebox (‘вийти?’, ’запит’, mb_yesno+mb_iconquestion+ mb_defbutton2) = idno then
    canclose:=false;
 
Функція введення даних із клавіатури Inputbox
 
inputbox (‘заголовок’, ‘ текст-підказка’, ‘значення за замовчуванням’)
 
Функція Inputbox пропонує користувачеві діалогове вікно із заголовком, із пропозицією користувачеві щось написати й з віконцем редагування, у якому попередньо завантажене значення тексту за замовчуванням. Якщо користувач натисне у вікні ОК, то функція поверне введену їм рядок тексту. Якщо ж користувач у діалозі натиснув Cancel, або нажав Esc, або закрив вікно системною кнопкою, то функція поверне рядок за замовчуванням, навіть якщо перед цим користувач щось написав у віконці редагування.
Для виклику функції потрібно описати строкову змінну й привласнити їй функцію:
 
var name:string;
. . .
name:= inputbox('реєстрація’, 'укажіть мету вашого приїзду', 'невідома'); (початок) 
Питання для самоконтролю
1. Опишіть принципи роботи з формами в проекті: додавання, видалення, завдання головної форми проекту. Що означає поняття «головна форма проекту»?
2. Які властивості форми ви знаєте? Дайте характеристику основним з них. Як задати властивості форми?
3. Які методи форми ви знаєте? Як викликати метод форми? Які події форми ви знаєте? Як написати оброблювач для потрібної події?
4. Які властивості дозволяють організувати масштабування компонентів при зміні розміру форми? Дайте їхню характеристику
5. Опишіть команду видачі повідомлень на екран і команду введення даних із клавіатури. Приклади
6. Опишіть функцію messagebox. Приведіть усі її параметри й приклад використання.
Лекція № 4
Тема: «Компоненти відображення й уведення текстової інформації»
 
План
1. Відображення тексту на формі2. Вікна редагування3. Керуючі кнопки Button і Bitbtn4. Приклад програми для розрахунків виразу5. Розміщення компонентів на формі 
1. Відображення тексту на формі
У бібліотеці візуальних компонентів Delphi існує безліч компонентів, що дозволяють відображати, уводити, редагувати текстову інформацію. Для відображення різних написів (міток) на формі використовується в основному компонент Label (Standard).
Компонент має властивості:
 
Властивість Опис
Alignment Вирівнювання тексту
Autosize Якщо рівно true, то розмір напису підганяється під розмір тексту
Color Колір фона
Cursor Покажчик миші при наведенні на мітку
Enabled Якщо рівно true, то напис доступний
Font Параметри форматування шрифту
Height Висота в пікселях
Hint Текст спливаючої підказки
Left Відступ від лівого краю форми в пікселях
Name Ім'я напису для звертання до нього в коді програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Top Відступ від верхнього краю форми в пікселях
Transparent Якщо рівно true, то фон в напису буде прозорим
Visible Якщо рівно true, то напис видимий на формі
Width Ширина напису в пікселях
Wordwrap Якщо рівно true, то текст напису може автоматично переходити на новий рядок
 
Більшість властивостей можна задати як при проектуванні, так і в коді за допомогою команди:
 
ім'я_надписи.властивість:=значення;
 
Можна відзначити ще одну властивість компонента Label, що перетворює його в подобу керуючого елемента. Ця властивість Focuscontrol. Якщо у властивості мітки Caption помістити перед одним із символів символ амперсанд «&», то символ, перед яким поставлений амперсанд, відображається в написі мітки підкресленим (сам амперсанд взагалі не відображається). Якщо після цього звернутися до властивості мітки Focuscontrol, то зі списку можна вибрати елемент, на який буде перемикатися фокус, якщо користувач натисне клавіші прискореного доступу: клавішу Alt + підкреслений символ. Завдяки властивості Focuscontrol мітки можуть забезпечити клавішами прискореного доступу інші елементи, наприклад, ті вікна редагування, у яких такі клавіші не передбачені. Тільки для того, щоб клавіші прискореного доступу в мітках спрацьовували, необхідно встановити властивість Showaccelchar цих міток в true. (початок) 
2. Вікна редагування
Для введення даних із клавіатури на формі можна розміщати спеціальні компоненти: Edit (Standard) або Labelededit (Additional).
Ці компоненти являють собою вікна, у яких відображається курсор і можна вводити інформацію. Вікна редагування наділені багатьма функціями, властивими більшості редакторів. Наприклад, у них передбачені типові комбінації гарячих клавіш: Ctrl-C - копіювання виділеного тексту в буфер обміну Clipboard (команда Copy), Ctrl-X - вирізання виділеного тексту в буфер Clipboard (команда Cut), Ctrl-V - вставка тексту з буфера Clipboard у позицію курсору (команда Paste), Ctrl-Z - скасування останньої команди редагування. Ці ж команди автоматично доступні з контекстного меню компонентів.
Компонент Edit має властивості:
 
Властивість Опис
Autoselect Якщо рівно true, то при переході в поле в ньому автоматично виділяється весь текст
Autosize Якщо рівно true, то висота поля підганяється під розмір тексту (ширина не змінюється)
Borderstyle Задає тип границі навколо поля
Charcase Автоматично форматує текст на верхній або нижній регістр
Color Задає колір фона поля
Cursor Задає покажчик миші
Enabled Якщо рівно true, то доступ до поля дозволений
Font Задає параметри форматування тексту
Height Висота поля в пікселях
Hint Текст спливаючої підказки
Left Відступ поля від лівого краю форми в пікселях
Maxlength Максимальна довжина поля в символах. Якщо рівно 0, то необмежене
Name Ім'я поля для звертання до нього в тексті програми
Passwordchar Задає символ, який буде підставлятися замість символів, що вводяться. Аналог поля для введення пароля
Readonly Якщо рано true, то поле блокується для редагування
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB. Нумерація компонентів починається з 0
Tabstop Якщо рівно false, то перехід на поле клавішею TAB буде неможливий
Text Зберігає вміст поля. Може бути прочитане в тексті програми
Top Відступ поля від верхнього краю форми в пікселях
Visible Якщо рівно true, то поле видиме
Width Ширина поля в пікселях
 
У поля також є властивості, доступні тільки при написанні коду:
 
Властивість Опис
Modified Якщо рівно true, вміст поля змінювався
Selstart Номер символу, з якого потрібно виділити текст
Sellength Кількість символів, які потрібно виділити в поле
Seltext Дозволяє прочитати виділений текст
 
Наприклад, якщо у вікні є текст «виділення тексту» і в ньому користувач виділив слово «тексту», то Sellength = 6, Selstart = 10 і Seltext = «тексту».
Вікна редагування можна використовувати й просто як компоненти відображення тексту. Для цього треба встановити в false їх властивість Readonly і доцільно встановити Autoselect в false. У цьому випадку користувач не зможе змінювати відображуваний текст, і вікно редагування стає подібним до міток, розглянутих вище. Але є й певні відмінності. По-перше, вікна редагування оформлені трохи інакше. А головне - вікна редагування можуть уміщати текст, що перевищує їхню довжину. У цьому випадку користувач може прокручувати цей текст, переміщаючи курсор у вікні. Таких особливостей не має жодна мітка.
Вміст полів завжди зберігається як текст. Якщо в полі вводяться цифри, то для використання їх у розрахунках потрібно конвертувати вміст полів у числа за допомогою функцій:
 
strtofloat (поле.text) - перетворення рядка в речовинне значення
strtoint (поле.text) - перетворення рядка в ціле значення.
 
Компонент Labelededit, крім самого вікна редагування, має мітку. Вона задається властивістю Editlabel. Ця властивість має всі основні властивості, властиві мітці Label.
Властивість Labelposition компонента Labelededit указує, з якої сторони від вікна розміщається мітка: lpabove – зверху, вирівняна по лівому краю, lpbelow – знизу, вирівняна по лівому краю, lpleft – ліворуч, lpright – праворуч.
У цілому, компонент Labelededit дуже зручний і, імовірно, може замінити вікна Edit у більшості додатків, оскільки рідко потрібне вікно редагування без его мітки. (початок) 
3. Керуючі кнопки Button і Bitbtn
Кнопка – це один з найбільш використовуваних компонентів у програмах. За допомогою кнопок користувач може генерувати події, які викликають виконання певних підпрограм.
Найпростішої й, мабуть, найбільше часто використовуваною кнопкою є кнопка Button (Standard). Рідше використовується кнопка Bitbtn (Additional), що відрізняється, насамперед, можливістю відобразити на її поверхні зображення. Більшість властивостей, методів і подій у цих видів кнопок однакові.
 
Властивість Опис
Cancel Якщо рівно true, кнопка реагує на клавішу ESC
Caption Задає текст напису на кнопці. Допускається використання символу &
Cursor Задає покажчик миші при наведенні на кнопку
Default Якщо рівно true, то кнопка реагує на клавішу ENTER
Enabled Якщо рівно true, то кнопка доступна
Font Задає параметри шрифту для кнопки
Height Задає висоту кнопки в пікселях
Hint Задає текст спливаючої підказки
Left Задає відступ кнопки від лівого краю форми в пікселях
Name Задає ім'я кнопки для звертання до неї в коді програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на кнопку клавішею TAB
Tabstop Якщо рівно false, то перехід на кнопку клавішею TAB буде заборонений
Top Задає відступ кнопки від верхнього краю форми в пікселях
Visible Якщо рівно true, то кнопки видима
Width Задає ширину кнопки в пікселях
Wordwrap Якщо рівно true, то напис на кнопці автоматично переходить на новий рядок
 
Усе сказане вище рівною мірою відноситься й до компонента Bitbtn. Даний компонент також є кнопкою, але на ній може відображатися малюнок. Зображення на цій кнопці задається властивістю Glyph. При натисканні кнопки із трьома крапками в рядку властивості Glyph з’являється вікно. Нажавши в ньому кнопку Load, ви перейдете у звичайне вікно відкриття файлу малюнка й можете вибрати файл бітової матриці .bmp, що містить бажане зображення. Зокрема, з Delphi поставляється велика кількість зображень для кнопок. Вони розташовані в каталозі C:\Program Files\Common Files\BorlandShared\Images\Buttons. Після того, як ви вибрали зображення, натисніть ОК і обране зображення з'явиться на вашій кнопці лівіше напису.
Розташування зображення й напису на кнопці визначається властивостями Margin, Layout і Spacing. Якщо властивість Margin рівно -1 (значення за замовчуванням), то зображення й напис розміщаються в центрі кнопки. При цьому положення зображення стосовно напису визначається властивістю Layout, яке може приймати значення: blglyphleft (ліворуч, це значення прийняте за замовчуванням), blglyphright (праворуч), blglyphtop (угорі), blglyphbottom (унизу). Якщо ж Margin > 0, то залежно від значення Layout зображення й напис зміщаються до тієї або іншій край кнопки, відступаючи від неї на число пікселів, задане значенням Margin.
Властивість Spacing задає число пікселів, що розділяють зображення й напис на поверхні кнопки. За замовчуванням Spacing = 4. Якщо задати Spacing = 0 зображення й напис будуть розміщений впритул друг до друга. Якщо задати Spacing = -1, то текст з'явиться посередині між зображенням і краєм кнопки.
Ще одна властивість Bitbtn – властивість Kind визначає тип кнопки. За замовчуванням значення цієї властивості рівно bkcustom - замовлена. Але можна встановити й безліч інших визначених типів: bkok, bhcancel, bkhelp, bkyes, bkno, bkclose, bkabort, bkretry, bklgnore, bkall. У цих типах уже зроблені відповідні написи, уведені піктограми, задані ще деякі властивості.
Основною подією для кнопки є подія Onclick, яка наступає при клацанні на кнопці. Для написання оброблювача цієї події клацніть на кнопці два рази й у заготовці процедури введіть потрібні команди. (початок) 
4. Приклад програми для розрахунків виразу
Нехай є форма вигляду:
 

 
Кнопка Розрахувати (Button1) підсумовує значення двох перші полів (Edit1 і Edit2) і записує відповідь у третє поле (Edit3). Перед розрахунком видати запит на виконання операції.
Для кнопки Розрахувати напишемо код:
 
procedure tform1.button1click(sender: tobject);
//опишемо допоміжні змінні
var a,b,c:real;
begin
//видаємо запит на виконання розрахунків
if application.messagebox ('розрахувати?', 'запит', mb_yesno+ mb_iconquestion) = idyes then
//якщо на запит користувач відповів да
begin
//конвертуємо вміст полів у числа
a:=strtofloat(edit1.text);
b:=strtofloat(edit2.text);
// підсумуємо значення полів
c:=a+b;
//записуємо відповідь у третє поле
edit3.text:=floattostr(c);
end;
end;
 
Кнопка Очистити очищає вміст усіх полів. Видати запит на виконання операції.
Для кнопки Очистити напишемо код:
 
procedure tform1.button2click(sender: tobject);
begin
//видаємо запит на виконання операції
if application.messagebox ('очистити?','запит', mb_yesno+mb_iconquestion)=idyes then
//якщо на запит користувач відповів да
begin
//очищаємо поля
edit1.text:='';
edit2.text:='';
edit3.text:='';
end;
end;
 
При виході із програми видати запит на виконання операції. Для видачі запиту на закриття програми в події форми Onclosequery напишемо код:
 
procedure tform1.formclosequery(sender: tobject; var canclose: boolean);
begin
if application.messagebox('вийти?','запит',mb_yesno)=idno then
canclose:=false;
end; (початок) 
5. Розміщення компонентів на формі
Для того щоб перенести на форму компонентів, треба відкрити відповідну сторінку палітри компонентів і знайти на ній потрібний компонент. У пошуку вам дуже допоможуть ярлички, що з'являються, якщо ви затримуєте курсор над тієї або іншою піктограмою. Виділіть курсором потрібний вам компонент, а потім клацніть мишею в тому місці форми, куди ви хочете помістити компонент. Можливий і інший варіант – подвійне клацання на компоненті. Тоді компонент перенесеться в центр форми, а потім ви можете його відбуксирувати в потрібне місце.
Іноді ви знаєте ім'я компонента, але не пам'ятайте, на якій сторінці він розташований і не можете його знайти. У цьому випадку вам може допомогти команда View – Component List. При її виконанні вам відкриється діалогове вікно, що містить алфавітний список усіх компонентів. У ньому ви можете знайти потрібний компонент по імені. У цьому вам може допомогти вікно швидкого пошуку по імені Search by name. По міру набору в ньому перших символів імені покажчик переміщається на відповідні розділи списку. Вибравши потрібний компонент, ви можете нажати кнопку Add to form унизу вікна або зробити подвійне клацання на обраному компоненті, і він перенесеться на форму. Якщо ви не упевнені, чи той компонент знайшли, натисніть клавішу F1, і вам буде показана довідка по виділеному компоненту.
Вилучити помилково перенесений на форму компонент дуже просто: виділіть його й натисніть клавішу Delete.
Привчіть себе відразу при переносі компонента на форму змінювати його ім'я Name, прийняте за замовчуванням. Ім'я повинне бути осмисленим, щоб потім, розбираючись у коді, ви легко могли б зрозуміти, що означає та або інша процедура, той або інший компонент. Тим самим ви заощадите собі багато часу. Уявіть собі простеньку форму, де є десяток кнопок, десяток міток і пара десятків розділів меню. Запевняю вас, що якщо ви не дасте компонентам осмислені імена, то дуже скоро ви почнете болісно міркувати, що ж це за кнопка Button7, клацання якої ви обробляєте в даній процедурі, і чому в процедурі задається якесь значення напису невідомо де розташованої мітки Label3. А вже на пошуки таємничого розділу меню N18 ви точно витратите чимало часу. Так що любіть себе, давайте компонентам зрозумілі вам імена.
Переносячи компонент на форму, ви можете буксирувати його в потрібне місце, можете змінювати його розміри. Для цього виділіть потрібний елемент. Він стане оточений рамкою з маркерами. Потягніть курсором за один з маркерів і розмір компонент буде змінюватися. При цьому є зручний механізм інформації про імені й розмірах компонента. При затримці курсору над компонентом з'являється ярличок з його іменем, а при натисканні кнопки миші на компоненті, при його буксируванні або зміні розмірів з'являється ярличок з розмірами компонента.
 
Батьки й власники компонентів - Parent і Owner
Часто компоненти розміщаються не безпосередньо на формах, а на панелях компонентів, які візуально поєднують групи компонентів по їхньому призначенню. У цьому випадку спочатку на формі повинні бути розміщені панелі, а потім на них розташовуються компоненти.
Віконний компонент - форма, панель і т.д. контейнер, що включає в себе інші компоненти, виступає стосовно них як батьківський компонент. У кожного компонента є батько. Їм може бути форма або інший віконний компонент. У процесі виконання додатка ви можете довідатися про батька того або іншого компонента по його властивості Parent. Цю властивість можна читати й змінювати тільки під час виконання, в Інспекторові Об'єктів ви її не знайдете.
Що дає поняття батьківського компонента? Компонент може успадковувати багато властивостей свого батька. Для всіх візуальних компонентів ви можете побачити в Інспекторові Об'єктів такі властивості, як Parentfont і Parentshowhint, для віконних компонентів є ще властивість Parentctl3D. Ці властивості вказують (якщо їх значення встановлені в true), що дочірній компонент успадковує від батьківського відповідно атрибути шрифту, показу ярличків, атрибути свого оформлення. Крім того, значення властивостей Left і Тор, які ви можете бачити в Інспекторові Об'єктів для будь-якого візуального компонента, і які визначають положення лівого верхнього кута компонента, виміряються в системі координат батьківського компонента. Таким чином, наприклад, при переміщенні границь батьківського компонента будуть синхронно переміщатися й усі його дочірні компоненти.
Є ще дві важливі властивості, які зв'язують дочірні компоненти з батьківським. Це властивості Visible - видимий, і Enabled - доступний. Якщо в процесі виконання додатка зробити в батьківському компоненті Visible рівним false, то стане невидимим не тільки батьківський, але й усі його дочірні компоненти. Аналогічно, якщо в процесі виконання додатка зробити в батьківському компоненті Enabled рівним false, то стануть недоступними всі його дочірні компоненти. Т.ч. користувач не зможе натискати кнопки й робити будь-які інші дії в межах даного батьківського компонента.
Поняття батьківського компонента дуже важливе, і його зміст виходить далеко за рамки просто прийнятного оформлення вікна форми.
Відзначимо ще одну властивість компонентів, яка часто плутається із властивістю Parent. Ця властивість Owner - власник даного компонента. Властивість Owner установлюється в момент створення компонента в процесі виконання додатка. Власник компонента - цей той компонент, при знищенні якого (звільненні займаної їм пам'яті) знищиться й даний компонент. Цим і обмежується зв'язок між власником і компонентами, якими він володіє, на відміну від безлічі зазначених вище властивостей, що зв'язують батьківський і дочірні компоненти.
За замовчуванням батьком і власником усіх компонентів, розміщених на формі, є сама форма. Але якщо в процесі проектування компонент розміщається не безпосередньо на формі, а на іншому віконному компоненті, наприклад, на панелі, то батьком для нього стає ця панель.
Усі дочірні компоненти у віконному елементі розташовуються в так званої Z-послідовності. Для компонентів, що перекриваються (що розташовуються один на одному) Z-послідовність визначає, який з них буде видимий. Видимим є той, який розташований у цій послідовності вище.
Звичайно послідовність компонентів відповідає тій, у якій вони поміщалися на форму. Однак невіконні компоненти типу міток завжди лежать в Z-послідовності нижче будь-яких віконних компонентів типу панелей і кнопок.
 
«Багатошарове» розміщення компонентів на формі
Розглянемо тепер особливості розміщення, пов'язані з поняттям, що обговорювалося вище, батьківського компонента. Компоненти дуже часто розміщаються на панелях. Більше того, нерідко панелі поміщаються одна на одну, так що утворюється «багатошарове» розміщення компонентів на формі.
Якщо ви перенесли компонент із бібліотеки не на форму, а на панель, то ця панель стає для нього батьківської. Ви ніякими пересуваннями не зможете перемістити його за межі батьківської панелі. Якщо ж ви передумали розміщати компонент на даній панелі й хочете перемістити його на іншу панель або безпосередньо на форму, то це можна зробити через буфер обміну Clipboard. Виділіть курсором компонент і виріжте його в Clipboard командою Edit – Cut або гарячими клавішами Ctrl+X. Потім клацніть на формі або на тій панелі, куди хочете перенести компонент, і виконайте команду Edit – Paste, або використовуйте гарячі клавіші Ctrl+V. Компонент перенесеться з Clipboard на нове місце й знайде нового батька - панель або форму.
Ще простіше перенос компонентів з одного батьківського контейнера в іншій в Delphi 7 можна робити за допомогою вікна Дерева Об'єктів, описаного нижче.
Якщо ви в процесі проектування переміщаєте панель, вона може накрити якісь компоненти, розміщені на формі або на іншій панелі. Чи будуть при цьому накриті компоненти видимими або ні, визначається їхнім місцем в описаній раніше Z-послідовності. Невіконні компоненти типу міток свідомо будуть невидимі, оскільки вони розташовуються в Z-послідовності завжди нижче будь-яких віконних компонентів. А от видимістю інших віконних компонентів - панелей, кнопок, вікон редагування можна керувати. Це робиться командами меню Edit – Bring To Front і Edit - Send To Back. Перша з них переміщає виділений віконний компонент на верх Z-послідовності й він починає загороджувати всі інші віконні компоненти. А друга команда переміщає виділений віконний компонент на самий низ Z-послідовності й будь-які інші віконні компоненти, розташовані в Z-послідовності вище, починають перекривати його. Ці команди можна виконати й простіше: клацнувши правою кнопкою миші й вибравши їх зі спливаючого меню.
 
Пошук «зниклих» компонентів
Іноді буває, що ви не можете знайти на формі компонентів, який, як ви знаєте, на ній є присутнім. Це буває з кількох причин. Наприклад, якщо ви використовуєте мітку типу Tlabel, установивши в ній властивість Autosize (автоматична зміна розміру по розмірах напису) в true і видалив значення напису Caption, то горизонтальний розмір мітки зменшується до нуля і її не буде видно на формі, поки під час виконання додатка значення Caption не зміниться. Компонент може зникнути також, якщо він накритий іншим компонентом, розташованим вище в Z-послідовності. Можливі й деякі інші причини, наприклад, такий вибір кольорів, що компонент зливається із фоном форми.
Знайти компонент можна знайти, вибравши його ім'я в списку, розташованому вгорі вікна Інспектора Об'єктів. Цей список містить усе компоненти, розміщені на формі. Якщо ви виберете в ньому потрібний компонент, то на формі довкола нього з'явиться рамка з маркерами, видима навіть у випадку, якщо компонент накритий зверху якою-небудь панеллю або іншим компонентом. При цьому в Інспекторові Об'єктів стануть видні сторінки властивостей і подій знайденого компонента.
Якщо ціль пошуку полягала в тому, щоб задати для компонента значення якихось властивостей або оброблювачі подій, то більше вам нічого й не треба. Якщо ж вам все-таки треба добратися до компонента, накритого іншим компонентом або панеллю, то доведеться або тимчасово зрушувати кудись ці перешкоди, або виконати для них команду Send To Back, яка зрушить їх у низ Z-Послідовності. Принаймні, ви знаєте, де розташований «утікач» і що треба зрушити, щоб його знайти.
Ще один спосіб знайти компонент на формі - виділення його вершини у вікні Дерева Об'єктів, про яке буде розказано нижче.
Особливо треба зупинитися на питанні, як, нічого не зрушуючи, добратися до нижніх панелей, якщо на них лежать інші панелі, або як добратися до форми, якщо вся вона накрита панелями. Тут можливий той же підхід, про який говорилося вище. Але можна зробити простіше. Виділіть верхню панель і натисніть клавішу Esc. У вікні Інспектора Об'єктів відкриються сторінки, пов'язані з панеллю, яка розміщена нижче. Натисніть Esc ще раз, відкриються сторінки наступного шару і т.д. доти, поки не відкриються сторінки форми. Звичайно, якщо у вас є тільки один шар панелі, то сторінки форми відкриються при першому же натисканні Esc.
 
Вікно Object Treeview і сторінка діаграм Редактори Коду
Починаючи з Delphi 6, в ІСР з'явився новий інструмент – вікно Object Treeview (Дерево Об'єктів), яке відображає дерево всіх візуальних і невізуальних компонентів, наявних у вашому додатку. Воно показує всілякі види зв'язку між компонентами: співвідношення батьківських і дочірніх компонентів, зв'язок компонентів через їхні властивості, зв'язки з наборами даних і т.п. Поки ми не розглядали більшість із цих зв'язків, так що проілюструємо роботу з Деревом Об'єктів на прикладі зв'язку батьківських і дочірніх компонентів.
Розмістіть на формі якісь панелі, компоненти й подивіться на вікно Дерева Об'єктів. У конфігурації ІСР за замовчуванням це вікно розташоване в лівій частині екрана над вікном Інспектора Об'єктів. Якщо ви закрили це вікно і його не видно, виконайте команду View – Object Treeview, і воно з'явиться на екрані.
Якщо ви виділите якусь вершину в дереві, компонент виділиться на формі, а в Інспекторові Об'єктів відкриються його сторінки властивостей і подій. Так що використання вікна Дерева Об'єктів - ще один спосіб знайти компонент на формі.
Ви можете переносити компоненти з одного батьківського контейнера в інший, просто перетаскуючи в дереві відповідну вершину в іншу батьківську вершину, наприклад, на іншу панель. Компонент на формі при цьому переміститься в поле нового батька. Аналогічним способом можна перетаскувати набори, джерела даних, компоненти відображення даних і т.д. при роботі з базами даних.
 
Робота із групою компонентів, вирівнювання компонентів по розміру й положенню
На формі можна виділити групу компонентів, до яких застосовується та або інша операція. Виділення групи можливо двома способами. Якщо компоненти розташовані безпосередньо на формі й поруч один з одним, то для виділення групи досить обвести курсором рамку навколо них, і всі вони виявляться виділеними. Якщо компоненти групи розташовані не безпосередньо на формі, а, наприклад, на панелі, то виділити їх рамкою неможливо. Так само неможливо виділити рамкою групу компонентів, розташованих у різних місцях форми. У цих випадках виділення проводиться інакше. Виділяйте потрібні компоненти курсором, натиснувши й не відпускаючи при цьому клавішу Shift. Усі компоненти, виділені таким чином, увійдуть у групу.
З виділеною групою компонентів можна робити наступні операції:
Переміщати їх одночасно, потягнувши курсором за один з виділених компонентів. Це дуже зручно, коли треба перемістити групу компонентів на формі, не змінюючи їх взаємного розташування.
Задавати в Інспекторові Об'єктів загальні для всієї групи властивості. При виділенні групи на сторінці властивостей в Інспекторові Об'єктів будуть видні тільки їх загальні властивості. А індивідуальні властивості, такі, наприклад, як ім'я компонента Name або напис Caption, зникнуть. Ви можете задати особливості шрифту, оформлення, колір і т.п., які будуть властиві всім компонентам виділеної групи.
Задати загальний для всіх компонентів групи оброблювач якоїсь події. Така потреба виникає на практиці досить часто.
Скопіювати всю групу в буфер обміну Clipboard командою Edit – Copy або «гарячими» клавішами Ctrl+C. Після цього ви можете, наприклад, відкрити якусь іншу форму й перенести на неї групу з Clipboard командою Edit – Paste або «гарячими» клавішами Ctrl+V. Це простий спосіб переносити фрагменти з однієї форми на іншу або з однієї панелі форми на іншу панель.
Вирівнювати компоненти групи по розміру й взаємному розташуванню.
Коли ви розміщаєте компоненти на формі, важко буває добитися акуратного вигляду вікна, симетричного розташування компонентів, а іноді виникають проблеми задавання однакового розміру їх по горизонталі й вертикалі. В Delphi існує зручний інструмент для рішення цих задач. Мова йде про команди Edit – Align - вирівнювання розміщення, Edit – Size - вирівнювання розмірів і Edit – Scale - масштабування. Ті ж команди можна вибирати не з меню Edit, а з розділу Position контекстного меню, яке спливе, якщо ви клацнете правою кнопкою миші на одному з компонентів групи (саме на компоненті, тому що якщо ви клацнете осторонь, то виділення групи зніметься).
При виконанні команди Size відкривається вікно. Ліва частина вікна - Width встановлює ширину компонентів. Ви можете вибрати варіанти: No change - не змінювати, Shrink to smallest - зменшити до розміру мінімального з компонентів групи, Grow to largest - збільшити до розміру максимального з компонентів групи, Width - задати у вікні ширину компонента в пікселях. Аналогічні варіанти пропонуються в правій частині вікна для Height - висоти компонентів.
При виконанні команди Edit – Align відкривається вікно. Ліва частина вікна - Horizontal установлює вирівнювання компонентів по горизонталі. Ви можете вибрати варіанти: No change - не змінювати, Left sides - вирівняти компоненти по їхніх лівих сторонах (тобто ліві сторони компонентів будуть розташовані друг під другом), Center - вирівняти компоненти по їхніх центрах, Right sides - вирівняти компоненти по їхніх правих сторонах, Space equally - розмістити з рівними інтервалами між компонентами, Center in window - розташувати в центрі вікна.
Права частина вікна - Vertical установлює вирівнювання компонентів по вертикалі. Отут є аналогічні варіанти. Ви можете вибрати: No change - не змінювати, Tops - вирівняти компоненти по їхніх верхніх сторонах, Center - вирівняти компоненти по їхніх центрах, Bottoms - вирівняти компоненти по їхніх нижніх сторонах, Space equally - розмістити з рівними інтервалами між компонентами, Center in window - розташувати в центрі вікна.
Необхідно зробити деякі уточнення по різних режимах вирівнювання.
При вирівнюванні по границях компонентів (Left sides, Right sides, Top, Bottoms, Center) на місці залишається самий лівий ( при вирівнюванні по горизонталі) або самий нижній ( при вирівнюванні по вертикалі) компонентів, а місце розташування інших підганяється під нього.
У режимі Space equally крайні компоненти (лівий і правий при вирівнюванні по горизонталі й верхній і нижній при вирівнюванні по вертикалі) не переміщаються. Інтервали між компонентами визначаються положенням цих крайніх компонентів і числом і розмірами проміжних. Так що, користуючись цим режимом, розмістіть спочатку крайні компоненти так, як вам потрібно, а вже потім використовуйте вирівнювання. Вирівнюються відстані між верхніми (при вирівнюванні по вертикалі) або лівими (при вирівнюванні по горизонталі) межами компонентів. Тому, якщо компоненти, що вирівнюються, мають різні розміри, то відстані між їхніми друга краями будуть не однакові. Компоненти можуть навіть накластися один на одного. Так що вирівнювання по рівних відстанях має сенс тільки для компонентів рівних розмірів.
Режим Center in window не означає, що кожний компонент розташується в горизонтальнім або вертикальному напрямку в центрі вікна. У центрі розташується тільки центр виділеної групи, а відносні зрушення компонентів збережуться незмінними. Крім того врахуйте, що мова в цьому випадку йде не про вікно форми, а про батьківське вікно компонентів групи. Якщо компоненти розташовані, наприклад, на панелі, то мається на увазі центр цієї панелі.
Вирівнювання компонентів часто вимагає багаторазового виконання вирівнювання в різних режимах. Навіть за допомогою команд спливаючого меню це робити незручно. В Delphi є набагато більш зручний інструмент вирівнювання. Виконаєте команду View – Alignment Palette - палітра вирівнювання. З'явиться вікно палітри вирівнювання. Призначення її кнопок зрозуміло з їхніх піктограм. Верхній ряд кнопок відноситься до вирівнювання по горизонталі й відповідає обговореним вище варіантам вирівнювання. Нижній ряд кнопок дозволяє вирівнювати по вертикалі. Випробуйте цей інструмент на якому-небудь тестовому прикладі, і ви переконаєтеся в його ефективності. Щоб повністю освоїтися з вирівнюванням, додайте на форму панелі, розмістіть на них різні компоненти й спробуйте вирівняти й самі панелі й компонента на них.
 
Фіксація компонентів
Після того, як ви ретельно розмістили й вирівняли компоненти, їх місце розташування корисно зафіксувати. Інакше в процесі наступної роботи над проектом ви можете випадково зрушити той або інший компонент, коли будете його виділяти курсором, і всю роботу з вирівнювання доведеться починати заново.
Щоб цього не відбулося, виконайте команду Edit – Lock Controls. Вона зафіксує розташування всіх компонентів на формі й не дозволить їх переміщати. Якщо надалі у вас все-таки виникне потреба змінити розташування компонентів, то виконайте повторно команду Edit – Lock Controls і компоненти будуть розблоковані. (початок) 
Питання для самоконтролю
1. Опишіть принципи роботи з компонентом Label. Які властивості має даний компонент? Дайте опис усіх властивостей
2. Опишіть принципи роботи з компонентом Edit. Приведіть назви й опис всіх його властивостей. Як конвертувати текст у рядок  і навпаки?
3. Опишіть компонент Button. Приведіть його властивості і їх характеристики. Опишіть компонент Bitbutton. У чому його відмінність? Які властивості має Bitbutton?
Лекція № 5
Тема: «Компоненти Delphi: лічильники, списки, прапорці, перемикачі, закладки»
 
План
1. Уведення й відображення цілих чисел2. Компоненти вибору зі списків3. Перемикачі4. Прапорці5. Компонент Imagelist6. Закладки 
1. Уведення й відображення цілих чисел
У бібліотеці візуальних компонентів Delphi існує низка компонентів, що дозволяють уводити, відображати й редагувати числа. Звичайно, з подібною інформацією можна працювати просто як з текстової. Але це незручно, тому що не гарантує від помилок при введенні.
В Delphi є спеціалізовані компоненти, що забезпечують уведення цілих чисел - Updown (Win32) і Spinedit (Samples).
Компонент Updown перетворює вікно редагування Edit у компонент, у якому користувач може вибирати ціле число, змінюючи його кнопками зі стрілками. Якщо до того ж установити в true властивість вікна Readonly, то користувач просто не зможе ввести у вікно який-небудь свій текст і змушений буде обмежитися вибором числа. Компонент Spinedit являє собою комбінацію Edit і Updown, оформлену як окремий тип компонента.
Компонент Updown має властивості:
 
Властивість Опис
Alignbutton Положення кнопок лічильника відносно поля (ліворуч або праворуч)
Arrowkeys Якщо рівно true, то лічильник можна перемикати стрілками нагору й униз
Associate Задає текстове поле, з яким зв’язаний компонент лічильника
Cursor Задає покажчик миші при наведенні на лічильник
Enabled Якщо рівно true, то компонент доступний
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Increment Задає крок зміни лічильника
Left Задає відступ компонента від лівого краю форми в пікселях
Max Задає максимальне значення лічильника
Min Задає мінімальне значення лічильника
Name Задає ім'я компонента для звертання до нього в тексті програми
Position Поточне значення лічильника
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
Wrap Якщо рівно true, то лічильник змінює значення по кільцю.
 
Властивості компонента Spinedit схожі на розглянуті, тільки мають інші імена: властивості Min, Max, Position називаються відповідно Minvalue, Maxvalue, Value. У цілому компонентів Spinedit у багатьох випадках зручніше простої комбінації Updown і Edit. Так що, якщо не потрібні якісь із описаних вище додаткових можливостей Updown (нестандартне розташування кнопок, «заккілюцювання» змін і т.п.), то можна користуватися компонентом Spinedit. (початок) 
2. Компоненти вибору зі списків
Компоненти Listbox (Standard) і Checklistbox (Standard) відображають списки рядків і дозволяють користувачеві вибрати в них потрібний рядок. Компоненти дозволяють захистити програму від помилок уведення й прискорити заповнення текстової інформації шляхом вибору готових значень із заданого переліку.
Компонент Listbox має властивості:
 
Властивість Опис
Autocomplite Якщо рівно true, то можна перейти на рядок списку ввівши перші букви його текста
Color Задає колір фона списку
Columns Задає кількість стовпчиків для відображення елементів списку
Cursor Задає покажчик миші при наведенні на лічильник
Enabled Якщо рівно true, то компонент доступний
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Items Задає перелік значень списку
Left Задає відступ компонента від лівого краю форми в пікселях
Name Задає ім'я компонента для звертання до нього в тексті програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Sorted Якщо рівно true, то елементи списку сортуються по зростанню
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
 
Компонент має властивість, доступну тільки при написанні коду. За допомогою властивості Itemindex можна довідатися індекс обраного рядка в списку. Якщо жоден рядок не обраний, то Itemindex = -1. За замовчуванням Itemindex = -1. Це означає, що жоден елемент списку не обраний. Якщо ви прагнете задати цій властивості якесь інше значення, тобто встановити вибір за замовчуванням, який буде показаний у момент початку роботи додатка, то зробити це можна, наприклад, в оброблювачі події Oncreate форми, увівши в нього оператор виду:
 
listbox1.itemindex:=0;
 
Для звертання до тексту обраного рядка списку використовують запис виду:
 
Listbox1.items.strings[listbox.itemindex];
 
Для роботи зі списком використовують наступні методи:
 
listbox.clear; – очищення списку від значень;
listbox.items.add(‘текст’); – додає в список новий рядок;
listbox.items.delete(listbox.itemindex); – видаляє зі списку виділений рядок;
listbox.setfocus; – передає фокус списку.
 
Основною подією компонента Listbox є подія Onclick, яке наступає при клацанні мишею на рядку списку.
Для роботи зі списками розглянемо приклад.
Нехай є форма вигляду:
 

 
Для того, щоб у лівому списку за замовчуванням був обраний перший рядок, необхідно в події форми Oncreate написати код:
 
procedure tform1.formcreate(sender: tobject);
begin
//робимо активної перший рядок
listbox1.itemindex:=0;
end;
 
Кнопка «+» додає в лівий список уміст текстового поля. При цьому потрібно перевірити, щоб текстове поле не було порожнім. Для кнопки напишемо код:
 
procedure tform1.button1click(sender: tobject);
begin
//якщо поле не порожнє
if edit1.text<>''then
begin
//додаємо в список уміст поля
listbox1.items.add(edit1.text);
//очищаємо поле
edit1.text:='';
end
else
begin
//якщо поле порожнє, видаємо повідомлення про помилку
application.messagebox('немає даних','помилка',mb_ok+mb_iconstop);
//ставимо курсор у текстове поле
edit1.setfocus;
end;
end;
 
Кнопка «-» видаляє з лівого списку обраний рядок. При цьому потрібно видати запит на виконання операції й перевірити, чи є для видалення обраний рядок. Для кнопки напишемо код:
 
procedure tform1.button2click(sender: tobject);
begin
//перевіряємо, чи є обраний рядок для видалення
if listbox1.itemindex<>-1 then
begin
//видаємо запит на видалення
if application.messagebox('вилучити?','запит',mb_yesno+ mb_iconquestion)=idyes then
//видаляємо рядок
listbox1.items.delete(listbox1.itemindex);
end
//якщо рядок для видалення не обраний
else
//видаємо повідомлення про помилку
application.messagebox ('немає даних для видалення','помилка',mb_ok+ mb_iconstop)
end;
 
Кнопка «>» переносить рядок з лівого списку в правий. При цьому потрібно перевірити, чи є в лівому списку обраний рядок для переміщення. Для кнопки напишемо код:
 
procedure tform1.button4click(sender: tobject);
begin
//перевіряємо, чи є в списку обраний рядок для переносу
if listbox1.itemindex<>-1 then
begin
//копіюємо рядок з лівого списку в правий
listbox2.items.add(listbox1.items.strings[listbox1.itemindex]);
//видаляємо з лівого списку скопійований рядок
listbox1.items.delete(listbox1.itemindex);
end
//якщо рядок для переносу не обраний
else
//видаємо повідомлення
application.messagebox ('немає даних для переносу','помилка',mb_ok+ mb_iconstop)
end;
 
Кнопка «<» ідентична кнопці «>», але імена списків потрібно поміняти.
Кнопка «>>» переносить усі елементи з лівого списку в правий. Для кнопки напишемо код:
 
procedure tform1.button3click(sender: tobject);
//опишемо змінну-лічильник для циклу
var i:integer;
begin
//організуємо цикл по всіх рядках списку
for i:=0 to listbox1.items.count-1 do
begin
//ставимо курсор на перший рядок списку
listbox1.itemindex:=0;
//копіюємо рядок з лівого списку в правий
listbox2.items.add(listbox1.items.strings[listbox1.itemindex]);
//видаляємо з лівого списку скопійований рядок
listbox1.items.delete(listbox1.itemindex);
end;
end;
 
Кнопка «<<» ідентична кнопці «>>», але імена списків потрібно поміняти.
Розглянемо тепер компонент списку, що випадає, Combobox. Даний компонент являє собою комбінацію компонента Listbox і текстового поля Edit. Цей компонент в основному має ті ж властивості й методи, що й Listbox. Однак він має й деякі відмінності.
Стиль зображення компонента Combobox визначається його властивістю Style, яке може приймати наступні основні значення:
 
csdropdown список що випадає з рядками однакової висоти й з вікном редагування, що дозволяють користувачеві вводити або редагувати текст
cssimple Розгорнутий список з рядками однакової висоти й з вікном редагування, що дозволяють користувачеві вводити або редагувати текст
csdropdownlist список що випадає з рядками однакової висоти, що не містить вікна редагування.
 
Вибір користувача або введений їм текст можна визначити за значенням властивості Text. Усе сказане вище про Itemindex і про завдання його значення за замовчуванням справедливо й для компонента Combobox. Причому для Combobox завдання початкового значення Itemindex ще актуальніше, чим для Listbox. Якщо початкове значення не задане, то в момент запуску додатка користувач не побачить у вікні компонента одне з можливих значень списку й, найімовірніше, не дуже зрозуміє, що із цим вікном треба робити.
Властивість Maxlength визначає максимальне число символів, які користувач може ввести у вікно редагування. Якщо Maxlength = 0, то число символів, що вводяться, не обмежене.
Властивість Dropdowncount указує число рядків, що з'являються в списку, що випадає, без відображення смуги прокручування.
Як і в компоненті Listbox, властивість Sorted дозволяє впорядкувати список за алфавітом. При Sorted = true нові рядки в список додаються не в кінець, а за алфавітом.
Основною подією для компонента є подія Onchange, яке наступає при введенні нового значення в текстове поле або при виборі значення зі списку.(початок) 
3. Перемикачі
Радіиокнопки утворюють групи взаємозалежних індикаторів, з яких може бути обраний тільки один. Вони використовуються для вибору користувачем однієї з декількох взаємовиключних альтернатив, наприклад, відділу, у якому працює співробітник, або статі співробітника.
Почнемо розгляд радіокнопок з компонента Radiogroup (Standard) - панелі групи радіокнопок. Це панель, яка може містити розташовані стовпцями й рядками радіокнопки. Компонент має властивості:
 
Властивість Опис
Caption Заголовок групи, відображуваний у лівому верхньому куті рамки
Color Колір фона
Columns Задає кількість стовпчиків для відображення перемикачів на панелі
Cursor Задає покажчик миші при наведенні на компонент
Enabled Якщо рівно true, то компонент доступний
Font Параметри шрифту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Itemindex Задає номер перемикача, обраного за замовчуванням. Нумерація з 0
Items Задає перелік назв перемикачів
Left Задає відступ компонента від лівого краю форми в пікселях
Name Задає ім'я компонента для звертання до нього в тексті програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
 
Компонент Radiogroup дуже зручний, але не вільний від деяких недоліків. Його добре використовувати, якщо написи кнопок мають приблизно однакову довжину і якщо число кнопок у кожному стовпці ( при розміщенні їх у декількох стовпцях) однаково.
Radiogroup при розміщенні кнопок орієнтується на напис максимальної довжини. Тому іноді використання цього компонента веде до непривабливого зовнішнього вигляд вікон.
У подібних випадках бажане нерегулярне розташування кнопок. Таку можливість дають компоненти Radiobutton (Standard), згруповані панеллю Groupbox (Standard). Панель Groupbox виглядає на формі так само, як Radiogroup, і напис у її верхньому лівому куті також визначається властивістю Caption. Ця панель сама по собі порожня. Її призначення - служити контейнером для інших керуючих елементів, зокрема, для радіокнопок Radiobutton.
Розглянемо властивості радіокнопки Radiobutton.
 
Властивість Опис
Alignment Задає розташування підпису перемикача (ліворуч або праворуч)
Caption Заголовок групи, відображуваний у лівому верхньому куті рамки
Checked Якщо рівно true, то перемикач обраний
Color Задає колір тла
Cursor Задає покажчик миші при наведенні на компонент
Enabled Якщо рівно true, то компонент доступний
Font Параметри шрифту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Left Задає відступ компонента від лівого краю форми в пікселях
Name Задає ім'я компонента для звертання до нього в тексті програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
Wordwrap Якщо рівно true, то напис може переноситися на новий рядок
 
Розглянемо на прикладі використання перемикачів. Нехай є форма вигляду:
 

 
Необхідно для кнопки написати оброблювач, який на підставі перших двох полів обчислює значення залежно від обраного перемикача й поміщає відповідь у третє поле.
Нехай група перемикачів створена за допомогою компонента Radiogroup. Код для кнопки буде мати вигляд:
 
procedure tform1.button1click(sender: tobject);
//опишемо допоміжні змінні
var a,b,c:real;
begin
//конвертуємо вміст двох полів у числа
a:=strtofloat(edit1.text);
b:=strtofloat(edit2.text);
//аналізуємо вибір перемикача
case radiogroup1.itemindex of
//якщо обраний перший перемикач, лічимо суму
0: c:=a+b;
//якщо обраний другий перемикач, лічимо різницю
1: c:=a-b;
end;
//відображає відповідь у третьому полі
edit3.text:=floattostr(c);
end;
 
Розглянемо цей же приклад за умови, що перемикачі створені за допомогою компонентів Radiobutton. Код для кнопки буде мати вигляд:
 
procedure tform1.button1click(sender: tobject);
//опишемо допоміжні змінні
var a,b,c:real;
begin
//конвертуємо вміст двох полів у числа
a:=strtofloat(edit1.text);
b:=strtofloat(edit2.text);
//якщо обраний перший перемикач, лічимо суму
if radiobutton1.checked=true then
c:=a+b
//якщо обраний другий перемикач, лічимо різницю
else
c:=a-b;
//відображає відповідь у третьому полі
edit3.text:=floattostr(c);
end; (початок) 
4. Прапорці
Прапорці Checkbox (Standard) використовуються в додатках в основному для того, щоб користувач міг включати й виключати якісь опції, або для індикації стану. Прапорець має властивості:
 
Властивість Опис
Alignment Задає розташування підпису перемикача (ліворуч або праворуч)
Caption Заголовок групи, відображуваний у лівому верхньому куті рамки
Checked Якщо рівно true, то перемикач обраний
Color Задає колір фона
Cursor Задає покажчик миші при наведенні на компонент
Enabled Якщо рівно true, то компонент доступний
Font Параметри шрифту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Left Задає відступ компонента від лівого краю форми в пікселях
Name Задає ім'я компонента для звертання до нього в тексті програми
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
Wordwrap Якщо рівно true, то напис може переноситися на новий рядок
 
Для демонстрації роботи із прапорцями розглянемо приклад. Нехай є форма вигляду:
 

 
Для кнопки написати код, який підсумовує значення двох полів і видає відповідь у вигляді, зазначеному за допомогою перемикачів. Для кнопки напишемо код:
 
procedure tform1.button1click(sender: tobject);
//опишемо допоміжні змінні
var a,b,c:real;
begin
//конвертуємо вміст полів у числа
a:=strtofloat(edit1.text);
b:=strtofloat(edit2.text);
c:=a+b;
//якщо обраний перший прапорець і не обраний другий
if (checkbox1.checked=true) and (checkbox2.checked=false) then
//видаємо відповідь у повідомленні
showmessage(floattostr(c))
//якщо обраний другий прапорець і не обраний перший
else if (checkbox1.checked=false) and (checkbox2.checked=true) then
begin
//відображаємо другу форму
form2.show;
//на формі в мітці відображаємо результат
form2.label1.caption:=floattostr(c);
end
//якщо обрано обоє прапорця
else if (checkbox1.checked=true) and (checkbox2.checked=true) then
begin
//відображає результат у повідомленні
showmessage(floattostr(c));
//відображаємо нову форму
form2.show;
//на формі в мітці відображаємо відповідь
form2.label1.caption:=floattostr(c);
end
//якщо жоден прапорець не обраний
else
//видаємо повідомлення про помилку
application.messagebox('не зазначений вид висновку','помилка',mb_ok+mb_iconstop);
end;
 
Для роботи приведеного коду необхідно виконати низку дій:
створити нову форму Form2 і розмістити на ній мітку Label1;
у модулі форми Form1 підключити модуль форми Form2. Це дозволить викликати форму Form2 у коді форми Form1. Для підключення перейдіть у код форми Form1 і після ключового слова Implementation вставте команду
uses unit2;
 
або виконайте команду File – Use Unit і виберіть модуль Unit2 (початок) 
5. Компонент Imagelist
Компонент Imagelist (Win32) використовується і як компонент, і як властивість інших компонентів – меню, панелей, кнопок, диспетчерів дій. Являє собою набір зображень однакових розмірів, на які можна посилатися по індексах, що починаються з 0. Використовується для ефективного управління безліччю піктограм і бітових матриць.
Зображення в компонент Imagelist можуть бути завантажені в процесі проектування за допомогою редактора списків зображень. Вікно редактора, викликається подвійним клацанням на компоненті Imagelist або клацанням правої кнопки миші й вибором команди контекстного меню Imagelist Editor.
У вікні редактора списків зображень ви можете додати в список зображення, користуючись кнопкою Add, вилучити зображення зі списку кнопкою Delete, очистити весь список кнопкою Clear.
Кожне завантажене в список зображення отримує індекс. Саме на ці індекси згодом ви можете посилатися у відповідних властивостях розділів меню, списків, кнопок і т.д., коли вам треба завантажити в них те або інше зображення. Змінити послідовність зображень у списку ви можете, просто перетягнувши зображення мишею на нове місце. (початок) 
6. Закладки
Багатосторінкові панелі дозволяють заощаджувати простір вікна додатка, розміщаючи на формі сторінки різного змісту. Найпоширенішим є компонент Pagecontrol (Win32). Щоб задавати й редагувати сторінки цього компонента, треба клацнути на ньому правою кнопкою миші. У меню, що спливає, ви можете бачити команди: New Page - створити нову сторінку, Delete Page – вилучити сторінку.
Кожна створювана вами сторінка є панеллю, на якій можна розміщати будь-які керуючі компоненти, вікна редагування й т.п. Після того, як ви створите кілька сторінок, виділіть одну з них, клацнувши в її середині, і подивіться її властивості в Інспекторові Об'єктів.
Кожна сторінка має наступні основні властивості:
 
Властивість Опис
Caption Напис, який з'являється на ярличкові сторінки
Cursor Задає покажчик миші при наведенні на компонент
Enabled Якщо рівно true, то компонент доступний
Font Параметри шрифту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Imageindex Індекс зображення, яке може з'являтися на ярличку сторінки. Нумерація з 0
Left Задає відступ компонента від лівого краю форми в пікселях
Name Задає ім'я сторінки для звертання до нього в тексті програми
Pageindex Індекс сторінки, по якому можна посилатися на сторінку.
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Tabvisible Якщо рівно true, то сторінка відображається на формі
Top Задає відступ компонента від верхнього краю форми в пікселях
 
Сам компонент Pagecontrol має свої властивості:
 
Властивість Опис
Cursor Задає покажчик миші при наведенні на компонент
Enabled Якщо рівно true, то компонент доступний
Font Параметри шрифту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Images Задає компонент Imagelist, що містить перелік зображень для відображення на ярликах сторінок
Left Задає відступ компонента від лівого краю форми в пікселях
МultiLine Визначає, чи будуть закладки розміщатися в кілька рядів, якщо всі вони не поміщаються в один ряд
Name Задає ім'я компонента для звертання до нього в тексті програми
Pages[Index] Доступ до сторінки по індексу (перша сторінка має індекс 0). Властивість тільки для читання.
Pagecount Кількість сторінок. Властивість тільки для читання
Scrollopposite Визначать спосіб переміщення закладок при розміщенні їх у кілька рядів
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Style Визначає стиль відображення компонента: tstabs – закладки, tsbuttons – кнопки, tsflatbuttons – плоскі кнопки.
TabheightиTabwidth Висота й ширина ярличків закладок у пікселях. Якщо значення цих параметрів задані рівними 0, то розміри ярличків визначаються автоматично по розмірах написів на них.
Tabposition Визначає місце розташування ярличків закладок: tpbottom - унизу, tpleft - ліворуч, tpright - праворуч і tptop - угорі компонента
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Width Задає ширину компонента в пікселях
 
Іноді в програмі потрібно перейти на конкретну закладку без участі користувача. Для цього необхідно викликати метод Show для сторінки з потрібним номером за допомогою команди:
 
pagecontrol1.pages[i].show;
 
де i – номер сторінки. Нумерація починається з 0.
Наприклад, щоб перейти на третю сторінку потрібно ввести команду:
 
pagecontrol1.pages[2].show;
 
Зазначена сторінка під номером 2, тому що нумерація сторінок починається з 0. (початок) 
Питання для самоконтролю
1. Опишіть компоненти введення цілих чисел. Як називаються ці компоненти і які властивості вони мають?
2. Опишіть властивості компонента Listbox. Які методи для роботи зі списками ви знаєте? Приклади.
3. Опишіть компоненти Checkbox і Radiobutton. Які основні властивості мають дані компоненти? Як створити різні групи перемикачів на одній формі?
4. Опишіть компонент Radiogroup. Які властивості він має? Як звернутися до потрібного перемикача в групі?  Для чого потрібний Imagelist і як з ним працювати?
5. Як створити закладки на формі? Опишіть потрібний компонент, указавши властивості самого компонента й властивості окремої закладки на ньому. Як звернутися до потрібної закладки із програми?
Лекція № 6
Тема: «Компоненти Delphi: багаторядкове поле, діалоги форматування»
 
План
1. Багаторядкове вікно редагування2. Створення форми реєстрації3. Системні діалоги форматування символів4. ASCII-таблиця символів 
1. Багаторядкове вікно редагування
Компонент Memo (Standard) являється вікном редагування багаторядкового тексту. Воно наділено багатьма функціями, властивими більшості редакторів. У ньому передбачені типові комбінації гарячих клавіш: Ctrl+C – копіювання виділеного тексту в буфер обміну Clipboard (команда Copy), Ctrl+X – вирізання виділеного тексту в буфер Clipboard (команда Cut), Ctrl+V – вставка тексту з буфера Clipboard у позицію курсору (команда Paste), Ctrl+Z – скасування останньої команди редагування.
На відміну від компонента Edit компонент Memo може містити текст, набраний у кілька рядків. Компонент має властивості:
 
Властивість Опис
Align Задає вирівнювання компонента на формі
Alignment Вирівнювання тексту
Color Задає колір фона
Cursor Задає покажчик миші при наведенні на лічильник
Enabled Якщо рівно true, то компонент доступний
Font Задає параметри форматування тексту
Height Висота компонента в пікселях
Hint Текст спливаючої підказки
Left Задає відступ компонента від лівого краю форми в пікселях
Lines Зберігає вміст компонента
Maxlength Задає максимальну довжину в символах. Якщо рівно 0, то необмежене
Name Задає ім'я компонента для звертання до нього в тексті програми
Readonly Якщо рівно true, то поле заблоковане для редагування
Scrollbars Відображає або приховує смуги прокручування в полі
Showhint Якщо рівно true, то відображається текст спливаючої підказки
Taborder Задає порядок переходу на компонент по клавіші TAB
Tabstop Якщо рівно false, то перейти на компонент клавішею TAB буде неможливо
Top Задає відступ компонента від верхнього краю форми в пікселях
Visible Якщо рівно true, то компонент видимий на формі
Wantreturns Якщо рівно true, то при наборі тексту можна переходити на новий рядок клавішею ENTER
Wanttabs Якщо рівно true, то при наборі тексту можна робити відступи клавішею TAB
Width Задає ширину компонента в пікселях
Wordwrap Якщо рівно true, то текст автоматично переноситься на новий рядок
 
Над компонентом Memo можна виконати кілька дій за допомогою методів:
 
memo1.clear; //очищення поля
memo1.undo; //скасування змін
memo1.selectall; //виділити весь текст у полі
memo1.lines.add(текст); //додавання рядка в поле
memo1.setfocus; //установка курсору в поле
 
Нехай, наприклад, у вашому додатку є вікно редагування Editl, у якому користувач уводить ім'я співробітника, і є кнопка, при клацанні на якій у вікно Memo1 повинна занестися шапка характеристики цього співробітника, після чого користувач може заповнити текст характеристики.
Оброблювач клацання на кнопці може мати вигляд:
 
memo1.clear;
memo1.lines.add('xарактеристика');
memo1.lines.add('співробітник '+editl.text);
memo1.setfocus;
 
Компонент Memo має методи для роботи з файлами.
 
memo1.lines.loadfromfile(ім'я файлу); //завантажує в компонент зазначений файл
memo1.lines.savetofile(ім'я файлу); //зберігає вміст поля у файл
 
Також компонент Memo має спеціальні методи для роботи з буфером обміну.
Для копіювання виділеного фрагменту в буфер використовують команду:
 
memo1.copytoclipboard;
 
Для вирізання виділеного фрагмента в буфер використовують команду:
 
memo1.cuttoclipboard;
 
Для вставки вмісту буфера у вікно Memo використовують команду:
 
memo1.pastefromclipboard; (початок) 
2. Створення форми реєстрації
Нерідко в програмах при запуску потрібно пройти реєстрацію, уводячи пароль. При цьому використовуються наступні вимоги:
символи пароля на екрані заміняються зірочками або іншими символами;
пароль може розбиватися на окремі групи й при введенні курсор автоматично переходить між групами;
користувачеві дається обмежене число спроб уведення пароля;
якщо пароль вірний, то вікно реєстрації зникає й з'являється основне вікно програми.
Розглянемо приклад. Нехай є форма вигляду:
 

 
Пароль розбитий на чотири групи по 5 символів. Користувач набирає пароль і курсор автоматично переходить між полями. Усього дається 5 спроб для введення. Якщо пароль не вірний, то програма завершує роботу.
Спочатку для всіх полів у властивості Passwordchar необхідно вказати символ «*». Це дозволить сховати на екрані справжні символи пароля.
Для того, щоб курсор автоматично переходив між полями при введенні пароля необхідно перевіряти, чи ввів користувач у полі 5 символів, якщо так, то перейти в наступне поле. При введенні тексту для текстового поля виникає подія Onchange, у якій потрібно написати код:
 
procedure tform1.edit1change(sender: tobject);
begin
//якщо в першому полі введено 5 символів
if length(edit1.text)=5 then
//перейти в друге поле
edit2.setfocus;
end;
 
Аналогічний код пишемо для інших полів
 
procedure tform1.edit2change(sender: tobject);
begin
//якщо в другому полі введено 5 символів
if length(edit2.text)=5 then
//перейти в третє поле
edit3.setfocus;
end;
 
procedure tform1.edit3change(sender: tobject);
begin
//якщо в третьому полі введено 5 символів
if length(edit3.text)=5 then
//перейти в четверте поле
edit4.setfocus;
end;
 
procedure tform1.edit4change(sender: tobject);
begin
//якщо в четвертому полі введено 5 символів
if length(edit4.text)=5 then
//перейти на кнопку ОК
button1.setfocus;
end;
 
Для кнопки ОК потрібно написати код, у якому перевіряється пароль. Якщо пароль вірний, то відкривається вікно головної програми. Якщо пароль не вірний, то дається ще одна спроба введення пароля. Якщо користувач зробив 5 невдалих спроб, то програма закривається.
 
procedure tform1.button1click(sender: tobject);
begin
//якщо пароль вірний
if edit1.text+edit2.text+edit3.text+edit4.text='11111111111111111111' then
begin
//прибарємо та вилучаємо з пам’яті форму пароля
release;
//відображаємо форму form2
form2.show;
end
//якщо пароль не вірний
else
begin
//видаємо повідомлення про помилку
application.messagebox('невірний пароль','помилка',mb_ok+ mb_iconstop);
//ставимо курсор у перше поле для повторного введення
edit1.setfocus;
//збільшуємо лічильник невдалих спроб
k:=k+1;
end;
//якщо було зроблено п'ять спроб
if k=5 then
//перериваємо роботу програми
application.terminate;
end;
 
Для роботи цього фрагмента необхідно виконати кілька операцій:
змінна k повинна бути описана як глобальна цілого типу;
для відкриття форми Form2 необхідно підключити модуль цієї форми. Для цього після слова Implementation додайте рядок:
так як головна форма проекту Form1 не закрита, а тільки вилучена з пам'яті, то при закритті форми Form2 програма продовжить свою роботу й буде займати оперативну пам'ять. Для коректного завершення програми необхідно при закритті форми Form2 припинити виконання програми. Для цього в події Onclose форми Form2 уведіть команду:
halt; (початок) 
Генерація пароля по алгоритму
Розглянутий приклад має недолік, пов'язаний з тим, що програма реагує на конкретний пароль. У реальних програмах пароль не є постійною величиною, а формується по деякому алгоритму. Прикладом цього є наявність програм-кейгенів, які дозволяють генерувати різні паролі для реєстрації програми.
Для генерації такого пароля необхідно знати наступне:
- вміст поля - це рядок. Звернутися до символу такого рядка можна за допомогою запису edit1.text[i], де i - номер символу в полі (нумерація з 1);
- кожний символ має свій унікальний Ascii-Код ( ASCII-таблицю див. нижче);
- для переведення символу в його Ascii-Код використовують функцію ord. Повний запис:
 
ord(edit1.text[i]);
 
Враховуючи ці фактори розглянемо кілька прикладів формування пароля.
Приклад 1. Нехай пароль розбитий на 3 поля по 4 символу. Пароль формується так: усі останні символи в кожному полі - рядкова латинська буква. З Ascii-Таблиці видно, що рядкові латинські букви мають кодування в діапазоні від 97 до 122. У цьому випадку умова перевірки пароля буде записана так:
 
if  ord(edit1.text[4])>=97) and (ord(edit1.text[4])<=122) and
    ord(edit2.text[4])>=97) and (ord(edit2.text[4])<=122) and
    ord(edit3.text[4])>=97) and (ord(edit3.text[4])<=122) then
 
Приклад 2. Нехай пароль розбитий на 3 поля по 4 символу. Пароль формується так: суми кодів крайніх символів у кожному полі збігаються. У цьому випадку умова перевірки пароля буде записана так:
 
if ((ord(edit1.text[1])+ord(edit1.text[4])=(ord(edit2.text[1])+ord(edit2.text[4])) and
    ((ord(edit1.text[1])+ord(edit1.text[4])=(ord(edit3.text[1])+ord(edit3.text[4])) then
 
3. Системні діалоги форматування символів
У програмах Windows іноді використовуються спеціальні діалогові вікна: Відкрити, Зберегти, Формат, Колір, Друк. Ці вікна можуть викликатися в різних програмах, але мають однаковий вигляд. Такий збіг досягається за рахунок того, що ці діалогові вікна є стандартними системними діалогами Windows.
Для роботи з діалогами в Delphi є спеціальні компоненти, розташовані на вкладці Dialogs. Розглянемо діалоги, призначені для форматування тексту.
 
Діалог вибору шрифту – компонентів Fontdialog
Компонент Fontdialog викликає діалогове вікно вибору атрибутів шрифту. У ньому користувач може вибрати ім'я шрифту, його стиль (накреслення), розмір і інші атрибути.
Основна властивість компонента – Font, у якому ви можете задати при бажанні початкові установки атрибутів шрифту й у якому ви можете прочитати значення атрибутів, обрані користувачем у процесі діалогу.
Властивості Maxfontsize і Minfontsize встановлюють обмеження на максимальний і мінімальний розміри шрифту. Якщо значення цих властивостей рівні 0 (за замовчуванням), то ніякі обмеження на розмір не накладаються. Якщо ж значення властивостей задані (звичайно це доцільно робити виходячи з розмірів компонента додатка, для якого вибирається шрифт), то в списку Розмір діалогового вікна з'являються тільки розміри, що укладаються в заданий діапазон. Властивості Maxfontsize і Minfontsize діють тільки при включеній опції fdlimitsize.
Властивість Device визначає, з якого списку можливих шрифтів буде запропонований вибір у діалоговому вікні: fdscreen – зі списку екрана (за замовчуванням), fdprinter – зі списку принтера, fdboth – з обох.
Властивість Options містить множину опцій:
 
fdansionly Відображати тільки множину шрифтів символів Windows, не відображати шрифтів зі спеціальними символами.
fdapplybutton Відображати в діалозі кнопку Застосувати незалежно від того, чи передбачений оброблювач події Onapply.
fdeffects Відображати в діалозі індикатори спеціальних ефектів (підкреслення й ін.) і список Колір.
fdfixedpitchonly Відображати тільки шрифти з постійною шириною символів.
fdforcefontexist Дозволяти користувачеві вибирати шрифти тільки зі списку, заборонити йому вводити інші імена.
fdlimitsize Дозволити використовувати властивості Maxfontsize і Minfontsize розміри, що обмежують розмір шрифту.
fdnofacesel Відкривати діалогове вікно без попередньо встановленого імені шрифту.
fdnooemfonts Видаляти зі списку шрифтів шрифти OEM.
fdscalableonly Відображати тільки масштабовані шрифти, видаляти зі списку не масштабовані (шрифти bitmap).
fdnosimulations Відображати тільки шрифти і їх накреслення, прямо підтримувані файлами, не відображаючи шрифти, у яких жирний стиль і курсив синтезується.
fdnosizesel Відкривати діалогове вікно без попередньо встановленого розміру шрифту.
fdnostylesel Відкривати діалогове вікно без попередньо встановленого накреслення шрифту.
fd Novectorfonts Видаляти зі списку векторні шрифти (типу Roman або Script для Windows 1.0).
fdshowhelp Відображати в діалоговому вікні кнопку Довідка.
fdtruetypeonly Пропонувати в списку тільки шрифти Truetype.
fdwysiwyg Пропонувати в списку тільки шрифти, доступні для екрана і для принтера, видаляючи з нього апаратно залежні шрифти.
 
За замовчуванням усі ці опції, крім fdeffects, відключені.
Приведемо приклади застосування компонента Fontdialog. Нехай ваш додаток включає вікно редагування Memo1, та кнопку Формат, за допомгою якої користувач може відкритвати діалог форматування тексту. Якщо Ви додали на форму компонентів Fontdialog з ім’ям за замовчуванням Fontdialog1, то оброблювач для кнопки може мати вигляд:
 
if fontdialog1.execute = true then
memo1.font.assign(fontdialog1.font);
 
Приведений оператор викликає діалог вибору атрибутів шрифту й, якщо користувач зробив вибір, то значення всіх обраних атрибутів, що містяться у властивості Fontdialog1.Font, присвоюються атрибутам вікна редагування, що містяться у властивості Memo1.Font. Шрифт у вікні редагування негайно зміниться.
Однак при виклику діалогу виникає проблема, пов'язана з тим, що у вікні діалогу не завжди правильно відображається поточний формат поля Memo. Це може привести до некоректної роботи діалогу. Для розв'язання даної проблеми необхідно перед відкриттям діалогу завантажувати в нього поточний формат поля. Тому повний код для форматування тексту може мати вигляд:
 
//завантажуємо в діалог поточний формат поля
memo1.font.assign(fontdialog1.font);
//викликаємо діалог і форматуємо текст
if fontdialog1.execute = true then
memo1.font.assign(fontdialog1.font);
 
Якщо ви встановите в компоненті Fontdialog1 опцію fdapplybutton, то можете написати оброблювач події Onapply:
 
memo1.font.assign(fontdialog1.font);
 
Тоді користувач може спостерігати зміни у вікні Memo1, натискаючи в діалоговім вікні кнопку Застосувати не закриваючи діалогу. Це дуже зручно, тому що дозволяє користувачеві правильно підібрати атрибути шрифту.
Ви можете дозволити користувачеві змінювати шрифт не тільки окремих компонентів, але й усіх компонентів і написів на формі. Це здійснюється оператором:
 
if fontdialog1.execute = true then
font.assign(fontdialog1.font);
 
У цьому операторі властивість Font без посилання на компонент має на увазі шрифт форми.
 
Діалог вибору кольору Colordialog і компонент Colorbox
Компонент Colordialog викликає стандартне діалогове вікно вибору кольору.
Основна властивість компонента Colordialog – Color. Ця властивість відповідає тому кольору, який вибрав у діалогах користувач. Якщо при виклику діалогу бажано встановити деяке початкове значення кольору, це можна зробити, установивши властивість Color попередньо під час проектування форми або програмно.
Властивість Options містить множину наступних опцій:
 
cdfullopen Відображати при відкритті діалогового вікна панель визначення замовлених квітів.
cdpreventfullopen Заборонити появу в діалоговім вікні кнопки Визначити колір. В результаті користувач не зможе визначати нові кольори.
cdshowhelp Додати в діалогове вікно кнопку Довідка.
cdsolidcolor Указати Windows використовувати суцільний колір, найближчий до обраного (це збіднює палітру).
cdanycolor Дозволяти користувачеві вибирати будь-які не суцільні кольори (такі кольори можуть бути нерівними).
 
За замовчуванням усі опції виключені.
Приведемо приклад застосування компонента Colordialog. Якщо ви хочете, щоб користувач міг задати колір якогось об'єкта, наприклад, колір фона компонента Memo1, то це можна реалізувати оператором
 
if colordialog1.execute = true then
memo1.color:=colordialog1.color;
 
Розглянутий компонент Colordialog викликає стандартний діалог Windows. Однак нерідко його можливості надлишкові й користувачеві зручніше вибирати колір за допомогою списку, що випадає. Таку можливість надає компонент Colorbox (Additional).
Довідатися колір, обраний користувачем у списку Colorbox, дозволяє властивість Selected. Для цього можна скористатися подією компонента Onselect, що настає у момент вибору користувачем кольору. Наприклад, оператор
 
memo1.color:=colorbox1.selected;
 
поміщений в оброблювач цієї події, задасть фону вікна Memo1 колір, обраний користувачем.
Якщо вам бажане в перший момент показати користувачеві певний колір, це можна зробити в оброблювачі події форми Oncreate, визначивши в ньому властивість SELECTED.
Наприклад, нехай при відкритті форми Form2 у компоненті Colorbox потрібно відобразити поточний колір фона форми.
Для цього в події форми Oncreate напишемо код:
 
colorbox1.selected:=form2.color; (початок) 
4. ASCII-таблиця символів
 
 
 
 
 
Питання для самоконтролю
1. Опишіть компонент Memo. Які властивості він має? Опишіть методи компонента й приведіть приклади їх використання
2. Як викликати діалог форматування тексту в програмі? Які властивості має відповідний компонент? Приведіть приклад форматування тексту в полі Memo
3. Як викликати діалог вибору кольору? Приведіть приклад зміни кольору фона форми. Опишіть принцип роботи з компонентом Colorbox: властивості й приклад використання.
Лекція № 7
Тема: «Робота з файлами й папками»
 
План
1. Робота з папками2. Використання класу Tstringlist3. Команди управління файлами4. Діалоги роботи з файлами5. Робота з папками й файлами за допомогою Win API 
1. Робота з папками
У деяких програмах необхідно виконувати деякі операції з папками: визначення поточної папки, створення, відкриття, видалення, перейменування папки. Усі ці операції можна виконати за допомогою спеціальних команд Delphi.
 
Визначення імені папки
Для визначення імені папки в Delphi є кілька функцій і властивостей.
Функція
 
getcurrentdir()
 
визначає ім'я поточної папки.
У програмі можна використовувати властивість виду:
 
application.exename
 
Ця властивість містить повне ім'я файлу програми, що виконується, включаючи ім'я файлу й розширення.
 
Знаючи повний шлях до файлу, з нього можна вичленувати будь-яку частину шляху за допомогою функцій:
 
extractfiledrive(‘ім'я файлу’) – виділяє ім'я диска з повного імені файлу
extractfilepath(‘ім'я файлу’) – виділяє повне ім'я папки з повного імені файлу
extractfilename(‘ім'я файлу’) – виділяє ім'я файлу з повного імені файлу
extractfileext(‘ім'я файлу’) – виділяє розширення з повного імені файлу.
 
Створення папки
Для створення папки використовують функцію виду:
 
createdir(‘ім'я папки’)
 
Команда створює папку із зазначеним ім'zv в поточній папці або на поточному диску.
 
Приклад.
Для створення папки Newfolder у поточній папці використовують команду виду:
 
createdir(‘newfolder’);
 
При зазначенні імені папки допускається вказівка повного шляху до неї. Наприклад, припустимий запис виду:
 
createdir(‘d:\arhiv\newfolder’);
 
При цьому необхідно, щоб усі папки, зазначені в повному шляху існували. А якщо ні, то папка створена не буде. У нашому випадку, якщо на диску D: не буде папки arhiv, то папка newfolder створена не буде.
Для вирішення цієї проблеми можна викорстовувати команди:
 
createdir(‘d:\arhiv’);
createdir(‘d:\arhiv\newfolder’);
 
В Delphi є функція, яка дозволяє змінити поточну папку на зазначену. Функція має вигляд:
 
setcurrentdir(‘ім'я папки’);
 
Приклади.
 
setcurrentdir(‘d:’); //переходимо на диск d:
setcurrentdir(‘arhiv’); //на поточному диску d: переходимо в папку arhiv
setcurrentdir(‘e:\music’); //переходимо в папку e:\music
 
Якщо потрібно створити ланцюжок вкладених друг у друга папок, то можна комбінувати функції setcurrentdir() і createdir()
Приклад. Створити папку з ім'м d:\arhiv\newfolder і повернутися в папку із програмою
 
setcurrentdir('d:'); //переходимо на диск d:
createdir('arhiv'); //створюємо папку arhiv
setcurrentdir('arhiv'); //заходимо в папку arhiv
createdir('newfolder'); //створюємо папку newfolder
setcurrentdir(extractfilepath(application.exename)); //переходимо в папку із програмою
 
В Delphi є команда, яка дозволяє створити весь ланцюжок папок, навіть якщо вони не існують:
 
forcedirectories(‘ім'я папки’);
 
Приклад.
 
forcedirectories(‘d:\arhiv\newfolder’);
 
Перевірка існування папки
При спробі перейти в неіснуючу папку або при спробі вилучити неіснуючу папку операція не буде виконана успішно. Для коректної роботи додатка необхідно попередньо перевірити наявність зазначеної папки. Зробити це можна за допомогою функції directoryexists()
 
if directoryexists(‘ім'я папки’)=true then
    папка існує
else
    папка не існує;
 
Приклад. Перейти в папку з ім'м data, яка перебуває в папці з файлом програми, що виконується,. Перед переходом перевірити наявність цієї папки.
 
//якщо папка існує
if directoryexists(extractfilepath(application.exename)+’\data’)=true then
//переходимо в цю папку
setcurrentdir(extractfilepath(application.exename)+’\data’);
 
Видалення папки
Для видалення папки існує функція виду:
 
removedir(‘ім'я папки’);
 
Зазначена папка повинна бути порожньою. Якщо папка не порожня, то команда не виконається.
Для видалення непустої папки можна використовувати функцію Winapi Shfileoperation (див. пункт 5 лекції). (початок) 
2. Використання класу Tstringlist
В Delphi є спеціальний клас, що дозволяє завантажувати в себе вміст файлів, обробляти цей вміст і зберігати отриманий результат знову у файл. Клас має ім'я Tstringlist. Для роботи з ним необхідно:
описати змінну цього класу;
створити в пам'яті екземпляр класу для роботи з ним.
 
Приклад
 
//описуємо змінну
var t:tstringlist;
. . .
//створюємо екземпляр класу
t:=tstringlist.create;
 
Після створення екземпляра класу з ним можна працювати за допомогою низки методів:
t.clear; //очищаємо клас
t.loadfromfile('ім’я файлу'); //завантажуємо в клас файл для обробки
t.savetofile(''ім’я файлу''); //зберігаємо у файл вміст класу
t.add('текст'); //додаємо в кінець класу рядок з текстом
t.delete(i); //видаляємо із класу рядок з номером i (нумерація починається з 0)
t.free; //видаляє з пам'яті клас по завершенню роботи з ним
Перевірка існування файлу
Метод loadfromfile() може не спрацювати, якщо зазначеного файлу не виявиться на диску. Перед його викликом необхідно перевіряти наявність файлу за допомогою функції fileexists(‘ім'я файлу’).
 
if fileexists(‘ім'я файлу’)=true then
файл існує
else
файл не існує
 
Приклад. Нехай є текстовий файл, що зберігає числові значення. Необхідно доповнити його ще двома значеннями.
 
//опишемо змінні
var t:tstringlist; a,b:byte;
begin
//якщо файл існує
if fileexists('primer.txt') = true then
begin
//задаємо дані для додавання
a:=10;
b:=20;
//створюємо екземпляр класу
t:=tstringlist.create;
//завантажуємо файл у клас
t.loadfromfile('primer.txt');
//додаємо в клас нові значення
t.add(floattostr(a));
t.add(floattostr(b));
//зберігаємо вміст класу у файл
t.savetofile('primer.txt');
//видаляємо з пам'яті клас
t.free;
end;
end;
 
Приклад. Нехай є два текстові поля edit1 і edit2. Необхідно порахувати суму цих полів і записати результат у файл із пояснюючим текстом.
 
//опишемо змінні (rez- для розрахунку суми)
var t:tstringlist; rez:real;
begin
//лічимо суму
rez:=strtofloat(edit1.Text)+strtofloat(edit2.Text);
//створюємо екземпляр класу
t:=tsringlist.create;
//очищаємо клас
t.clear;
//у класі формуємо текст
t.add('Вихідні дані:');
t.add('-перше число = '+edit1.text);
t.add('-друге число = '+edit2.text);
t.add('Сума:'+floattostr(rez));
//зберігаємо вміст класу у файл
t.savetofile('rez.txt');
//видаляємо з пам'яті клас
t.free;
end;
 
Приклад. Скопіювати текстовий файл під іншим ім'ям
 
//опишемо змінну
var t:tstringlist;
begin
//якщо файл існує
if fileexists('primer.txt') = true then
begin
//створюємо екземпляр класу
t:=tsringlist.create;
//завантажуємо файл у клас
t.loadfromfile('primer.txt');
//зберігаємо вміст класу під іншим ім'ям
t.savetofile(‘copy.txt’);
//видаляємо з пам'яті клас
t.free;
end;
end;
 
Іноді потрібно обробити файл, змінивши в ньому значення або вилучивши дані з файлу. У цьому випадку доводиться використовувати властивості класу:
t.count - число рядків тексту в класі
t.strings[i] - текст, що зберігається в i рядку класу (нумерація починається з 0)
 Крім цього в подібних задачах зручно використовувати два екземпляри класу.  У першому зберігається вихідний текст, а в другому формується результуючий.
Приклад. У текстовому файлі все значення менше 10 збільшить у два рази.
 
//описуємо допоміжні змінні
//i – лічильник циклу
var t1,t2:tstringlist; i:integer;
begin
//якщо файл існує
if fileexists('primer.txt') then
begin
//створюємо екземпляр класу-джерела
t1:=tsringlist.create;
//створюємо екземпляр класу-приймача
t2:=tsringlist.create;
//завантажуємо файл у клас-джерело
t1.loadfromfile('primer.txt');
//очищаємо клас-приймач
t2.clear;
//у циклі проходимо по всіх рядках класу-джерела
for i:=0 to t1.count-1 do
begin
//якщо в рядку значення менше 10
if strtofloat(t1.strings[i])<10 then
//у клас-приймач додаємо цей рядок помножений на 2
t2.add(floattostr(strtofloat(t1.strings[i])*2))
//а якщо ні, то
else
//записуємо цей рядок без змін
t2.add(floattostr(c));
end;
//зберігаємо вміст класу-приймача в той же файл (заміняємо)
t2.savetofile('primer.txt');
//видаляємо з пам'яті створені класи
t1.free;
t2.free;
end;
end;
 
Приклад. У текстовому файлі вилучити рядки, що містять значення менше 10.
 
//описуємо допоміжні змінні
//i – лічильник циклу
var t1,t2:tstringlist; i:integer;
begin
//якщо файл існує
if fileexists('primer.txt') then
begin
//створюємо екземпляр класу-джерела
t1:=tsringlist.create;
//створюємо екземпляр класу-приймача
t2:=tsringlist.create;
//завантажуємо файл у клас-джерело
t1.loadfromfile('primer.txt');
//очищаємо клас-приймач
t2.clear;
//у циклі проходимо по всіх рядках класу-джерела
for i:=0 to t1.count-1 do
begin
//якщо в рядку значення більше 10
if strtofloat(t1.strings[i])>10 then
//записуємо це число в клас-приймач
t2.add(floattostr(c))
end;
//зберігаємо вміст класу-приймача в той же файл (заміняємо)
t2.savetofile('primer.txt');
//видаляємо з пам'яті створені класи
t1.free;
t2.free;
end;
end; (початок) 
3. Команди керування файлами
За допомогою команд Delphi над файлами можна виконувати операції перейменування, видалення, копіювання, переміщення.
 
Копіювання файлу
Для копіювання використовують функцію виду:
 
copyfile (‘ файл-джерело’,’ файл-приймач’,true);
 
Перед копіювання можна перевірити наявність файлу-джерела на диску й наявність папки у файлу приймача.
Приклад. Скопіювати файл primer.txt у файл d:\files\text.txt
 
//якщо вихідний файл існує
if fileexists('primer.txt')=true then
begin
//якщо існує папка призначення
if directoryexists('d:\files')=true then
//копіюємо файл у зазначену папку
copyfile ('primer.txt','d:\files\text.txt',true)
//якщо папка призначення не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Папка призначення не існує’, ‘Помилка копіювання', mb_ok+mb_iconstop)
end
//якщо файл не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Файл не існує’, ‘Помилка копіювання’, mb_ok+mb_iconstop);
 
У розглянутому прикладі ми копіюємо конкретний файл по конкретному шляху. Розглянемо випадок, коли користувач самостійно задає файл і папку призначення.
Приклад. Нехай ім'я файлу вказується в полі edit1, а ім'я папки призначення в полі edit2. Необхідно скопіювати файл під тим же ім'ям у зазначену папку.
 
//якщо вихідний файл існує
if fileexists(edit1.text)=true then
begin
//якщо існує папка призначення
if directoryexists(edit2.text)=true then
//копіюємо файл у зазначену папку під тим же ім'ям
copyfile (pchar(edit1.Text),pchar(edit2.Text+'\'+extractfilename(edit1.Text)),true)
//якщо папка призначення не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Папка призначення не існує’, ‘Помилка копіювання', mb_ok+mb_iconstop)
end
//якщо файл не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Файл не існує’, ‘Помилка копіювання’, mb_ok+mb_iconstop);
 
У даному прикладі потрібно звернути увагу на той факт, що якщо імена файлів або папок вказуються в компонентах, то у функції copyfile вміст цих компонентів обов'язково конвертується за допомогою функції pchar().
 
Перейменування (переміщення) файлу
Для перейменування файлу використовують функцію
 
renamefile(‘ім'я файлу’, ‘нове ім'я файлу’);
 
Як і при копіюванні потрібно перевіряти наявність файлу й папки на диску.
Приклад. Перейменувати файл primer.txt у файл text.txt
 
//якщо файл існує
if fileexists('primer.txt')=true then
//перейменовуємо файл
renamefile('primer.txt','text.txt');
 
За допомогою даної команди можна переміщати файл в іншу папку.
Приклад. Перемістити файл primer.txt у папку d:\files
 
//якщо вихідний файл існує
if fileexists('primer.txt')=true then
begin
//якщо існує папка призначення
if directoryexists('d:\files')=true then
//переміщаємо файл у зазначену папку
renamefile ('primer.txt','d:\files\primer.txt')
//якщо папка призначення не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Папка призначення не існує’, ‘Помилка переміщення', mb_ok+mb_iconstop)
end
//якщо файл не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Файл не існує’, ‘Помилка переміщення’, mb_ok+mb_iconstop);
 
Можна одночасно переміщати й перейменовувати файл, якщо в новому імені файлу вказати не тільки нову папку, але й нове ім'я файлу. Так у розглянутому вище прикладі команда перейменування могла мати вигляд:
 
renamefile ('primer.txt','d:\files\text.txt');
 
Як видно файл primer.txt не тільки переміщається в папку d:\files, але й перейменовується у файл із ім'ям text.txt.
Приклад. Нехай користувач самостійно задає ім'я вихідного файлу в полі edit1 і папку для переміщення в полі edit2. У цьому випадку команда перейменування може мати вигляд:
 
//якщо вихідний файл існує
if fileexists(edit1.text)=true then
begin
//якщо існує папка призначення
if directoryexists(edit2.text)=true then
//переміщаємо файл у зазначену папку під тим же іменем
renamefile(edit1.Text,edit2.Text+'\'+extractfilename(edit1.Text))
//якщо папка призначення не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Папка призначення не існує, ‘Помилка переміщення', mb_ok+mb_iconstop)
end
//якщо файл не існує
else
//видаємо повідомлення з помилкою
application.messagebox(‘Файл не існує’’, ‘Помилка переміщення’, mb_ok+mb_iconstop);
 
На відміну від функції copyfile() при перейменуванні не потрібно вміст компонентів конвертувати за допомогою функції pchar().
 
Видалення файлу
Для видалення файлу використовують функцію
 
deletefile(‘ім'я файлу’);
 
Перед видалення доцільно перевірити наявність файлу на диску.
Приклад. Видалити файл primer.txt
 
//якщо вихідний файл існує
if fileexists('primer.txt')=true then
//видаляємо файл
deletefile(‘primer.txt’); (початок) 
4. Діалоги роботи з файлами
У всіх розглянутих раніше прикладах ім'я файлу ми задавали або як текстову константу, або користувач міг увести ім'я в текстове поле. Проте в Delphi є два діалоги, що дозволяють указати ім'я файлу і його розташування.
Компоненти Opendialog – діалог «Відкрити файл» і Savedialog – діалог «Зберегти як» використовуються найчастіше у більшості додатків. Усі властивості цих компонентів однакові, тільки їх зміст трохи різний для відкриття й збереження файлів. Основна властивість, у яку вертається у вигляді рядка обраний користувачем файл – Filename. Значення цієї властивості можна задати й перед звертанням до діалогу. Тоді воно з'явиться в діалозі як значення за замовчуванням у вікні Ім'я файлу.
Типи файлів, що з'являються в діалозі списку Тип файлу, задаються властивістю Filter. У процесі проектування цю властивість найпростіше задати за допомогою редактора фільтрів, який викликається натисканням кнопки із трьома крапками біля імені цієї властивості в Інспекторові Об'єктів. При цьому відкривається вікно редактора. У його лівій панелі Filter Name ви записуєте той текст, який побачить користувач у списку діалогу. А в правій панелі Filter записуються розділені крапокю з комою шаблони фільтра.
Після виходу з вікна редагування фільтрів задані вами шаблони з'являться у властивості Filter у вигляді рядка. У цьому рядку тексти й шаблони розділяються вертикальними лініями.
В аналогічному вигляді, якщо потрібно, можна задавати властивість Filter програмно під час виконання додатка.
Властивість Filterindex визначає номер фільтра, який буде за замовчуванням показаний користувачеві в момент відкриття діалогу. Нумерація фільтрів починається з 1.
Властивість Initialdir визначає початковий каталог, який буде відкритий у момент початку роботи користувача з діалогом. Якщо значення цієї властивості не задане, то відкривається поточний каталог або той, який був відкритий при останньому звертанні користувача до відповідного діалогу в процесі виконання додатка.
Властивість Defaultext визначає значення розширення файлу за замовчуванням. Якщо значення цієї властивості не задане, користувач повинен указати в діалозі повне ім'я файлу з розширенням. Якщо ж задати значення Defaultext, то користувач може писати в діалозі ім'я без розширення. У цьому випадку буде прийнято задане розширення.
Властивість Title дозволяє вам задати заголовок діалогового вікна. Якщо ця властивість не задана, вікно відкривається із заголовком, визначеним у системі. Але ви можете задати й свій заголовок.
Властивість Options визначає умови вибору файлу. Множина опцій, які ви можете встановити програмно або під час проектування, включає:
 
ofallowmultiselect Дозволяє користувачеві вибирати кілька файлів
ofcreateprompt У випадку якщо користувач написав ім'я неіснуючого файлу, з'являється зауваження й запит, чи треба створити файл із заданим ім'ям.
ofenableincludenotify Дозволяє посилати в діалог повідомлення.
ofenablesizing Дозволяє користувачеві змінювати розмір діалогового вікна.
ofextensiondifferent Цей прапорець, значення якого можна прочитати після виконання діалогу, показує, що розширення файлу, обраного користувачем, відрізняється від Defaultext.
оfFilеМustExist У випадку, якщо користувач написав ім'я неіснуючого файлу, з'являється повідомлення про помилку.
оfHideReadOnly Видаляє з діалогу індикатор Відкрити тільки для читання
оfNoChangeDir Після клацання користувача на кнопці ОК відновлюється поточний каталог, незалежно від того, який каталог був відкрити при пошуку файлу.
ofnodereferencelinks Забороняє перепризначувати клавіші швидкого доступу в діалоговім вікні.
ofnolongnames Відображаються тільки не більш 8 символів імені й трьох символів розширення.
оfNоNetwоrkButton Забирає з діалогового вікна кнопку пошуку в мережі. Діє тільки, якщо прапор ofoldstyledialog включений.
ofnoreadonlyreturn Якщо користувач вибрав файл тільки для читання, то генерується повідомлення про помилку.
ofnotestfilecreate Забороняє вибір у мережі захищених файлів і не доступних дисків при збереженні файлу.
ofnovalidate Не дозволяє писати в іменах файлів недозволені символи, але не заважає вибирати файли з недозволеними символами.
ofoldstyledialog Створює діалог вибору файлу в старому стилі
ofoverwriteprompt У випадку, якщо при збереженні файлу користувач написав ім'я існуючого файлу, з'являється зауваження, що файл із таким ім'ям існує, і запитується бажання користувача переписати існуючий файл.
ofpathmustexist Генерує повідомлення про помилку, якщо користувач указав в імені файлу неіснуючий каталог.
ofreadonly За замовчуванням установлює індикатор Відкрити тільки для читання при відкритті діалогу.
ofshareaware Ігнорує помилки порушення умов колективного доступу й дозволяє, незважаючи на них, робити вибір файлу.
ofshowhelp Відображає в діалоговім вікні кнопку Довідка.
 
Незважаючи на численність опцій у властивості Options, їх починає не вистачати по мірі розвитку Windows. Тому, починаючи з Delphi 6, у діалоги введена ще одна властивість – Optionsex. В цю множину по мірі розвитку Windows і Delphi будуть включатися нові опції. Поки Optionsex містить тільки одну опцію:
 
оfExNоPlaceBar Забороняє появу в діалозі смуги, що забезпечує доступ до папок Історія, Робочий стіл і т.п.
 
За замовчуванням усі перелічені опції у властивостях Options і Optionsex, крім ofhidereadonly, виключені. Але, як видно з їхнього опису, багато з них корисно включити перед викликом діалогів.
Приклад. Нехай є два текстові поля. Необхідно знайти суму значень цих текстових полів. Результат записати у файл із пояснюючим текстом. Ім'я файлу вказати за допомогою діалогу. Для роботи використовувати компонент Memo.
Додайте на форму компонентів Savedialog. Задайте для нього властивості:
Filter: Filtername = Текстові файли, Filter = *.txt;
Defaultext = txt.
 
Код розрахунки може мати вигляд:
 
//описуємо змінну для розрахунки суми
var rez:real;
begin
//якщо користувач указав ім'я файлу й клацнув кнопку ОК
if savedialog1.execute=true then
begin
//лічимо суму
rez:=strtofloat(edit1.Text)+strtofloat(edit2.Text);
//очищаємо поле memo
memo1.Clear;
//у полі memo формуємо текст
memo1.Lines.Add('Вихідні дані:');
memo1.Lines.Add('-перше число = '+edit1.text);
memo1.Lines.Add('-друге число = '+edit2.text);
memo1.Lines.Add('Сума:'+floattostr(rez));
//зберігаємо вміст поля memo у зазначений файл
memo1.Lines.Savetofile(savedialog1.Filename);
end;
end; (початок) 
5. Робота з папками й файлами за допомогою функцій Win API
Існує можливість роботи з папками й файлами за допомогою функцій Win API. Дані функції вбудовані в саму операційну систему й можуть викликатися в будь-якому додатку на будь-якій мові програмування.
Так як ці функції є частиною ОС, то при їхньому виклику на екрані будуть з'являтися стандартні діалоги та інші вікна самої ОС. Наприклад:
при видаленні файлу або папки може видаватися стандартний запит на виконання операції, а сама інформація може поміщатися в Кошик;
при копіюванні або переміщенні великих порцій даних на екрані може відображатися вікно з індикатором часу, що залишився, і т.п.
Для використання таких функцій в Delphi необхідно підключати модуль Shellapi.
Розглянемо функцію виду:
 
Shfileoperation(параметри);
 
Дана функція дозволяє копіювати, переміщати, перейменовувати й видаляти файли й папки. При цьому всі операції за бажанням розробника можуть супроводжуватися стандартними вікнами операційної системи.
До параметрів відносять:
wfunc – тип операції. Даний параметр може приймати значення FO_COPY – копіювання, FO_MOVE – переміщення, FO_DELETE  – видалення, FO_RENAME – перейменування.
pfrom – вказівник на рядок з ім'ям вихідної папки або файлу. Для завдання вимагає дотримання ряду правил (див. приклад нижче).
pto – вказівник на рядок з ім'ям результуючої папки або файлу. Задається аналогічно параметру pfrom.
fflags – прапорці, що задають параметри операції. Можуть приймати значення: FOF_ALLOWUNDO – зберігає інформацію про можливе скасування операції; FOF_NOCONFIRMATION – відповідає "Так для всіх" на всі питання; FOF_SILENT – не показує прогрес бар, що відображає хід операції; FOF_SIMPLEPROGRESS – відображає вікно прогрес бару, але не показує імен файлів; OF_NORECURSION – не відображає користувацький інтерфейс при помилці, FOF_NOCONFIRMMKDIR  – не вимагає підтвердження створення нового каталогу. Якщо потрібно вказати кілька прапорців, то їх об'єднують операцією OR.
 
Приклад. Вилучити файл primer.txt із запитом і переміщенням файлу в кошик.
 
//змінна для завдання параметрів
var
p: tshfileopstruct;
begin
//усі параметри рівні 0
zeromemory(@p, sizeof(p));
//задаємо потрібні параметри
with p do
begin
//указуємо тип операції
wfunc:=fo_delete;
//указуємо ім'я файлу, що віддаляється
pfrom:=pchar(extractfilepath(application.exename)+ 'primer.txt' + #0);
//задаємо прапорець скасування операції (переміщення в кошик)
fflags:=fof_allowundo;
end;
//виконуємо видалення
shfileoperation(p);
end;
 
Незважаючи на те, що файл primer.txt знаходиться в одній папці із програмою, у коді довелося вказати повний шлях до файлу. Тільки в цьому випадку він буде поміщений у Кошик. Якщо вказати тільки ім'я файлу або папки без шляху, то об'єкт віддаляється без переміщення в Кошик, навіть якщо зазначений прапорець
 
fflags:=fof_allowundo;
 
Якщо не потрібно видавати запит на видалення файлу й не потрібно показувати індикатор видалення, то задайте прапорець
 
fflag:=fof_noconfirmation or fof_silent;
 
Для видалення папки замість імені файлу вкажіть ім'я папки. При цьому вилучити можна непусту папку разом з усім її вмістом. Зробити це за допомогою стандартних команд неможливо.
Операції копіювання, переміщення й перейменування виконуються аналогічно, але додатково потрібно вказати параметр pto, що задається аналогічно параметру pfrom.
Наприклад, скопіювати файл файл primer.txt у папку d:\files.
 
//змінна для завдання параметрів
var
p: tshfileopstruct;
begin
//усі параметри рівні 0
zeromemory(@p, sizeof(p));
//задаємо потрібні параметри
with p do
begin
//указуємо тип операції
wfunc:=fo_copy;
//указуємо ім'я файлу, що копіюється
pfrom:=pchar('primer.txt'+#0);
//указуємо папку для приймання файлу
pto:=pchar(d:\files\'+#0);
//прапорці за замовчуванням
fflags:=0;
end;
//виконуємо копіювання
shfileoperation(p);
end;
 
Скасувати операцію копіювання буде неможливо, тому що не зазначений повний шлях до вихідного файлу. Однак якщо записати параметр pfrom так:
 
pfrom:=pchar(extractfilepath(application.exename)+'primer.txt'+#0);
 
то скасування буде можливе.
При виконанні наведеної вище операції видається вікно з індикатором копіювання. Якщо в папці d:\files виявиться однойменний файл, буде видане вікно із запитом на перезапис файлу. Якщо ми хочемо виконати «тихе» копіювання без повідомлень і вікон, то потрібно включити прапори
 
fflag:=fof_noconfirmation or fof_silent; (початок) 
Питання для самоконтролю
1. Опишіть команди визначення поточної папки, створення, переходу й видалення папки. Приведіть приклади
2. Як з повного імені файлу витягти частини: диск, папка, ім'я файлу? Як перевірити існування папки? Як визначити повне ім'я файлу програми?
3. Який клас в Dephi дозволяє виконувати операції над файлами? Як створити екземпляр цього класу? Приведіть властивості й методи цього класу
4. Приведіть команди копіювання, перейменування й видалення файлів засобами команд Delphi. Приклади.
5. Які діалоги для роботи з файлами ви знаєте? Як створити й викликати такий діалог? Які властивості мають відповідні компоненти?
6. Яка функція Winapi дозволяє виконувати операції над папками й каталогами. Які параметри вона має?
Лекція № 8
Тема: «Прийоми роботи з формами. Компонент Richedit»
 
План
1. Створення програм з MDI інтерфейсом2. Реєстрація й MDI інтерфейс3. Робота з компонентом Richedit4. Приклад коректного відкриття й збереження файлів 
1. Створення програм із багатодокументним інтерфейсом
У додатку MDI є батьківська (первинна) форма й низка дочірніх форм (форм документів). Вікна документів можуть створюватися самим користувачем у процесі виконання додатка. Число дочірніх вікон заздалегідь невідомо – користувач може створити їх стільки, скільки йому буде потрібно. Вікна документів розташовуються в клієнтській області батьківської форми. Тому найчастіше доцільно в батьківській формі обмежуватися тільки головним меню, інструментальними панелями й, якщо необхідно, рядком статусу, залишаючи все інше місце у вікні для вікон дочірніх форм. При цьому звичайно вікно батьківської форми у вихідному стані розвертають на весь екран.
Для створення додатка MDI необхідно спроектувати батьківську й дочірню форми. У батьківській формі властивість Formstyle встановлюється в fsmdiform, а в дочірній – в fsmdichild.
За замовчуванням при запуску MDI додатка автоматично відображається й дочірня форма. Для усунення цього недоліку дочірню форму необхідно виключити із числа створюваних автоматично. Для цього виконайте команду Project – Option і на вкладці Forms перемістіть дочірню форму зі списку Auto-create forms у список Available forms.
Для виклику екземпляра дочірньої форми на екран можна використовувати наступний стандартний код:
 
var змінна:t<ім'я дочірньої форми>;
begin
    <змінна>:=t<ім'я дочірньої  форми>.create(self);
    <змінна>.show;
    <змінна>.repaint;
end;
 
Для того, щоб даний код працював, необхідно  в модулі головної форми підключити модуль дочірньої форми.
Нехай, наприклад, на батьківській формі Form1 є пункт меню Файл – Створити під ім'ям mnunew. Цей пункт дозволяє створити екземпляр дочірньої форми Form2. Для створення екземпляра дочірньої форми за допомогою меню необхідно:
за допомгою команди File – UseUnit ви повинні підключити модуль дочірньої форми;
в оброблювачі події, пов'язаного з вибором користувачем меню, можна написати код:
var f:tform2;
begin
    f:= tform2.create(self);
    f.show;
    f.repaint;
end;
 
У батьківської формі є ряд властивостей, що дозволяють керувати дочірніми вікнами. Усі вони доступні тільки для читання й тільки під час виконання.
Властивість Mdichildcount визначає кількість відкритих дочірніх вікон. Приведемо оператор, який можна вставити в попередній приклад для завдання унікального імені заново створеного вікна. 
 
f.caption : = 'Документ '+inttostr(mdichildcount);
 
Якщо створювати екземпляри дочірніх форм описаним вище способом, то користувач може відкрити як завгодно багато однакових форм документа. У більшості випадків це вірний підхід. Однак, іноді це не завжди доцільно. Для відкриття дочірньої форми тільки в одному екземплярі можна перевіряти властивість mdichildcount  як показано в наступному прикладі:
 
//якщо кількість відкритих дочірніх форм рівно 0
if mdichildcount=0 then    
//то відкриваємо дочірню форму    
begin           
    form2:=tform2.Create(self);           
    form2.Show;           
    form2.repaint;    
end;
 
У деяких програмах необхідно створювати різні види дочірніх форм по одному екземпляру для кожного виду.
Для вирішення цієї проблеми використовуються властивлості MDI форми:
- MDIChildCount - кількість відкритих дочірніх форм;
- MDIChildren - це масив, який містить загальне число відкритих дочірніх форм.  Кожен елемент цього масиву MDIChildren[i] - є окремою формою.Нумерація форм починається з 0.
Тому достатньо в коді перевіряти наявність в масиві форми потрібного виду. Якщо така форма знайдена, то вона вже була відкрита раніше і її створення не відбувається. Крім того дуже часто в програмах при спробі створити вже існуючу дочірню форму, програма замість створення робить цю форму активною.
 
Нехай є дві дочірні форми Form2 і Form3. На головній формі є два пункти меню (n2 і n3), кожний з яких відкриває по одному екземпляру дочірніх форм. Для розв'язання цього завдання потрібно написати код:
 
procedure TForm1.N21Click(Sender: TObject);
var i:integer;
begin
    //цикл по всіх дочірніх формах   
    for i := 0 to MDIChildCount - 1 do
        //якщо форма TForm2 уже створена       
        if (MDIChildren[I]is TForm2) then
        begin
            //якщо форма TForm2 згорнута користувачем           
            if MDIChildren[i].WindowState = wsMinimized then
                //форма розгортається до звичайного вигляду               
                MDIChildren[i].WindowState := wsNormal
            //якщо форма Form2 не згорнута           
            else
                //відображаємо форму Form2 поверх інших вікон               
                MDIChildren[i].BringToFront;
            //завершуємо процедуру, нова форма не створюється           
            Exit;
        end;
    //якщо форма Form2 не знайдена серед створених
    //створюємо її   
    Form2:=TForm2.Create(nil);
    //відображаємо форму на екрані
    Form2.Show;
    Form2.Repaint;
end;
 
Аналогічно напишемо код для пункту меню n3
 
procedure TForm1.N31Click(Sender: TObject);
var i:integer;
begin
    //цикл по всіх дочірніх формах   
    for i := 0 to MDIChildCount - 1 do
        //якщо форма TForm3 уже створена       
        if (MDIChildren[I]is TForm3) then
        begin
            //якщо форма TForm3 згорнута користувачем           
            if MDIChildren[i].WindowState = wsMinimized then
                //форма розгортається до звичайного вигляду               
                MDIChildren[i].WindowState := wsNormal
            //якщо форма Form3 не згорнута           
            else
                //відображаємо форму Form3 поверх інших вікон               
                MDIChildren[i].BringToFront;
            //завершуємо процедуру, нова форма не створюється           
            Exit;
        end;
    //якщо форма Form3 не знайдена серед створених
    //створюємо її   
    Form3:=TForm3.Create(nil);
    //відображаємо форму на екрані
    Form3.Show;
    Form3.Repaint;
end;
 
 
Для звертання до поточного екземпляра дочірньої форми головна форма має властивість Activemdichild. Для звертання до конкретного екземпляра дочірньої форми використовують запис виду:
 
(activemdichild as t<ім'я дочірньої форми>)
 
Для нашої дочірньої форми Form2 звертання запишеться так:
 
(activemdichild as tform2)
 
У момент створення вікон документів вони автоматично розташовуються каскадом у клієнтській області батьківської форми. Є низка методів батьківської форми, що впорядковують розміщення дочірніх вікон.
 
cascade; //розташовує всі відкриті (не згорнуті) вікна каскадом
 
tilemode:= tbvertical;
tile; //розташовує вікна ліворуч праворуч
 
tilemode:= tbhorizontal;
tile; //розташовує вікна зверху вниз
 
При закритті дочірньої форми викликом методу Close або за допомогою кнопки закриття форма не закривається, а згортається вниз головної форми. Для вирішення цієї проблеми необхідно в події Close дочірньої форми вставити код:
 
action:=cafree;
 
Проектування меню в MDI додатках
У головному вікні, коли немає дочірніх форм зазвичай відображається мінімальний набір команд меню. Як тільки відкривається дочірня форма, набір команд меню значно збільшується. Це досягається за рахунок того, що дочірня форма може мати власне меню, яке автоматично вбудовується в меню головної форми. При закритті дочірньої форми відбувається повернення меню в початковий стан.
Якщо потрібно, щоб меню вторинних форм поєднувалися з меню головної форми, то в кожній такій вторинній формі треба встановити властивість Automerge для компонента Mainmenu = true. При цьому властивість Automerge головної форми повинно залишатися в false.
Спосіб об'єднання меню визначається властивістю розділів Groupindex. За замовчуванням усі розділи меню мають однакове значення Groupindex, рівне нулю. Якщо потрібне об'єднання меню, то розділам треба задати неубутні номери властивостей Groupindex. Тоді, якщо розділи меню, що вбудовується, мають ті ж значення Grouplndex, що і якісь розділи меню основної форми, те ці розділи заміняють відповідні розділи основного меню. А якщо ні, то розділи допоміжного меню вбудовуються між елементами основного меню відповідно до номерів Groupindex. Якщо розділ, що вбудовується, має Groupindex менший, ніж кожний з розділів основного меню, то розділи вбудовуються в початок.
Тепер зупинимося на одному з питань, пов'язаних з меню в додатках MDI. У них користувач може відкривати стільки вікон документів, скільки йому потрібно. В подібних додатках є меню Вікно, яке містить такі розділи, як Нове, Упорядкувати й т.п. Останнім іде список відкритих вікон документів, у який заносяться назви відкритих користувачем вікон. Вибираючи в цього списку, користувач може перемикатися між вікнами документів.
Для включення в меню списку відкритих вікон, треба у властивості WindowMenu головної MDI форми додатка указати ім'я меню, у кінець якого повинен міститися список. Вказується саме ім'я меню, а не його розділів.
 
Відображення ярликів дочірніх форм
Використання списку дочірніх форм через пункт Меню є стандартним, але не завжди зручним. Для зручності користувача можна відображати всі дочірні форми як закладки (аналогічно з панеллю задач Windows). Для створення таких закладок можна використовувати спеціальні компоненти, наприклад, компонент MDIPanel, якого за замовченням немає в середовищі і він потребує встановлення. Для його використання достатньо нанести компонент на головну MDI форму і через властивість AlignPanel задати вид його розміщення (за замовченням внизу). (початок) 
2. Реєстрація й MDI інтерфейс
Якщо програма має головне MDI вікно, а також вікно реєстрації, яке з'являється раніше головної форми, то в цьому випадку виникає проблема. Це пов'язане з тим, що форма реєстрації є головною формою в проекті. По стандарту MDI форма завжди повинна бути головної. Тому при використанні вікна реєстрації коректна побудова MDI інтерфейсу стає проблематичним.
У цьому випадку доводиться вікно реєстрації відображати через код проекту до запуску основної програми.  Якщо пароль вірний, то запускається основна програма. Інакше - вихід.
Приклад. Нехай форма Form2 - це форма реєстрації. Форма не створюється автоматично (переміщена у список Available Forms) і при закритті видаляється з пам'яті (у події OnClose форми введіть команду Action:=caFree;).
На формі є поле для вводу пароля і дві кнопки. Треба перевірити пароль і, якщо він вірний, то "повідомити" про це головну програму і запустити її. Для "повідомлення" головної програми будемо використовувати глобальну змінну key, яка приймає значення: 0 - пароль не вірний, 1 - пароль вірний.
Опишемо глобальну змінну в коді форми Form2.
 
var key:integer=0;
 
Для другої кнопки напишемо код закриття форми:
 
procedure TForm2.Button2Click(Sender: TObject);
begin
    //форма закривається   
    close;
end;
 
Для першої кнопки напишемо код:
 
procedure TForm2.Button1Click(Sender: TObject);
begin
    //якщо пароль вірний
    if edit1.text='111' then
        //змінна приймає значення 1
        key:=1;
    //форма закривається
    close;
end;
 
В коді проекту введіть код, який відобразить форму реєстрації, а потім проаналізує значення змінної key і виконає відповідні дії.
 
begin
    //створюємо форму реєстрації
    Form2:=TForm2.Create(nil);
    //відображаємо форму для реєстрації
    Form2.ShowModal;
 
    //якщо змінна key=1 (пароль вірний)
    if key=1 then
    begin
        //створюємо головну форму і запускаємо програму
        Application.Initialize;
        Application.CreateForm(TForm1, Form1);
        Application.Run;
    end;  (початок) 
3. Робота з компонентом Richedit
Компонент Richedit (Win32) є вікном редагування багаторядкового тексту. Даний компонент має ті ж властивості, методи й події, що й компонент Memo. Однак компонент Richedit працює з текстом у збагаченому форматі RTF. При бажанні змінити атрибути виділеного фрагмента тексту ви можете задати властивість Selattributes. Наприклад, для форматування виділеного фрагмента за допомогою Fontdialog використовують команду виду:
 
if fontdialog1.execute=true then
    richeditl.selattributes.assign(fontdialog1.font);
 
За вирівнювання, відступи і т.д. у межах поточного абзацу відповідає властивість Paragraph. Ця властивість у свою чергу має ряд параметрів:
 
Alignment Визначає вирівнювання тексту. Може приймати значення taleftjustify (уліво), tacent(по  центру) або tarightjustify (вправо).
Firstindent Число пікселів відступу червоного рядка.
Numbering Керує вставкою маркерів, як у списках. Може приймати значення nsnone – відсутність маркерів, nsbullet – маркери ставляться.
Leftindent Відступ у пікселяах від лівого поля.
Rightindent Відступ у пікселях від правого поля.
 
Значення параметрів властивості Paragraph можна задавати тільки в процесі виконання. Значення параметрів властивості Paragraph стосуються до того абзацу, у якому перебуває курсор. Наприклад, кожний з наступних операторів здійснить відповідне вирівнювання поточного абзацу:
 
richeditl.paragraph.alignment:=taleftjustify; //уліво
richeditl.paragraph.alignment:=tacenter; //по центру
richeditl.paragraph.alignment:=tarightjustify; //вправо
 
Наступний оператор приведе до того, що поточний абзац буде відображатися як список, тобто з маркерами:
 
richeditl.paragraph.numbering:=nsbullet;
 
Знищення списку в поточному абзаці здійснюється оператором:
 
richeditl.paragraph.numbering:=nsnone; (початок) 
4. Приклад коректного відкриття й збереження файлівНехай на головній формі є пункт меню Файл – Відкрити під ім'ям mnuopen. Дана команда меню завантажує обраний файл у компонент Richedit, розташований на дочірній формі Form2.
 
procedure tform1.openexecute (sender:tobject);
//описуємо змінну для створення дочірньої форми
var f:tform2;
begin
if  opendialog1.execute=true then
begin
//відкриваємо нову дочірню форму
f:=tform2.create(application);
f.c=show;
//завантажуємо файл у компонент richedit1 на дочірній формі
(activemdichild as tform2).richedit1.lines.loadfromfile(opendialog1.filename);
//запам'ятовуємо повний шлях до файлу
(activemdichild as tfdoc).fname :=opendialog1.filename;
//у заголовку вікна відображаємо ім'я відкритого файлу
(activemdichild as tfdoc).caption:= extractfilename(opendialog1.filename);
end;
end;
 
Щоб наведений код працював необхідно на дочірнью форму додати компонент Label1. Дана компонент буде невидимим (Visible=False) і буде зберігати повне ім'я відкритого файлу, щоб надалі відредагований текст можна було зберегти в тому ж файлі.
При відкритіі форми даний компонент повинен очищатися. Для цього в події OnCreate форми введіть команду:
 
Label1.Caption:='';
 
Нехай на дочірній формі є пункт меню Файл – Зберегти як… під ім'ям mnusaveas. Дана команда зберігає у файл уміст компонента Richedit1.
 
procedure tform2.saveasexecute (sender:object)
begin
    //указуємо ім'я файлу із заголовка вікна
    savedialog1.filename:=caption;
    if savedialog1.execute=true then
    begin
        //зберігаємо компонент richedit1 на формі form2 у файл
        richedit1.lines.savetofile(savedialog1.filename);
        //запам'ятовуємо повне ім'я файлу, у який збережені дані
        label1.caption:=opendialog1.filename;
        //у заголовку вікна відображаємо ім'я файлу
        caption:= extractfilename(opendialogl.filename);
    end;
end;
 
Нехай у меню дочірньої форми є пункт Файл – Зберегти під ім'ям mnusave. Дана команда при збереженні нового файлу повинна відкрити діалог для введення імені файлу, а при збереженні існуючого файлу – переписати файл під наявним іменем.
 
procedure tform2.saveexecute (sender:object)
begin
    //якщо файл новий
    if label1.caption=’’ then
        //викликаємо метод для пункту меню зберегти як
        saveasexecute (sender)
    //якщо файл не новий
    else
        //перезберігаємо файл під наявним іменем
        richedit1.lines.savetofile(label1.caption);
end;
 
Особливості відкриття й збереження документів в Richedit
Компонент Richedit може працювати як з документами RTF, так і зі звичайними текстовими файлами. Властивість Plaintext (плаский текст) компонента Richedit визначає, з яким саме форматом працює Richedit при читанні з файлу й при записі у файл. За замовчуванням Plaintext = false, тобто компонент налаштований на роботу з форматом RTF. При Plaintext = true компонент налаштований на роботу зі звичайними текстовими файлами.
Якщо при відкриванні файлу властивість Plaintext = true, то навіть файл RTF відкриється як текстовий, тобто не будуть видні символи форматування. Якщо ж при відкриванні файлу властивість Plaintext рівно false — своєму значенню за замовчуванням, то в додатках він може відкривати й файли у форматі RTF, і файли «тільки текст».
Можливість збереження документів як у текстовому форматі, так і у форматі RTF, можна забезпечити в такий спосіб. У компоненті Savedialog треба встановити фільтри (властивість Filter):
 
у форматі rtf *.rtf
тільки текст *.txt
 
У властивості Defaultext треба задати розширення за замовчуванням «rtf», властиве першому фільтру.
При зміні користувачем фільтра в діалозі збереження файлу виникає подія Ontypechange компонента Savedialog. В оброблювачі цієї події треба задати залежно від властивості Filterindex (обраного фільтра) властивості Plaintext компонента Richedit і Defaultext компонента Savedialog:
 
//якщо обраний перший фільтр (rtf)
if savedialogl.filterlndex = 1 then
begin
    //указуємо формат тексту rtf
    richeditl.plaintext := false;
    //задаємо розширення за замовчуванням для файлів rtf
    savedialogl.defaultext := ‘rtf’;
end
//якщо обраний другий фільтр (txt)
else
begin
    //указуємо формат тексту txt
    richeditl.plaintext := true;
    //задаємо розширення за замовчуванням для текстових файлів
    savedialogl.defaultext := ‘txt’;
end;
 
Для відкриття файлу в різних форматах цей же код можна написати в події Ontypechange  для компонента Opendialog. (початок) 
Питання для самоконтролю
1. Як створити головну MDI форму? Як створити дочірню форму? Як звернутися до активної дочірньої форми? Як упорядкувати дочірні вікна усередині головної?
2. Як створити вікно непрямокутної форми? Опишіть основний порядок дій. Приклад
3. Як створити вікно у вигляді багатокутника. Опишіть основний порядок дій. Приклад
4. Опишіть принципи створення форми заставки в програмі. Приклад
5. Для чого потрібний компонент Richedit? Приведіть його основні властивості. Як можна форматувати виділений текст і абзаци в полі?
Лекція № 9
Тема: «Робота із графікою»
 
План
1. Компоненти для роботи із графікою2. Компонент Imagelist3. Робота з таймером4. Елементи анімації 
1. Компоненти для роботи із графікою
Нерідко виникає потреба прикрасити свій додаток якимись зображеннями. Для роботи із графічними файлами використовується компонент Image (Additional). Його властивість, яка може містити зображення - Picture. Натисніть на кнопку із трьома крапками біля цієї властивості або просто зробіть подвійне клацання на Image, і перед вами відкриється вікно Picture Editor, що дозволяє завантажити у властивість Picture який-небудь графічний файл (кнопка Load), а також зберегти відкритий файл під новим ім'ям або в новому каталозі.
Коли ви в процесі проектування завантажили зображення з файлу в компонент Image, він не просто відображає його, але й зберігає в додатку. Це дає вам можливість поставляти ваш додаток без окремого графічного файлу. Втім, в Image можна завантажувати й зовнішні графічні файли в процесі виконання додатка.
У компонента Image є ще низка важливих властивостей.
Якщо встановити властивість Autosize в true, то розмір компонента Image буде автоматично підгонятися під розмір поміщеної в нього картинки. Якщо ж властивість Autosize установлена в false, то зображення може не поміститися в компонент або, навпаки, площа компонента може виявитися багато більше площі зображення.
Інша властивість – Stretch дозволяє підгоняти не компонент під розмір малюнка, а малюнок під розмір компонента. Установіть Autosize в false, розтягніть або стисніть розмір компонента Image і установіть Stretch в true. Ви побачите, що малюнок займе всю площу компонента, але оскільки навряд чи реально вручну встановити розміри Image точно пропорційними розміру малюнка, то зображення спотвориться. Установлювати Stretch в true може мати сенс тільки для якихось візерунків, але не для картинок. Властивість Stretch не діє на зображення піктограм, які не можуть змінювати своїх розмірів.
Властивість Center, встановлене в true, центрує зображення на площі Image, якщо розмір компонента більше розміру малюнка.
Розглянемо ще одну властивість – Transparent (прозорість). Якщо Transparent рівно true, то зображення в Image стає прозорим. Це можна використовувати для накладення зображень один на одного. Урахуйте, що властивість Transparent діє тільки на файли у форматі BMP.
 
Створення форм із фоновим малюнком
Як відомо у форми є властивість Color, за допомогою якої можна задати для вікна будь-який колір фона. Але ваша програма може мати ще більш привабливий вигляд, якщо в якості фона форми вибрати графічне зображення. Для цього необхідно виконати дії:
нанесіть на форму компонент Image і в його властивості Align укажіть значення alclient. Це дозволить розтягти компонент Image до розмірів форми;
для компонента Image задайте властивість Stretch рівним True. Це дозволить автоматично підгоняти розмір зображення під розмір компонента;
для компонента Image у властивості Picture укажіть малюнок, який ви прагнете використовувати в якості фона.
Малюнок, поміщений у компонент Image, вбудовується в додаток, одже одержуваний файл програми збільшується на розмір графічного файлу.
 
Діалоги роботи із графічними файлами
В Delphi є компоненти для відкриття й збереження графічних файлів. Вони перебувають на вкладці Dialogs і називаються Openpicturedialog (Dialogs) і Savepicturedialog (Dialogs). Ці діалоги мають ті ж властивості й методи, що й стандартні діалоги по роботі з файлами. Відмінність у тому, що в самому діалоговому вікні є спеціальна область для попереднього перегляду вмісту графічних файлів.
Властивість Picture компонента Image у свою чергу має методи для відкриття й збереження файлів:
 
image.picture.loadfromfile(‘ім'я_файлу’); //відкрити файл
image.picture.savetofile(‘ім'я_файлу’); //зберегти файл
 
Команда відкриття файлу може мати вигляд:
 
if openpicturedialog1.execute=true then
    image1.picture.loadfromfile(openpicturedialog1.filename);
 
Команда збереження файлу може мати вигляд:
 
if savepicturedialog1.execute=true then
    image1.picture.savetofile(savepicturedialog1.filename);
 
Збереження графіки у різних форматах
За замовченням Delphi зберігає всі зображення у форматі bmp незалежно від того, яке розширення файлу ви вкажете. Для зберігання в інші формати треба використовувати спеціальні модулі итипи даних для конвертування інформації.
 
1. Збереження у форматі BMP.
 
Формат BMP підпримується автоматично.
Приклад. На формі є компонент Image із зображенням. Необхідно зберегти це зображення у форматBMP.
 
//змінна для роботи із графікою в форматі BMP
var bmp:TBitMap;
begin
    //якщо користувач не вказав ім'я для збереження файлу
    //програма завершує роботу
    if not savepicturedialog1.Execute then exit;
 
    //створюємо екземпляр змінної
    bmp:= TBitMap.Create;
    //в змінну загружаємо рисунок із компонента Image (конвертуємо автоматично)
    bmp.Assign(image1.Picture.Graphic);
    //задаемо розширення для файлу
    savepicturedialog1.defaulext:='bmp';
    //зберігаємо файл на диску
    bmp.SaveToFile(savepicturedialog1.filename);
    //видаляємо змінну
    bmp.Free;
end;
 
2. Збереження у форматі JPG.
 
Для роботи з цим форматом існує стандартний модуль JPEG, який потрібно підключити в додатку.
Приклад. Попередній приклад перепишемо для збереження зображення у форматі JPG
 
//змінна для роботи із графікою в форматі JPG
var jpg:TJpegImage;
begin
    //якщо користувач не вказав ім'я для збереження файлу
    //програма завершує роботу
    if not savepicturedialog1.Execute then exit;
 
    //створюємо екземпляр змінної
    jpg:= TJpegImage.Create;
    //в змінну загружаємо рисунок із компонента Image (конвертуємо автоматично)
    jpg.Assign(image1.Picture.Graphic);
    //задаемо розширення для файлу
    savepicturedialog1.defaulext:='jpg';
    //зберігаємо файл на диску
    jpg.SaveToFile(savepicturedialog1.filename);
    //видаляємо змінну
    jpg.Free;
end;
 
3. Збереження у форматі GIF.
 
Для роботи з цим форматом треба використовувати зовнішній модуль GifImage, якого немає в Delphi. Для використання цього модуля скопіюєте файлgifimage.pas в теку з вашим проектом і підключіть модуль GifImage в коді програми.
Приклад. Попередній приклад перепишемо для збереження зображення у форматі GIF
 
//змінна для роботи із графікою в форматі GIF
var gif:TGifImage;
begin
    //якщо користувач не вказав ім'я для збереження файлу
    //програма завершує роботу
    if not savepicturedialog1.Execute then exit;
 
    //створюємо екземпляр змінної
    gif:= TGifImage.Create;
    //в змінну загружаємо рисунок із компонента Image (конвертуємо автоматично)
    gif.Assign(image1.Picture.Graphic);
    //задаемо розширення для файлу
    savepicturedialog1.defaulext:='gif';
    //зберігаємо файл на диску
    gif.SaveToFile(savepicturedialog1.filename);
    //видаляємо змінну
    gif.Free;
end;
 
4. Збереження у форматі PNG.
 
Для роботи з цим форматом треба використовувати зовнішній модуль PNGImage, якого немає в Delphi. Для використання цього модуля скопіюєте вміст текиPNGImage в теку з вашим проектом і підключіть модульPNGImage в коді програми.
Особливістю роботи цього формату є те, що зображення спочатку конвертується в BMP, а потім - в PNG.
Приклад. Попередній приклад перепишемо для збереження зображення у форматі PNG
 
//змінна для роботи із графікою в форматі BMP та PNG
var bmp: TBitMap;
    png: TPNGObject;
begin
    //якщо користувач не вказав ім'я для збереження файлу
    //програма завершує роботу
    if not savepicturedialog1.Execute then exit;
 
    //створюємо екземпляр змінної  для BMP формату
    bmp:= TBitMap.Create;
    //в змінну загружаємо рисунок із компонента Image (конвертуємо автоматично)
    bmp.Assign(image1.Picture.Graphic);
    //створюємо екземпляр змінної  для PNG формату
    png:= TPNGObject.Create;
    //в змінну загружаємо BMP зображення
    png.Assign(bmp);
    //задаемо розширення для файлу
    savepicturedialog1.defaulext:='png;
    //зберігаємо файл на диску
    png.SaveToFile(savepicturedialog1.filename);
    //видаляємо змінну
    png.Free;
end;
Робота з буфером обміну
Існує можливість обмінюватися графічною інформацією через буфер обміну. Для цього можна використовувати спеціальний об'єкт Clipboard, що має методи копіювання й вставки. Для роботи із цим об'єктом потрібно в коді форми підключити модуль Clipbrd.
Для копіювання вмісту компонента Image у буфер обміну можна використовувати код:
 
clipboard.assign(image1.picture);
 
Для вирізання вмісту компонента Image у буфер обміну можна використовувати код:
 
clipboard.assign(image.picture);
//очищаємо компонент image1
image1.picture:=nil;
 
Вставка вмісту буфера обміну в компонент Image пов'язана із проблемою формату даних. Якщо в буфері перебуває текст, то спроба вставки приведе до помилки. Тому потрібно перевіряти формат інформації в буфері перед вставкою. Це можна зробити за допомогою коду:
 
//якщо в буфері обміну графічна інформація
if clipboard.hasformat(cf_picture) then
    //вставляємо вміст буферу обміну
    image1.picture. assign(clipboard);
 
Об'єкт Clipboard має спеціальний метод Hasformat, що дозволяє визначити формат даних у буфері обміну. Даний метод може приймати значення:
CF_Text – текстові дані;
CF_Picture – графіка. (початок)2. Компонент Imagelist
Компонент Imagelist (Win32) уже розглядався раніше як сховище зображень для панелей інструментів, меню й інших компонентів. Однак даний компонент може не тільки відображати свій вміст на кнопках, вкладках і в меню. В Imagelist є спеціальний метод, що дозволяє прочитати будь-який малюнок з колекції й відобразити його на формі в компоненті Image.
Метод має вигляд:
 
imagelist.getbitmap(index,bitmap);
Index – номер картинки в Imagelist;
Bitmap – це змінна типу Tbitmap.
Зчитування зображення за допомогою даного методу можна виконати за допомогою коду:
 
//описуємо змінну типу tbitmap
var a:tbitmap;
begin
    //створюємо екземпляр цієї змінної
    a:=tbitmap.create;
    //зчитуємо зображення з index=0 у змінну
    imagelist1.getbitmap(0,a);
    //відображаємо змінну в компоненті
    image1image1.picture.assign(a);
end; (початок) 
3. Робота з таймером
Timer (System) – це спеціальний компонент, що дозволяє виконати певну дію через заданий проміжок часу: сховати вікно форми-заставки, організувати анімаційний рух фігур і т.п. Компонент є невидимим і може розташовуватися в будь-якім місці форми.
Компонент має наступні властивості:
Enabled – включає або виключає таймер;
Interval – задає в мілісекундах інтервал, через який спрацьовує таймер. (1 с = 1000 мс)
Нехай є компонент Imagelist з 5 картинками. Написати код, що відображає ці картинки в компоненті Image по черзі через певний інтервал часу.
У події таймера Ontimer напишіть код:
 
//зчитуємо k-є зображення в змінну а
imagelist1.getbitmap(k,a);
//відображаємо зображення в компоненті image
image1.picture.assign(a);
//якщо поточне зображення не останнє
if k<4 then
    //переходимо до наступного
    k:=k+1
//якщо поточне зображення останнє
else
    //переходимо на перше
    k:=0;
 
Щоб наведений код працював необхідно:
описати змінну k як глобальну цілого типу, а змінну a як глобальну типу Tbitmap;
у події форми Oncreate задати початкові значення описаним змінним:
k:=0;
a:=tbitmap.create;
у властивості таймера Interval укажіть потрібний інтервал часу.
на формі-заставці розмістіть компонент Timer, і в його властивості Interval укажіть значення 3000 (3 секунди);
для таймера введіть код:
//видаляємо з пам'яті форму-заставку
destroy;
//відкриваємо форму form2
form2.show;
щоб при закритті форми Form2 програма завершувала свою роботу, необхідно в події цієї форми Oncreate ввести команду:
halt; (початок) 
4. Елементи анімації
 
Анімація форм
 
Для побудови привабливого інтерфейсу ля появи або закриття форми можна задавати ефекти анімації. Дл цього використовуються спеціальні API функціяWindows:
 
AnimateWindow (Handle, час (в мс), ефекти);
 
Анімація виконується протягом часу, який заданий в якості другого параметру функції.
Ефекти - це перелік констант, які дозволяють задати параметри анімації. Для задавання декількох ефектів їх об'єднуть за допомогою операції OR. Кожен ефект - це числова константа:
$10 - анімація з центру (з точки);
$20000 - після анімації зробити вікно активним (на передній план);
$40000 - анімація як слайд. Тип слайду задається за допомогою констант: $1 - зліва направо, $2 - зправа наліво, $4 - зверху вниз, $8 - знизу вверх;
$80000 - анімація як проявлення;
$10000 - до ефекту анімації додається параметр закриття вікна.
 
Приклад. Нехай форма з'являється з ефектом анімації із точки по центру екрана.
У події форми OnShow напишемо код:
 
procedure TForm1.FormShow(Sender: TObject);
begin
    //центруємо форму на екрані
    Left:= (Screen.Width - Width)div 2;
    Top:= (Screen.Height - Height)div 2;
    //задаємо анімацію і робимо окно активним
    AnimateWindow(Handle, 1000, $10 OR $20000);
end;
 
Закриємо форму як слайд зліва направо.
У події форми OnClose напишемо код:
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    //вікно як слайд зліва направо закривається
    AnimateWindow(Handle, 1000, $40000 OR $1 OR $10000);
end;
 
Анімація компонентів
 
Анімація передбачає ефект руху компонентів по формі. Для створення ефекта анімації в кожного компонента використовують властивості:
Left – задає відступ компонента від лівого краю форми в пікселях. При збільшенні властивості компонент рухається вправо, при зменшенні – уліво;
Top – задає відступ компонента від верхнього краю форми в пікселях. При збільшенні властивості компонент рухається вниз, при збільшенні – нагору.
Рух можна виконувати автоматично за допомогою таймера або при натисканні на клавіші (наприклад, стрілок керування курсором).
При русі компонентів по формі іноді потрібно визначити факт досягнення компонентом краю форми. У цьому випадку у форми є властивості, які зберігають дійсний розмір форми без її границь і рядка заголовка. Ці властивості мають імена Clientwidth (ширина) і Clientheight (висота).
Нехай є форма вигляду:
 

 
На формі є компонент Shape (Additional). За допомогою таймера організувати рух компонента по формі з ефектом пролистування залежно від обраного напрямку за допомогою перемикачів Radiogroup.
Для таймера напишемо код:
 
procedure tform1.timer1timer(sender: tobject);
begin
    //аналізуємо обраний перемикач
    case radiogroup1.itemindex of
    //якщо обраний перший перемикач
    0:
        if shape1.left<=clientwidth-shape1.width then
            shape1.left:=shape1.left+1
        else
            shape1.left:=-shape1.width;
    //якщо обраний другий перемикач
    1:
        if shape1.left>=-shape1.width then
            shape1.left:=shape1.left-1
        else
            shape1.left:=clientwidth;
    //якщо обраний третій перемикач
    2:
        if shape1.top<=clientheight-shape1.height then
            shape1.top:=shape1.top+1
        else
            shape1.top:=-shape1.height;
    //якщо обраний четвертий перемикач
    3:
        if shape1.top>=-shape1.height then
            shape1.top:=shape1.top-1
        else
            shape1.top:=clientheight;
    end;
end;
 
Перепишемо приклад, створивши анімацію з ефектом відскоку від країв форми. Нехай форма має вигляд:
 

 
Для організації відскоку на формі потрібно розмістити два компоненти Timer. Timer1 буде переміщати фігуру по горизонталі, а Timer2 – по вертикалі.
На формі за замовчуванням обраний перший перемикач, тому для компонента Timer2 установимо властивість Enabled=False.
Для таймера Timer1 напишемо код:
 
//якщо фігура торкнулася лівого краю форми
if shape1.left<=0 then
    //міняємо напрямок руху
    h:=1
//якщо фігура торкнулася правого краю форми
else if shape1.left>=clientwidth-shape1.width then
    //міняємо напрямок руху
    h:=-1;
//зміщуємо фігуру по формі
shape1.left:=shape1.left+h;
 
Для компонента Timer2 напишемо код:
 
//якщо фігура торкнулася верхнього краю форми
if shape1.top<=0 then
    //міняємо напрямок руху
    v:=1
//якщо фігура торкнулася нижнього краю форми
else if shape1.top>=clientheight-shape1.height then
    //міняємо напрямок руху
    v:=-1;
//зміщуємо фігуру по формі
shape1.top:=shape1.top+v;
 
При виборі напрямку руху ми буде активувати потрібний таймер для руху фігури. Для компонента Radiogroup у події Onclick напишемо код:
 
case radiogroup1.itemindex of
//якщо обраний перший перемикач
0:
    begin
        //активуємо тільки перший таймер
        timer1.enabled:=true;
        timer2.enabled:=false;
    end;
//якщо обраний другий перемикач
1:
    begin
        //активуємо тільки другий таймер
        timer1.enabled:=false;
        timer2.enabled:=true;
    end;
//якщо обраний третій перемикач
2:
    begin
        //активуємо обоє таймера
        timer1.enabled:=true;
        timer2.enabled:=true;
    end;
end;
 
Для роботи наведених кодів необхідно виконати ряд додаткових операцій:
змінні V і H повинні бути описані як глобальні цілого типу;
у події форми Oncreate необхідно задати початкові значення для змінних:
v:=-1;
h:=-1; (початок) 
Питання для самоконтролю
1. Опишіть компонент Delphi, призначений для відображення графічної інформації на формі.
2. Які діалоги для роботи із графічними файлами ви знаєте? Приведіть приклади їх використання.
3. Опишіть принципи роботи із графікою через буфер обміну. Приклади.
4. Опишіть компонент Imagelist. Як виконати читання зображення із цього компонента? Приведіть приклад.
5. Опишіть призначення й принцип роботи з таймером.
Лекция № 10
Тема: "Работа с данными типа Дата/Время"
 
План
1. Понятие и назначение типа TDateTime. Генерирование Даты/Времени.
2. Выделение частей из  Даты/Времени
3. Функции преобразования Даты/Времени в текст
4. Функции расчета Даты/Времени. Сравнение Даты/Времени
5. Компоненты для работы с датами
 
1. Понятие и назначение типа TDateTime. Генерирование Даты/Времени.
Для хранения даты, времени или обоих значений сразу в Delphi имеется тип TDateTime. Переменная такого типа сохраняется как переменная Double, с датой в целой части, а временем в дробной. Дата сохраняется как число дней с 30 декабря 1899. 
Поскольку TDateTime фактически является Double, то вы можете выполнять над ним вычисления, как будто это было число. Это очень полезно для вычислений типа разницы между двумя датами.
Если переменную изменить на целое число, то фактически дата изменяется на такое количество дней.
Для пользователя записывать дата или время в виде чисел неудобно, поэтому существует несколько способов генерирования значений Даты/Времени для следующей обработки. Рассмотрим их:
- day - генерирует текущую дату (дата берется с системных часов компьютера пользователя)
- time - генерирует текущее время (время берется с системных часов компьютера пользователя)
- now - генерирует текущую дату и время.
 
Пример:
 
var d,t,dt:tdatetime;
begin
    d:=date; //сегодняшнее число
    t:=time; //текущее время
    dt:=now; //текущая дата и время
 
Продемонстрируем возможности вычисления дат:
 
    d:=date-1; //вчерашняя дата
    d:=date+1; //завтрашняя дата и т.п.
 
Если нужно записать произвольную дату, то ее привычнее задавать в текстовом формате, а затем конвертировать в тип TDateTime. Для этого используются функции:
 
- StrToDate(текст) - конвертирует дату в тип TdateTime
- StrToTime(текст) - конвертирует время в тип TDateTime
- StrToDateTime(текст) - конвертирует даты и время в тип TDateTime
 
Пример:
 
var d,t,dt:tdatetime;
begin
    d:=StrToDate('15.01.2014'); //записали в переменную дату
    t:=StrToTime('12:45'); //записали в переменную время
    dt:=StrToDateTime('15.01.2014 12:45'); //записали в переменную дату и время
 
Существует еще один способ генерирования дат, в котором каждая часть даты или времени задается с помощью целых чисел:
 
- encodedate(год, месяц, день) - генерирует дату
- encodetime(часы, минуты, секунды, миллисекунды) - генерирует время
- encodedatetime(год, месяц, день, часы, минуты, секунды, миллисекунды) - генерирует дату и время
 
Пример:
 
var d,t,dt:tdatetime;
begin
    d:=encodedate(2014,1,15); //генерируется дата 15.01.2014
    t:=encodetime(12,45,0,0); //генерируется время 12:45:00
    dt:=encodedatetime(2014,1,15,12,45,0,0); //генерируется 15.01.2014 12:45:00
 
2. Выделение частей из  Даты/Времени
При работе с типом TDateTime часто возникает необходимость выделить из значения его часть. Для выполнения этого существуют специальные функции, которые описаны в модуле DateUtils. Следовательно перед их использование нужно подключить данный модуль. рассмотрим эти функции:
 
- dayof(дата) - выделяет номер дня
- monthof(дата) - выделяет номер месяца
-dayofweek(дата) - выделяет номер дня недели (1 - воскресенье)
- dayoftheweek(дата) - похожа на предыдущую, но 1 - понедельник
- yearof(дата) - выделяет год из даты
- hourof(время) - выделяет часы из времени
- minuteof(время) - выделяет минуты из времени
- secondof(время) - выделяет секунды из времени
- currentyear - текущий год
 
Примеры
 
var d,m,w,y:integer;
h,n,s:integer;
begin
    d:=dayof(date); //текущий день
    m:=monthof(date); //текущий месяц
    w:=dayofweek(date); //номер текущего дня недели
    y:=yearof(date); //текущий год. Можно записать и так: y:=currentyear;
    h:=hourof(time); //значение часов в текущий момент
    n:=minuteof(time); //значение минут в текущий момент
    s:=secondof(time); //значение секунд в текущий момент
 
Иногда название месяца или название дня недели нужно отображать как текст (в краткой или полной форме). Для этого в Delphi используются встроенные массивы текстовых названий:
 
longmonthnames=(Январь, Февраль, Март и т.д.);
shortdatenames=(Янв, Фев, Мар и т.д.);
longdaynames=(Воскресенье, Понедельник, Вторник и т.д.)
shortdaynames=(Вс, Пн, Вт и т.д.)
 
Пример:
 
var s:string;
begin
    s:=longmonthnames[4]; //4-й месяц Апрель
    s:=shortmonthnames[8]; //8-й месяц Авг
    s:=longmonthnames(monthof(date)); //полное название текущего месяца
    s:=longdaynames[2]; //Понедельник, так как 1 - это Воскресенье
    s:=longdaynames[dayofweek(date))]; //полное название текущего дня недели
 
Существую процедуры, которые разбивают значение TDateTime сразу на все составляющие и записывают результат в отдельные переменные:
 
- decodedate(дата, год, месяц, день); //разбирает дату на день, месяц, год
- decodetime(время, часы, минуты, секунды, миллисекунды); //разбирает время на составляющие
- decodedatetime(дата/время, год, месяц, день, часы, минуты, секунды, миллисекунды); //разбирает дату/время на составляющие
 
Пример:
 
var y,m,d:integer;
h,n,s,ms:integer;
begin
    decodedate(date,y,m,d); //разбирает текущую дату в переменные y,m,d
    decodetime(time,h,n,s,ms); //разбирает текущее время в переменные h,n,s,ms
    decodedatetime(now, y,m,d,h,m,s,ms); //разбирает дату и время в переменные
 
3. Функции преобразования Даты/Времени в текст
Как было сказано выше, значения Даты/Времени хранится в памяти как вещественное число, что совсем не удобно для восприятия пользователем. Для вывода таких значений на форму необходимо преобразовывать их в удобный текстовый вид. Для этого существует ряд функций:
 
- datetostr(дата) - преобразовать дату в текст
- timetostr(время) - преобразовать время в текст
- datetimetostr(дата и время) - преобразовать дату и время в текст
 
Пример
 
var d:tdatetime;
begin
    d:=now;
    showmessage('Сегодня: '+datetostr(d));
    showmessage('Текущее время: '+timetostr(d));
    d:=d+10;
    showmessage('Через 10 дней будет: '+datetimetostr(d));
 
Форматирование вывода
При конвертировании значений Дата/Время в текст используется формат, принятый в настройках операционной системы конкретного пользователя. Если нужно представить значения в ином флромате, то для конвертирования используйте функцию вида:
 
formatdatetime('format' ,дата/время)
 
Параметр format может содержать следующие символы:
 
d - день
m - месяц
y - год
h - часы
n - минуты
s - секунды
/ - разделитель дат
: - разделитель времени
"" - символ, заключенный в кавычки воспринимается именно как символ
Остальные символы отображаются как в шаблоне:
 
Пример:
 
var d:tdatetime;
begin
    d:=now;
    showmessage('Дата в обычном формате: '+formatdatetime('dd/mm/yyyy',d)); // дд.мм.гггг
    showmessage('Дата в формате Access: '+formatdatetime('#mm"/"dd"/"yyyy#',d)); // #мм/дд/гггг#
    showmessage('Дата в формате MySQL: '+formatdatetime('mm-dd-yyyy',d)); // мм-дд-гггг
 
4. Функции расчета Даты/Времени. Сравнение Даты/Времени
Для выполнения расчетов можно использовать простые арифметические операции + и -. В этом случае вы можете найти разницу между датами или перейти вперед на указанную дату.
Если к дате прибавить или от даты отнять целое число, то дата изменится на заданное количество дней.
Также можно использовать функции вида:
 
daysbetween(дата, дата) - число дней между датами
monthsbetween(дата, дата) - число месяцев между датами
yearsbetween(дата, дата) - число лет между датами
hoursbetween(дата, дата) - число часов между датами
minutesbetween(дата, дата) - число минут между датами
secondsbetween(дата, дата) - число секунд между датами
 
Для изменения даты или времени используют функции:
 
incday(дата, число) - изменяет дату на число дней
incmonth(дата, число) - изменяет дату на число месяцев
incyear(дата, число) - изменяет дату на число лет
inchour(дата, число) - изменяет дату на число часов
incminute(дата, число) - изменяет дату на число минут
incsecond(дата, число) - изменяет дату на число секунд
 
Пример.
 
var d:tdatetime;
begin
    d:=incday(now,-1); //получили вчерашнюю дату
    d:=incmonth(now,1); //получили этот же день в следующем месяце
    d:=inchour(now,100); //получили дату, которая наступит через 100 часов от текущего момента
 
Для сравнения дата и времени используют стандартные операции отношения =, <>, >, >=, <, <=. Также существует функция сравнения даты и времени:
 
Пример:
 
var a,b:tdatetime;
begin
a:=strtodate('05.01.2014');
b:=strtodate('10.01.2014');
 
a>b - false
a<b - true
5. Компоненты для работы с датами
Для работы с датами желательно использовать компоненты, которые защитят пользователя от ошибок ввода. К таким компонентам относятсяDateTimePicker (Win32) и MonthCalendar (Win32). Оба компонента имеют идентичные свойства, но отличаются внешним видом: первый компонент - это поле с раскрывающимся календарем, второй - это календарь на отдельный месяц. Первый экономит место на форме, второй - более наглядный, так как сразу отображает все даты месяца.
Основные свойства компонентов:
 
CalColors - параметры цветов разных частей календаря;
Date - дата, выбранная в календаре;
DateFormat - формат отображения даты (Short - обычный формат, Long - месяц отображается текстом);
MaxDate - максимально допустимая дата
MinDate - минимально допустимая дата.
Лекція № 10
Тема: «Робота з базами даних в Delphi. Компоненти для доступу до даних»
 
План
1. Створення з'єднання з базою даних2. Робота з таблицею бази даних3. Створення форм для роботи з даними БД4. Комбінування  табличних і сторінкових форм5. Методи й властивості для роботи з даними в таблиці 
1. Створення з'єднання з базою даних
Для доступу до бази даних в Delphi є кілька способів. Кожний зі способів використовує свої компоненти, розміщені на різних закладках компонентів. Найпоширенішою є технологія ADO. Дана технологія забезпечує можливість підключення як локальних, так і сітьових баз даних. Відрізняється легкістю й простотою роботи, підтримує всі поширені формати баз даних, дозволяє публікувати дані в Інтернет і т.п.
Усі компоненти, необхідні для роботи з даними знаходяться на вкладці ADO.
Для роботи з базою даних необхідно виконати підключення до фізичної бази даних, розташованої на диску комп'ютера або в мережі. Для цього служить компонент Adoconnection, який при запуску програми не бачимо на формі. Для установки з'єднання із БД нанесіть на форму компонентів Adoconnection (ADO). У його властивості Connectionstring клацніть на кнопці із трьома крапками. Відкриється вікно настроювання параметрів з'єднання. У цьому вікні клацніть на кнопці Build для віддкриття вікна задавання параметрів підключення до БД.
Для підключення бази Access виберіть тип бази даних Microsoft Jet і клацніть Далі, на наступній закладці вкажіть ім'я бази даних (після вибору файлу треба відредагувати повне ім’я цього файлу, щоби програма на була прив’язана до конкретної папки) . За допомогою кнопки Перевірити підключення можна перевірити з'єднання. Якщо БД Access має пароль, то при натисканні на кнопку Перевірити підключення буде видане вікно з повідомленням про невірний пароль. Для завдання пароля перейдіть на закладку Всі й у рядку Jet OLEDB: Database Password уведіть пароль доступу.
Для підключення бази SQL Server виберіть тип бази даних Microsoft OLE DB Provider for SQL Server і клацніть Далі, на наступній закладці вкажіть ім'я сервера, в якості значення для перемикача «Для входа на сервер использовать» виберіть «Учетные сведения Windows NT», в вписку виберіть потрібну базу данихяка розміщена на сервері. За допомогою кнопки Перевірити підключення можна перевірити з'єднання.
Компонент ADOConnection при запуску програми завжди відображає вікно для реєстрації користувача: треба ввести логін та пароль. Якщо цього робити не потрібно, то змініть властивість Loginprompt компонента на значення false. Це відключить появу вікна реєстрації. (початок) 
2. Робота з таблицею бази даних
Кожна база даних має як мінімум одну таблицю, а в реальних програмах таблиць звичайно більше однієї. Після з'єднання з базою даних за допомогою компонента Adoconnection ми повинні вказати ім'я таблиці, з якої буде працювати поточна форма. Для доступу до таблиці бази даних використовуйте компонент Adotable (ADO). Даний компонент не видимий на формі під час роботи програми. Його основні властивості:
- Connection – вказується ім'я з'єднання з базою даних;
- Tablename – ім'я таблиці БД;
- Active – якщо рівно true, то таблиця підключена до програми і її дані доступні для перегляду й редагування. Дану властивість не рекомендується встановлювати при проектуванні, підключення таблиці треба проводити при запуску програми.
Для підключення потрібної таблиці  в події Oncreate відповідної форми необхідно вставити команду:
 
adotable1.active:=true;
 
При видаленні форми з пам'яті необхідно відключати таблицю. Для цього в події Ondestroy форми необхідно вставити команду:
 
adotable1.active:=false;
 
Робота з полями таблиці
За замовчуванням на формі відображаються всі поля таблиці. При цьому заголовок поля і його ширина відповідаємо значенням, які були зазначені при проектуванні таблиці в СУБД. Це не завжди зручно й можна дані параметри змінювати.
Для роботи з полями таблиці виконайте подвійне клацання на компонента Adotable. У результаті відкриється вікно редактора полів таблиці. Клацніть у цьому вікні правою кнопкою миші й виберіть команду ADD ALL FIELDS. У вікні редактора полів відобразяться всі поля тієї таблиці, яка пов'язана з поточним компонентом Adotable.
Поля в списку можна переміщати, змінюючи тим самим їхній порядок відображення на формі.
Виділивши потрібне поле можна для нього задати наступні властивості:
Alignment – вирівнювання тексту;
Defaultexpression – значення за замовчуванням;
Displayformat – формат відображення даних. Використовується для числових полів і полів типу дата/час;
Displaylabel – заголовок поля, відображуваний на формі;
Displaywidth – ширина поля в символах;
Editmask – маска введення значень у поле;
Name – ім'я поля для звертання до нього в коді програми. Рекомендується, щоб значення даного властивості збігалося зі справжнім ім'ям поля в таблиці БД;
Readonly – забороняє або дозволяє зміну значення в полі;
Visible – відображає або приховує поле таблиці.
Для коректної роботи рекомендується завжди додавати всі поля, а потім непотрібні приховувати від перегляду (visible=false).
 
Звертання до значення потрібного поля
Часто при написанні коду програми потрібно звернутися до значення конкретного поля поточного запису таблиці. Це значення може використовуватися в розрахунках або його можна перевірити за допомогою умови й т.п.
Для звертання до поля таблиці використовується фізичне ім'я поля в таблиці БД або ім'я поля, зазначене у властивості name редактора полів Adotable.
По імені поля в таблиці до нього можна звернутися за допомогою запису:
 
adotable1.fieldbyname(‘ім'я_поля’).value;
 
Нехай у таблиці є поле oklad, тоді звернутися до нього можна за допомогою запису:
 
adotable1.fieldbyname(‘oklad’).value;
 
Замість властивості value можна використовувати властивість as тип:
 
adotable1.fieldbyname(‘ім'я_поля’).asтип
 
Тип – це тип даних, до якого автоматично конвертується значення зазначеного поля таблиці.
Нехай у таблиці є поле oklad. Значення даного поля потрібно отримати як число для розрахунків. Тоді звернутися до нього можна за допомогою запису:
 
adotable1.fieldbyname(‘oklad’).asfloat
 
Нехай значення цього ж поля потрібно вивести у функції Showmessage. Тобто значення поля потрібно із числового формату конвертувати в строковий. У цьому випадку запис команди буде мати вигляд:
 
showmessage(adotable1.fieldbyname(‘oklad’).asstring);
 
Всі розглянуті приклади звертаються до поля по його імені в таблиці БД. Такий запис довгий. Зверенення до поля можна записати кортоше, якщо звертатися до нього за допомогою властивості name. Нехай у таблиці є поле oklad, для якого через редактор полів задана властивість name=adooklad. Для звертання до цього поля припустимий запис:
 
adooklad.value
 
Для конвертування значення поля в потрібний формат припустимий запис:
 
adooklad.asfloat – конвертування в число
adooklad.asstring – конвертування в текст
 
Створення полів, що обчислюються
У редакторі полів можна створювати поля, що обчислюються: поля, яких фізично немає в таблиці БД, але їх значення автоматично розраховуються на підставі даних з інших полів.
Для створення такого поля зробіть подвійне клацання на компоненті Adotable для відкриття вікна редактора полів, у контекстному меню вікна редактора виберіть команду New Field, укажіть перемикач Calculated, ім'я й тип поля. Кожна таблиця може мати кілька обчислювальних полів.
Якщо в таблиці є поле, що обчислюється, то для компонента Adotable у події Oncalcfields необхідно написати код, що містить потрібні формули для одержання значень таких полів. При цьому звертання до значень полів таблиці здійснюється за допомогою команд, розглянутих вище.
Приклад: Нехай у таблиці є поле srbal для зберігання середнього бала студента. Це поле в редакторі Adotable має властивість name=adosrbal. поле, що обчислюється, стипендія (stip) потрібно розрахувати по формулі: середній бал*50. При цьому стипендію отримують тільки студенти із середнім балом від 4 і вище.
 
Напишемо код при звертанні до полів таблиці по їхнім іменам у базі даних.
У події Oncalcfields компонента Adotable напишемо код:
 
procedure tform1.adotable1calcfields(dataset: tdataset);
begin
if adotable1.fieldbyname(‘srbal’).asfloat>= 4 then
adotable1.fieldbyname(‘stip’).value=adotable1.fieldbyname(‘srbal’).asfloat*50
else
adotable1.fieldbyname(‘stip’).value:=0;
end;
 
Напишемо код при звертанні до полів таблиці по їхній властивості name у редакторі полів Adotable.
У події Oncalcfields компонента Adotable напишемо код:
 
procedure tform1.adotable1calcfields(dataset: tdataset);
begin
if adosrbal.asfloat>= 4 then
stip.value=adosrbal.asfloat *50
else
stip.value:=0;
end;
 
Обмеження значення поля
Для полів можна перевіряти умови на значення. Це дозволить захистити програму від уведення неприпустимих даних. Подвійним клацанням на компоненті Adotable відкрийте редактор полів, виділіть потрібне поле й у його події Onvalidate напишіть код, перевіряючий його значення. Звертатися до значення поля можна одним з розглянутих вище способів.
Приклад. Нехай у таблиці є поле cena. Потрібно заборонити вводити ціну менш ніж 20. Запишемо код через звертання до значення поля по його імені в таблиці.
           
// якщо ціна менше 20
if adotable1.fieldbyname('cena').asfloat<20 then
begin
//виводимо повідомлення про помилку
application.messagebox (…);
//скасовуємо введення
abort;
end;
 
Приклад. Нехай поле cena у редакторі полів Adotable має властивість name=adocena. Потрібно заборонити вводити ціну менш ніж 20. Запишемо код через звертання до значення поля по його імені в редакторі полів.
 
// якщо ціна менше 20
if adocena.asfloat<20 then
begin
//виводимо повідомлення про помилку
application.messagebox (…);
//скасовуємо введення
abort;
end; (початок) 
3. Створення форм для роботи з даними БД
Сторінкова форма дозволяє переглядати дані з таблиці по одному запису. Така форма може містити компоненти, які максимально полегшують для користувача введення даних. Наприклад, крім текстових полів можна використовувати прапорці, списки, що випадають, графічні поля для перегляду графічних зображень.
Після підключення потрібної таблиці необхідно створити проміжну ланку, яка зв'яже поля таблиці й візуальні компоненти на формі. У якості такого елемента використовується компонент Datasource (DataAccess),  у властивості Dataset якого вказують ім'я компонента Adotable, пов'язаного з потрібною таблицею БД.
Після створення компонента Datasource можна приступати до проектування зовнішнього вигляду сторінкової форми. Усі візуальні компоненти для роботи із БД знаходяться на вкладці Datacontrols. Дана вкладка має безліч компонентів, які по зовнішньому вигляду й набору властивостей повністю дублюють звичайні візуальні компоненти. Але у цих компонентів є дві властивості, якими вони відрізняються від своїх звичайних аналогів:
Datasource – ім'я компонента Datasource, пов'язаного з потрібною таблицею Adotable;
Datafileld – ім'я поля таблиці, значення якого будуть відображатися в даному компоненті.
Робота із графічними полями
Якщо в таблиці передбачене зберігання зображень, то для відображення таких даних використовують компонент Dbimage, а для заповнення даного компонента використовують компонент Openpicturedialog.
Приклад:  Нехай у полі Dbimage відображається вміст поля foto. Даний компонент заповнюється подвійнім клацаннямю на ньому. У події Ondbclick компонента  Dbimage напишемо код:
 
if openpicturedialog1.execute=true then
begin
//переводимо запис у режим редагування
adotable1.edit;
//завантажуємо в поле foto обраний графічний файл
tblobfield(adotable1.fieldbyname('foto')).loadfromfile(openpicturedialog1.filename);
//зберігаємо запис
adotable1.post;
end;
 
Компонент Dbimage може працювати тільки в BMP файлами. Для захисту програми від невірного введення необхідно у компонента Openpicturedialog у властивості Filter вилучити всі типи файлів крім BMP.
 
Робота з полями дата/час
Заповнювати дату із клавіатури у звичайному текстовому полі небажано, тому що у випадку помилки введення дані не збережуться і програма завершить роботу. Для введення дат рекомендується використовувати компонент Datetimepicker (Win32), який являє собою список з календарем. Нанесіть на форму текстове поле Dbedit для відображення поля дата/час. Нанесіть на форму компонентів Datetimepicker,  зробіть його невидимим і вкажіть такий же розмір, що й у поля.  
При переході в текстове поле з датою треба відобразити Datetimepicker. Для цього для поля в події Onenter необхідно написати код:
 
//робимо поле з календарем видимим
Datetimepicker1.visible:=true;
//якщо текстове поле не пусте, то завантажуємо в поле з календарем дату, що зберігається в полі
if dbedit1.text<>’’ then
datetimepicker.date:=strtodate(dbedit.text);
 
При виході з поля потрібно знову відобразити текстове поле й показати  в ньому обрану дату. Для цього в події Onexit для Datetimepicker написати такий код:
 
//робимо поле з календарем невидимим
datetimepicker.visible:=false;
//відображаємо в полі обрану дату
dbedit.text:=datetostr(datetimepicker.date);
 
Після написання всіх оброблювачів розмістіть компонент Datetimepicker точно над текстовим полем з датою.
 
Створення полів – довідників
Якщо значення поля таблиці може бути заповнене значенням з деякого фіксованого набору (стать, місяці року, дні тижня, розряди й т.п.), то для таких полів доцільно використовувати компонент Dbcombobox, у властивості Items якого можна ввести перелік припустимих значень. Використання такого компонента з однієї сторони звільняє користувача від введення даних із клавіатури, а з іншого захищає програму від помилок уведення, друкарських помилок і т.п.
Однак часто текстові поля заповнюються значеннями з динамічних наборів даних. Такі набори можуть поповнюватися новими значеннями, або з них можуть видалятися існуючі значення. У цьому випадку такий перелік значень може зберігатися в окремій таблиці-довіднику.
У базі даних створіть таблицю-довідник для зберігання деякого переліку припустимих значень поля.
Для створення списків на підставі таблиці-довідника додайте на форму компонента Adotable і Datasource, пов'язані з таблицею-довідником, нанесіть на форму компонентів Dblookupcombobox (Datacontrols). У властивостях  Datasource і Datafield укажіть таблицю й поле, яке буде заповнюватися за допомогою такого списку. У властивостях Listsource і Keyfield укажіть таблицю й поле, значеннями яких заповнюється список.
 
Швидке створення сторінкової форми
Для швидкого переносу потрібних полів на сторінкову форму виконайте подвійне клацання на компоненті Adotable для відкриття редактора полів, утримуючи CTRL, виділіть потрібні поля таблиці, і перетягнітье їх на форму. При цьому кожне поле буде мати напис і ширину,  зазначені при проектуванні таблиці в СУБД. Якщо ці значення вас не влаштовують, то перед перетаскуванням поля на форму потрібно вказати потрібні значення для його відповідних властивостей.
 
Навігація по записах на сторінковій формі
Для виконання переходів по записах у таблиці й виконання операцій по редагуванню даних в Delphi є компонент Dbnavigator (Datacontrols), який являє собою панель із набором кнопок для виконання низки дій з даними. Для зв'язування цього компонента з потрібною таблицею в його властивості Datasource потрібно вказати ім'я компонента Datasource, пов'язаного з потрібною таблицею БД.
У компонента є властивості Visiblebuttons, за допомогою якого можна управляти набором відображуваних кнопок на ньому, а відповідно й набором функцій, доступних для користувача програми.
Якщо користувач не розуміє призначень якоїсь кнопки на панелі Dbnavigator, то можна відобразити спливаючи підказки. Для цього властивість Showhint встановіть рівним True, а у властивості Hints змініть наявні англомовні підказки на мову, зрозумілу для користувача. При цьому навіть якщо кнопки не відображається на формі, її підказку видаляти не можна.
 
Створення табличних форм
Перегляд великої таблиці за допомогою сторінкової форми досить не зручний і займає багато часу для навігації й пошуку потрібному запису. Використання табличних форм дозволяє усунути цю проблему. На таких формах користувач бачить відразу множину записів. Якщо дані ще й відсортовані по потрібному полю, то пошук потрібного запису значно полегшується й перехід на потрібний запис значно прискорюється.
Для створення табличних форм використовується компонент Dbgrid (Datacontrols), який за допомогою властивості Datasource зв'язується з компонентом Datasource, який вказує на потрібну таблицю БД. У сітці автоматично відображаються всі поля таблиці й з тими параметрами, які вони отримали при проектуванні в СУБД. Для зміни числа, порядку й інших параметрів полів потрібно відкрити редактор полів Adotable, додати потрібні поля й поміняти їхні властивості.(початок) 
4. Комбінування табличних і сторінкових форм
Табличні форми також мають недоліки, пов'язані з тим, що в сітці неможливо відобразити прапорці, графічні поля, списки для полегшення введення даних. Тому в реальних програмах часто комбінують табличні й сторінкові форми для створення зручного інтерфейсу користувача.
Для цього в сітці відображають тільки основний набір полів, а поруч із сіткою розміщають візуальні компоненти для перегляду й редагування інших полів. І сітка й візуальні компоненти у властивості Datasource посилаються на той самий компонент Datasource, пов'язаний з потрібною таблицею БД. Це дозволяє при швидкому і зручному переміщенні по записах у сітці переглядати й редагувати поля поточного запису за допомогою таких елементів як прапорці, списки, календарі, графічні поля й т.п.
Іншим варіантом може бути такий, при якому на одній формі в сітці відображається набір з основних полів, а перегляд і редагування всього запису виконується на іншій сторінковій формі, яка викликається при деякій події. У цьому випадку в коді сторінкової форми потрібно підключити модуль табличної форми й усі візуальні компоненти у властивості Datasource повинні посилатися на компонент Datasource табличної форми. Це дозволить відображати на обох формах дані з поточного запису однієї таблиці.
 
Створення стрічкових форм
Стрічкова форма дозволяє відображати дані у вигляді сітки, у якій можна буде використовувати всі візуальні компоненти, доступні для сторінкових форм.
Для створення стрічкових форм використовується компонент Dbctrlgrid (Datacontrols). За допомогою властивості Datasource стрічкова форма зв'язується з компонентом Datasource, що вказують на потрібну таблицю. Основними властивостями стрічкової форми є:
Dbcolcount – число стовпчиків;
Dbrowcount – число рядків.
Після додавання компонента Dbctrlgrid на його першій смузі (не заштрихована) можна розміщати будь-які візуальні компоненти для роботи з полями таблиці. При запуску програми ці компоненти автоматично повторяться для кожного запису таблиці на інших рядках стрічкової форми. (початок) 
5. Методи й властивості для роботи з даними в таблиці
Компонент Adotable має низку методів, що дозволяють виконати навігацію або зміну даних у таблиці.
 
Методи навігації
Методи навігації дозволяють виконувати переходи по записах. До таких методів відносять:
 
adotable1.first; // перехід на перший запис
adotable1.prior; // перехід на попередній запис
adotable1.next; // перехід на наступний запис
adotable1.last; // перехід на останній запис
adotable1.moveby (n); // перехід на запис із номером n
 
Також при навігації використовуються деякі властивості компонента Adotable:
 
adotable1.recno – номер поточного запису
adotable1.recordcount – загальне число записів
 
Існують властивості, що визначають досягнення кінця й початку таблиці:
 
adodotable1.bof – початок файлу
adotable1.eof – кінець файлу
 
Ці властивості рівні True, якщо досягнуті початок або кінець файлу.
 
Методи редагування
Методи редагування дозволяють змінювати дані в таблиці. До таких методів відносяться:
 
adotable1.insert; // додати запис
adotable1.delete; // вилучити запис
adotable1.edit; // перевести запис у режим редагування
adotable1.post; // зберегти запис
adotable1.cancel; // скасувати зміни
adotable1.refresh; // оновити запис
 
Перед викликом методів редагування, часто доводиться перевіряти, у якому стані перебуває поточний запис. Наприклад, якщо викликати метод Post (зберегти), а запис не новий або не переведений в режим редагування, то видається повідомлення про помилку.
Для перевірки стану запису використовується властивість:
 
adotable1.state
 
Ця властивість може прийматия:
 
dsbrowse – запис у режимі перегляду;
dsedit – запис у режимі редагування;
dsinsert – запис новий.
 
Приклад: Нехай у таблиці треба збільшити оклад співробітників на 300 у.е. Поле має ім'я oklad. Запишемо код через звертання до значення поля по його імені в таблиці.
 
var s:string;
begin
//зберігаємо в змінну мітку поточного запису
s:=adotable1.bookmarks;
//стаємо на перший запис
adotable1.first;
//поки не дійшли до кінця файлу
while not adotable1.eof do
begin
//переводимо запис у режим редагування
adotable1.edit;
//змінюємо оклад
adotable1.fieldbyname(‘oklad’).value:= adotable1.fieldbyname(‘oklad’).asfloat+300;
//зберігаємо запис
adotable1.post;
//переходимо на наступний запис
adotable1.next;
end;
//переходимо на запис зі збереженою міткою
adotable1.bookmarks:=s;
end;
 
Приклад: Нехай у таблиці треба збільшити оклад співробітників на 300 у.е. Нехай поле в редакторі полів Adotable має властивість name=adooklad. Запишемо код через звертання до значення поля через його ім'я в редакторі полів
 
var s:string;
begin
//зберігаємо в змінну мітку поточного запису
s:=adotable1.bookmarks;
//стаємо на перший запис
adotable1.first;
//поки не дійшли до кінця файлу
while not adotable1.eof do
begin
//переводимо запис у режим редагування
adotable1.edit;
//змінюємо оклад
adooklad.value:=adooklad.asfloat+300;
//зберігаємо запис
adotable1.post;
//переходимо на наступний запис
adotable1.next;
end;
//переходимо на запис зі збереженою міткою
adotable1.bookmarks:=s;
end;
 
Наведені приклади мають суттєвий недлік: при циклічноній обробці записів коритсувач буде бачити, як в сітці форми виконується перехід по всіх полях таблиці. Таке відображення з однієї сторони може вводити користувача в оману, а з другої – відображення переходу по записах на екрані потребує додаткового часу роботи програми, і обробка виконується довше.
Для вирішення проблеми необхідно до цикли вимикати візуальне відображення переходу по записах, а після циклу вмикати.
Для цоього компонент Adotable має методи:
 
adotable1.disablecontrols; //вимкнути відображення переходу по записах
adotable1.enablecontrols; //увімкнути відображення переходу по записах
 
Приклад. Нехай у таблиці потрібно порахувати суму окладів усіх співробітників. Поле має ім'я oklad. Запишемо код через звертання до значення поля по його імені в таблиці.
 
//описуємо змінну для підрахунку суми
var sum:real; s:string;
begin
//зберігаємо в змінну мітку поточного запису
s:=adotable1.bookmarks;
//обнуляємо суму
sum:=0;
//вимикаємо відображення переходу по записах
adotable1.disablecontrols;
//стаємо на перший запис
adotable1.first;
//поки не дійшли до кінця файлу
while not adotable1.eof do
begin
//сумуємо оклад
sum:= sum+adotable1.fieldbyname(‘oklad’).asfloat;
//переходимо на наступний запис
adotable1.next;
end;
//переходимо на запис зі збереженою міткою
adotable1.bookmarks:=s;
//вмикаємо відображення переходу по записах
adotable1.enablecontrols;
end;
 
Приклад. Нехай у таблиці потрібно порахувати суму окладів усіх співробітників. Нехай поле в редакторі полів Adotable має властивість name=adooklad. Запишемо код через звертання до значення поля через його ім'я в редакторі полів
 
//описуємо змінну для підрахунку суми
var sum:real; s:string;
begin
//зберігаємо в змінну мітку поточного запису
s:=adotable1.bookmarks;
//обнуляємо суму
sum:=0;
//вимикаємо відображення переходу по записах
adotable1.disablecontrols;
//стаємо на перший запис
adotable1.first;
//поки не дійшли до кінця файлу
while not adotable1.eof do
begin
//сумуємо оклад
sum:= sum+adooklad.asfloat;
//переходимо на наступний запис
adotable1.next;
end;
//переходимо на запис зі збереженою міткою
adotable1.bookmarks:=s;
//вмикаємо відображення переходу по записах
adotable1.enablecontrols;
end;
 
Нехай є деяка форма з даними. Необхідно в компоненті Label1 відображати поточний номер запису й загальне число записів. При переході між записами для компонента Adotable є подія Onafterscroll. У цій події потрібно написати код:
 
procedure Tform1.Adotable1Afterscroll(Dataset: Tdataset);
begin
if adotable1.Recordcount>0 then
label1.Caption:='Запис '+inttostr(adotable1.recno)+' з '+inttostr(adotable1.Recordcount)
else
label1.Caption:='Даних немає';
end;
 
Ций же код потрібно виконувати при створенні форми, додаванні й видаленні даних з таблиці. Для цього в події Oncreate форми, Afterpost і Afterdelete компонента Adotable1 додайте команду:
 
Adotable1Afterscroll(Adotable1); (початок) 
Питання для самоперевірки
1. Як виконати підключення таблиці до програми за технологією ADO? Опишіть принципи роботи з полями таблиці.
2. Як можна звернутися до значення поля, як створити поле, що обчислюється й написати для нього формулу? Приклад.
3. Як програмно задати обмеження на значення потрібного поля? Приведіть приклад.
4. За допомогою яких компонентів можна відобразити значення полів таблиці на формі, які властивості при цьому потрібно вказати?
5. Приведіть приклад коду, який поміщає в Blob-поле вміст обраного графічного файлу. Які обмеження має компонент Dbimage?
6. Який компонент використовується для роботи з полями типу дата/час? Приведіть приклад.
7. Як створити список-довідник. Опишіть дії для створення такого довідника.
7. За допомогою якого компонента можна додати на форму набір кнопок для виконання над даними основних операцій? Які властивості має цей компонент?
8. Приведіть основні методи таблиці для виконання навігації по записах. Приведіть приклад циклу для переходу по всіх записах таблиці.
9. Приведіть методи таблиці для виконання редагування даних таблиці.
 
Лекція № 12
Тема: «Робота із сіткою Dbgrid»
 
План
1. Основні властивості сітки2. Робота зі стовпчиками сітки3. Формування списку значень для стовпчиків4. Збереження параметрів сітки в реєстрі5. Умовне форматування сітки6. Відображення графіки в сітці 
1. Основні операції із сіткою Dbgrid
Компонент Dbgrid служить для відображення записів у вигляді таблиці. Даний компонент має низку властивостей і подій, які підвищують зручність роботи з даними.
Компонент має властивості:
Borderstyle – дозволяє відобразити або сховати границі сітки;
Color – задає колір фона сітки;
Columns – містить список стовпців сітки. Дозволяє настроювати властивості кожного стовпчика окремо;
Datasource – містить посилання на набір даних, який буде відображатися в сітці;
Fixedcolor – колір фіксованих областей на сітці;
Options – перелік властивостей сітки (див. нижче);
Readonly – захист сітки від редагування;
Titlefont – параметри шрифту заголовка сітки.
За допомогою властивості Options можна задати множину параметрів сітки. Кожний з параметрів приймає два значення true/false. До таких параметрів відносяться:
dgediting – дані в сітці можна редагувати;
dgalwaysshoweditor – при переході в комірку сітки відразу відображається курсор;
dgtitles – відображається рядок заголовка сітки;
dgindicator – ліворуч відображається стовпчик для зазначення поточного запису;
dgcolumnresize – дозволяє змінювати ширину й порядок колонок сітки;
dgcollines – відображає вертикальні лінії сітки;
dgrowlines – відображає горизонтальні лінії сітки;
dgtabs – дозволяє перехід по стовпчикам за допомогою клавіші Tab;
dgrowselect – при клацанні на будь-якій комірці рядка виділяється весь рядок. При включенні даного режиму автоматично вимикається властивість goediting (сітку не можна редагувати);
dgalwaysshowselection – активна комірка в сітці залишається виділеної, навіть якщо сітка втратить фокус;
dsconfirmdelete – при натисканні Ctrl+Delete користувач може вилучити обраний рядок. Даний параметр указує, що при видаленні потрібно видавати запит на підтвердження операції;
dscancelonexit – якщо користувач додав новий рядок у сітку й нічого в неї не вводив, то при переході на інший компонент (сітка втратила фокус), новий рядок знищується без збереження;
dsmultiselect – дозволяє виділення декількох рядків утримуючи клавішу Ctrl.
Властивість Options можна встановлювати при проектуванні форми, а також програмно. При програмній зміні до переліку стандартно включених параметрів додають потрібні за допомогою команди:
 
dbgrid1.options:=dbgrid1.options+[список параметрів];
 
Для вимикання включених властивостей їх потрібно відняти за допомогою команди:
 
dbgrid1.options:=dbgrid1.options-[список параметрів];
 
Наприклад, нехай сітка заблокована для редагування (виключена властивість dgediting і dgalwaysshoweditor). При подвійному клацанні на сітці поточний запис повинty перейти в режим редагування. Напишемо код у події сітки Ondblclick:
 
procedure tform1.dbgrid1dblclick(sender: tobject);
begin
//переводимо запис у режим редагування
adotable1.edit;
//активуємо параметри для редагування сітки
dbgrid1.options:=dbgrid1.options+[dgediting,dgalwaysshoweditor];
end;
 
При збереженні запису або скасуванні змін сітка повинна повернутися у вихідний стан. У події Afterpost і Aftercancel таблиці Adotable вставимо команду:
 
dbgrid1.options:=dbgrid1.options-[dgediting, dgalwaysshoweditor];
 
Властивості, доступні при написанні коду
Сітка має низку властивостей, які доступні тільки при написанні коду:
Fieldcount – кількість стовпчиків у сітці;
Selectedfield – дозволяє звернутися до поля БД в активному стовпчику;
Selectedindex – містить номер активного стовпчика (нумерація з 0); (початок)2. Робота зі стовпчиками сітки
Кожна сітка має стовпчики. При цьому стовпчики можуть відповідати полям таблиці БД або бути порожніми. Для роботи з переліком стовпчиків використовують спеціальний редактор, який викликається подвійним клацанням на компоненті Dbgrid.
У контекстному меню є команди для додавання стовпчика, видалення стовпчика, додавання всіх полів таблиці у вигляді стовпчиків.
При виділенні стовпчика в редакторі для нього можна задати низку властивостей:
Alignment – вирівнювання тексту;
Buttonstyle – тип кнопки в полі (bsauto – список, що випадає, bsellipsis – кнопка із трьома крапками, bsnone – немає кнопки);
Color – колір фона стовпчика;
Dropdownrows – число рядків відображуваних у списку поля, що випадає;
Fieldname – ім'я поля таблиці, пов'язане зі стовпчиком сітки;
Picklist – перелік значень для поля зі списком, що випадає;
Readonly – блокує стовпчик для введення;
Title – параметри заголовка стовпчика;
Visible – робить стовпчик видимим або невидимим;
Width – ширина стовпчика.
Звертання до стовпчика сітки
Для звертання до стовпчика сітки можна використовувати запис:
 
dbgrid1.columns[i]
 
де i – номер стовпчика (нумерація з 0).
Такий запис дозволяє звернутися до будь-якої властивості стовпчика в програмі:
 
dbgrid1.columns[i].fieldname //звертання до імені поля стовпчика
dbgrid1.columns[i].visible //звертання до параметра ширини стовпчика
 
Звертання до поточного стовпчика сітки
Якщо користувач клацнув на комірці сітки, то часто потрібно довідатися, на якому стовпчику виконане клацання. Це можна зробити за допомогою властивості dbgrid1.selectedindex. Дана властивість містить номер стовпчика, на якому клацнув користувач (нумерація з 0). Наприклад, умова виду:
 
if dbgrid1.selectedindex=1 then
. . .
 
перевіряє, чи клацнув користувач на другому стовпчикові.
Звернутися до активного стовпчика можна за допомогою запису:
 
dbgrid1.columns[dbgrid1.selectedindex]
 
Створення порожніх стовпчиків
Сітка може мати стовпчики, не пов'язані з полями таблиці. Такі стовпчики можуть відіграти інформаційну функцію. Наприклад, комірки такого стовпчика можуть офарблюватися в різний колір, залежно від деякої умови.
Також такі стовпчики можуть створюватися для перегляду Blob-полів. Якщо користувач клацне по комірці такого стовпчика, то відкриється вміст Blob-поля.
Наприклад, нехай у сітці є порожній стовпчик із заголовком Фото. Якщо користувач клацне по комірці цього стовпчика, то відкриється нова форма form2, на якій відображається фото обраного співробітника.
Для обробки клацання по комірці сітки у компонента Dbgrid є подія Oncellclick, у якому і напишемо код:
 
if dbgrid1.columns[dbgrid1.selectedindex].fieldname = '' then
form2.showmodal;
 
Даний приклад шукає стовпчик, для якjго не зазначена властивість Fieldname (порожнє). Якщо в сітці буде кілька порожніх полів, то при клацанні на кожному з них буде відкривати форма Form2. Якщо потрібно відкривати форму тільки при клацанні на стовпчику з іменем Фото, то потрібно перевіряти саме заголовок стовпця, а код зміниться так:
 
if dbgrid1.columns[dbgrid1.selectedindex].title.caption='фото' then
form2.showmodal; (початок) 
3. Формування списку значень для стовпчиків
Якщо значення поля таблиці може приймати одне зі значень деякого фіксованого набору (наприклад, стать, день тижня, місяць, розряд і т.п.), то для такого стовпчика можна створити список з переліком припустимих значень. Для цього подвійним клацанням на сітці Dbgrid відкрийте редактор стовпчиків, виділите стовпчик потрібного поля таблиці й у властивості Picklist введіть перелік значень. Також можна у властивості Dropdownrows указати кількість рядків списку, видимих для користувача. Якщо реально в списку більше рядків, чим зазначено у властивості, то з'явиться смуга прокручування списку.
У результаті в комірці такого стовпчика буде з'являтися кнопка для розкриття списку значень. Користувач має можливість увести значення із клавіатури або вибрати зі списку.
 
Динамічне формування списку
Дуже часто повний перелік припустимих значень стовпчика не відомий і може змінюватися в процесі роботи програми. У цьому випадку доводиться формувати такий перелік динамічно по ходу роботи. Найчастіше такий перелік формується на підставі даних полів таблиць. Для демонстрації такого формування розглянемо приклад. Нехай у таблиці personal є поле dolgnost з переліком посад співробітників. Для стовпчика цього поля необхідно створити список з переліком усіх посад, уведених раніше в цьому полі. Для рішення задачі необхідно:
нанести на форму компонентів Adoquery (ADO) для одержання переліку значень за допомогою запиту. Для компонента задати властивості: Connection=Adoconnection, SQL=запит на вибір даних з поля. Текст запиту має вигляд:
select distinct dolgnost from personal order by dolgnost
 
при клацанні в комірці стовпчика поля dolgnost потрібно програмно формувати список припустимих значень. Для цього в події Oncellclick компонента Dbgrid1 введіть код:
 
//якщо клацнули на стовпчику поля dolgnost
if dbgrid1.columns[dbgrid1.selectedindex].Fieldname='dolgnost' then
begin
//активуємо запит, відбираючи перелік значень для списку
adoquery1.Active:=true;
//у стовпчику поля очищаємо список від старих значень
dbgrid1.Columns[dbgrid1.selectedindex].Picklist.Clear;
//переходимо на перше значення відібраного переліку
adoquery1.first;
//у циклі проходимо по всіх елементах відібраного переліку
while adoquery1.Eof<>true do
begin
//записуємо в список стовпчика чергове значення з відібраного переліку
dbgrid1.Columns[column.Index].Picklist.Add(adoquery1.fieldbyname('fam').asstring);
//переходимо до наступного значення у відібраному переліку
adoquery1.Next;
end;
//закриваємо запит
adoquery1.Active:=false;
end; (початок)4. Збереження параметрів сітки в реєстрі
Одним з істотних зручностей для користувача при роботі із сіткою є реалізація можливості настроювання порядку, зовнішнього вигляду й відображення колонок сітки. Для збереження параметрів найбільш зручно використовувати реєстр Windows. При збереженні параметрів сітки до реєстру необхідно враховувати наступне правило: потрібно зберігати всі параметри, які ви міняли для стовпчиків сітки + ім'я поля + видимість + ширина.
Розглянемо приклад: нехай для стовпчиків сітки були задані колір фона й заголовок. При виході із програми необхідно зберегти параметри сітки в реєстрі в гілці hklm_local_machine\software\myprogram\dbgrid.
 
У події Onclose форми напишемо код:
 
//описуємо змінні
var reg:tregistry; i:integer;
begin
//створюємо об'єкт для роботи з реєстром
reg:=tregistry.create;
//задаємо початковий розділ реєстру
reg.rootkey:=hkey_local_machine;
 //у циклі проходимо по всіх стовпчиках сітки
for i:=0 to dbgrid1.fieldcount-1 do
begin
//створюємо в реєстрі чергову гілку col[i]
reg.openkey('\software\myprogram\dbgrid\col'+inttostr(i),true);
//записуємо до реєстру ім'я поля стовпчика
reg.writestring('field',dbgrid1.columns.items[i].fieldname);
//записуємо до реєстру текст заголовка стовпчика
reg.writestring('caption',dbgrid1.columns[i].title.caption);
//записуємо до реєстру колір фона стовпчика
reg.writeinteger('color',dbgrid1.columns[i].color);
//записуємо до реєстру ознаку видимості стовпчика
reg.writebool('visible',dbgrid1.columns[i].visible);
//записуємо до реєстру ширину стовпчика
reg.writeinteger('width',dbgrid1.columns[i].width);
end;
//видаляємо з пам'яті об'єкт для роботи з реєстром
reg.free;
end;
 
 Для роботи коду не забудьте підключити модуль registry.
Запустіть програму й закрийте її. У результаті в реєстрі буде створені потрібні записи. Після цього можна писати код для читання даних про параметри сітки з реєстру. У події форми Oncreate напишіть код:
 
//описуємо змінні
var reg:tregistry; i:integer;
begin
//створюємо об'єкт для роботи з реєстром
reg:=tregistry.create;
//задаємо початковий розділ реєстру
reg.rootkey:=hkey_local_machine;
//перевіряємо, чи існує в реєстрі запис про сітку
if reg.keyexists('software\myprogram\dbgrid')=true then
begin
//у циклі проходимо по всіх стовпчиках сітки
for i:=0 to dbgrid1.fieldcount-1 do
begin
//відкриваємо в реєстрі чергову гілку col[i]
reg.openkey('\software\myprogram\dbgrid\col'+inttostr(i),true);
//читаємо з реєстру ім'я поля для стовпчика
dbgrid1.columns[i].fieldname:=reg.readstring('field');
//читаємо з реєстру текст заголовка стовпчика
dbgrid1.columns[i].title.caption:=reg.readstring('caption');
//читаємо з реєстру колір фона стовпчика
dbgrid1.columns[i].color:=reg.readinteger('color');
//читаємо з реєстру параметр видимості стовпчика
dbgrid1.columns[i].visible:=reg.readbool('visible');
//читаємо з реєстру ширину стовпчика
dbgrid1.columns[i].width:=reg.readinteger('width');
end;
end;
//видаляємо з пам'яті об'єкт для роботи з реєстром
reg.free;
end;
 
Настроювання видимості стовпців
Нехай у сітці відображається шість стовпчиків. Праворуч від сітки є список із шести полів. Користувач може відзначити ті стовпчики, які він хотів би бачити в сітці. Вибір користувача зберігається в реєстрі.
Нехай таблиця має шість полів: tab, fam, imya, otch, datar, foto. Нанесемо на форму компонентів Checklistbox (Additional). У властивості Items уведемо назви для полів: Табельний номер, Прізвище, Ім'я, По батькові, Дата народження, Фото.
 

 
При клацанні на потрібному полі колонка в сітці відображається або ховається. Для цього в події Onclickcheck списку введіть код:
 
var n:integer;
begin
case checklistbox1.itemindex of
//якщо обраний перший елемент списку (поле tab)
0:
begin
//знаходимо в циклі номер стовпчика для поля tab
n:=0;
while dbgrid1.columns[n].fieldname<>'tab' do
n:=n+1;
//застосовуємо до стовпчика стан прапорця списку
dbgrid1.columns[n].visible:=checklistbox1.checked[0];
end;
//аналогічно для другого рядка (поле fam)
1:
begin
n:=0;
while dbgrid1.columns[n].fieldname<>'fam' do
n:=n+1;
dbgrid1.columns[n].visible:=checklistbox1.checked[1];
end;
//аналогічно для третього рядка (поле imya)
2:
begin
n:=0;
while dbgrid1.columns[n].fieldname<>'imya' do
n:=n+1;
dbgrid1.columns[n].visible:=checklistbox1.checked[2];
end;
//аналогічно для четвертого рядка (поле otch)
3:
begin
n:=0;
while dbgrid1.columns[n].fieldname<>'otch' do
n:=n+1;
dbgrid1.columns[n].visible:=checklistbox1.checked[3];
end;
//аналогічно для п'ятого рядка (поле datar)
4:
begin
n:=0;
while dbgrid1.columns[n].fieldname<>'datar' do
n:=n+1;
dbgrid1.columns[n].visible:=checklistbox1.checked[4];
end;
 //аналогічно для шостого рядка (поле foto)
5:
begin
n:=0;
while dbgrid1.columns[n].fieldname<>'foto' do
n:=n+1;
dbgrid1.columns[n].visible:=checklistbox1.checked[5];
end;
end;
end;
 
При створенні форми потрібно, щоб у списку відобразилися ті поля, стовпчики яких відображаються в сітці. Для цього в події Oncreate форми потрібно внести зміни:
 
//описуємо змінні
var reg:tregistry; i:integer;
begin
//створюємо об'єкт для роботи з реєстром
reg:=tregistry.create;
//задаємо початковий розділ реєстру
reg.rootkey:=hkey_local_machine;
//перевіряємо, чи існує в реєстрі запис про сітку
if reg.keyexists('software\myprogram\dbgrid')=true then
begin
//у циклі проходимо по всіх стовпчиках сітки
for i:=0 to dbgrid1.fieldcount-1 do
begin
//відкриваємо в реєстрі чергову гілку col[i]
reg.openkey('\software\myprogram\dbgrid\col'+inttostr(i),true);
//читаємо з реєстру ім'я поля для стовпчика
dbgrid1.columns[i].fieldname:=reg.readstring('field');
//читаємо з реєстру текст заголовка стовпчика
dbgrid1.columns[i].title.caption:=reg.readstring('caption');
//читаємо з реєстру колір фона стовпчика
dbgrid1.columns[i].color:=reg.readinteger('color');
//читаємо з реєстру параметр видимості стовпчика
dbgrid1.columns[i].visible:=reg.readbool('visible');
//читаємо з реєстру  ширину стовпчика
dbgrid1.columns[i].width:=reg.readinteger('width');
//у списку рядку привласнюємо значення властивості visible
Checklistbox1.checked[adotable1.fieldbyname(reg.readstring('field')).index]:=reg.readbool('visible');
end;
end;
//видаляємо з пам'яті об'єкт для роботи з реєстром
reg.free;
end; (початок) 
5. Умовне форматування сітки
Іноді потрібно, щоб рядки або комірки в сітці виділялися різним кольором. Для цього в події сітки Ondrawcolumncell можна перевірити потрібні умові й відформатувати сітку.
Заливання елементів сітки виконується стандартним набором операцій:
заливання фона поля
dbgrid1.canvas.brush.color:=clred; //колір фону
dbgrid1.canvas.fillrect (rect); //залити
вивід тексту
dbgrid1.canvas.font.color:=clblack; //колір тексту
dbgrid1.canvas.textout(rect.left,rect.top,column.field.text); //вивести
 
Якщо перевіряється тільки значення поля, то заливається весь рядок.
Приклад. Рядки, у яких розмір окладу більше 1000 грн. залити червоним кольором, інші - синім. Текст видати чорним кольором. Якщо поле з окладлм має ім'я oklad, то в події сітки Ondrawcolumncell напишемо код:
 
if adotable1.fieldbyname('oklad').asfloat>1000 then
//задаємо колір фона рядка
dbgrid1.canvas.brush.color:=clred
else
//задаємо колір фона рядка
dbgrid1.canvas.brush.color:=clblue;
//заливаємо рядок
dbgrid1.canvas.fillrect (rect);
//задаємо колір тексту в рядку
dbgrid1.canvas.font.color:=clblack;
//друкуємо текст у рядку
dbgrid1.canvas.textout(rect.left+2,rect.top,column.field.text);
 
Якщо крім значення поля перевіряється ще й ім'я поля, то заливається не весь рядок сітки, а та комірка, яка відповідає імені поля, що перевіряється. Для перевірки імені поля в події Ondrawcolumncell використовують запис:
 
column.fieldname
 
Приклад. Нехай у сітці є порожній стовпчик. У рядках, у яких розмір окладу більше 1000 грн, залити комірку порожнього стовпчика червоним кольором, а інші комірки цього ж стовпчика синім. Якщо поле має ім’я oklad, то в події сітки Ondrawcolumncell напишемо код:
 
if column.fieldname=’’ then
begin   
if adotable1.fieldbyname('oklad').asfloat>1000 then
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clred
else
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clblue;
//заливаємо комірку
dbgrid1.canvas.fillrect(rect);
end;
 
Приклад. У розглянутому прикладі зафарбовується тільки фон, тому що колонка порожня й тексту не має. Якщо ж зафарбовується комірка з текстом, то потрібно ще видавати й текст. Нехай для попереднього прикладу потрібно зафарбовувати не порожній стовпчик, а стовпчик поля fam.
 
if column.fieldname=’fam’ then
begin   
if adotable1.fieldbyname('oklad').asfloat>1000 then
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clred
else
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clblue;
//заливаємо комірку
dbgrid1.canvas.fillrect (rect);
//задаємо колір тексту в комірці
dbgrid1.canvas.font.color:=clblack;
//друкуємо текст у комірці
dbgrid1.canvas.textout(rect.left+2,rect.top,column.field.text);
end;
 
Даний приклад видає текст у зафарбованій комірці завжди по лівому краю. У реальних програмах текстові дані звичайно видають по лівому краю, а числа й дати по правому. Тому при видачі тексту потрібно перевіряти тип видаваних даних і відповідно вирівнювати їх.
Перепишемо приклад з урахуванням вищесказаного.
Приклад:  Рядки, у яких розмір окладу більше 1000 грн. залити червоним кольором, інші - синім. Текст видати чорним кольором.
 
if adotable1.fieldbyname('oklad').asfloat>1000 then
//задаємо колір фона рядка
dbgrid1.canvas.brush.color:=clred
else
//задаємо колір фона рядка
dbgrid1.canvas.brush.color:=clblue;
//заливаємо рядок
dbgrid1.canvas.fillrect (rect);
//задаємо текст кольору тексту у рядку
dbgrid1.canvas.font.color:=clblack;
//якщо видаваний текст строкового типу
if (column.field.datatype=ftwidestring) or
(column.field.datatype=ftstring) then
//видаємо текст по лівому краю
dbgrid1.canvas.textout(rect.left+2,rect.top,column.field.text)
//інакше видаємо текст по правому краю
else
dbgrid1.canvas.textout(rect.right-dbgrid1.canvas.textwidth(column.field.text)-2,rect.top,column.field.text);
 
Приклад. У рядках, у яких розмір окладу більше 1000 грн, залити комірку поля fam червоним кольором і видати текст чорним кольором.
 
if column.fieldname=’fam’ then
begin   
if adotable1.fieldbyname('oklad').asfloat>1000 then
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clred
else
//задаємо колір фона комірки
dbgrid1.canvas.brush.color:=clblue;
//заливаємо комірку
dbgrid1.canvas.fillrect(rect);
//задаємо колір тексту в комірці
dbgrid1.canvas.font.color:=clblack;
//якщо видаваний текст строкового типу
if (column.field.datatype=ftwidestring) or
(column.field.datatype=ftstring) then
//видаємо текст по лівому краю
dbgrid1.canvas.textout (rect.left+2,rect.top,column.field.text)
//інакше видаємо текст по правому краю
else
dbgrid1.canvas.textout(rect.right-dbgrid1.canvas.textwidth(column.field.text)-2,rect.top,column.field.text);
end;
 
Зауваження: при виводі тексту треба брати до уваги, що в деяких комірках сітки не маже бути тексту (наприклад - це поля з BLOB даними). В цьому випадку команда виводу тексту буде видавати в таких комірках помилку. Тому треба завжди перевіряти імена полів перед виведенням.
 
Наприклад. У попередньому прикладі ми вивели тест з різним вірівнюванням у всіх комірках. Нехай у сітці є комірка для поля photo. Треба вивести текст у всіх комірках окрім цього поля. Код буде мати вигляд:
 
//якщо комірка належить полю photo
//то код нижче не виконується
if column.fieldname='photo' then exit;
//задаємо колір тексту в комірці
dbgrid1.canvas.font.color:=clblack;
//якщо видаваний текст строкового типу
if (column.field.datatype=ftwidestring) or
(column.field.datatype=ftstring) then
//видаємо текст по лівому краю
dbgrid1.canvas.textout (rect.left+2,rect.top,column.field.text)
//інакше видаємо текст по правому краю
else
dbgrid1.canvas.textout(rect.right-dbgrid1.canvas.textwidth(column.field.text)-2,rect.top,column.field.text);
end; (початок) 
6. Відображення графіки в сітці
У деяких програмах у комірках сітки потрібно відображати графічні елементи (іконки). Наприклад, при вставці фотографії в полі Фото у відповідній комірці з'являється невелика іконка, що вказує на те, що поле графічне й воно заповнене. Для реалізації відображення графічної інформації в комірці необхідно помістити на форму компонент Imagelist і додати в нього всі іконки, необхідні для відображення. Потім у події сітки Ondrawcolumncell ввести код:
 
//описуємо змінну
var im1: tbitmap;
begin
//створюємо об'єкт для зчитування картинок з Imagelist
im1:=tbitmap.create;
//будемо відображати графіку в стовпчику з ім’ям pict
if (column.fieldname='pict' ) then
begin
//заливаємо комірку білим кольором
dbgrid1.canvas.brush.color:=clwhite;
dbgrid1.canvas.fillrect(rect);
//зчитуємо іконку для відображення
//якщо поле tab<5, зчитуємо першу картинку з Imagelist
if (adotable1.fieldbyname('tab').asfloat<5) then
imagelist1.getbitmap(0,im1)
//інакше зчитуємо другу картинку
else
imagelist1.getbitmap(2,im1);
//по центру комірки відображаємо зчитану картинку
dbgrid1.canvas.draw((rect.left+rect.right-im1.width)div 2,rect.top,im1);
end;
end; (початок) 
Питання для самоперевірки
1. Опишіть основні властивості сітки Dbgrid.
2. Опишіть основні властивості окремого стовпчика в сітці Dbgrid.
3. Як можна в програмі звернутися до потрібного стовпчика в сітці Dbgrid? Як можна звернутися до поточного стовпчика?
4. Як у сітці Dbgrid створити порожній стовпчик? Як для стовпчика сітки створити список, що випадає?
5. У якій події сітки Dbgrid виконують розфарбовування рядків або комірок? Приведіть приклад розфарбовування всіх комірок рядка сітки.
6. Приведіть приклад розфарбовування окремої комірки в сітці Dbgrid. Як у комірці сітки відобразити іконку з Imagelist?
Лекція № 13
Тема: «Використання користувацьких компонентів для роботи із БД»
 
План
1. Використання файлів типу JPG і GIF2. Робота з бібліотекою Infopower3. Робота із сіткою wwdbgrid4. Робота з компонентами Infopower5. Створення складених елементів у сітці6. Робота зі зв'язаними таблицями 
1. Використання файлів типу JPEG і GIF
Як було сказано раніше в таблицях баз даних можна зберігати графічні зображення. При цьому, якщо саме поле таблиці може зберігати дані в будь-якому форматі, то компонент Dbimage може працювати тільки з форматом BMP. Отже розроблювач змушений обмежувати можливості по роботі із графічним полем таблиці тільки форматом BMP. Такий підхід веде до швидкого збільшення розміру БД, тому що графічні файли у форматі BMP відрізняються більшим розміром. Альтернативні формати JPEG або GIF у десятки разів менші по розміру, однак не підтримуються компонентом Dbimage.
 
Установка сторонніх компонентів
Першим кроком до вирішення описаної проблеми є використання компонента pdbimage. Даний компонент розроблений на основі стандартного Dbimage, має такі ж властивості, методи й події. Основною його відмінною рисою є підтримка форматів JPEG і GIF. Для роботи із цим компонентом використовують такий же підхід, як і при роботі з Dbimage (див. лекцію 11). Відмінність тільки в тому, що замість Dbimage на форму наносять компонент pdbimage. Однак компонент вимагає попередньої установки окремого модуля для роботи з форматом GIF. Такий модуль має ім'я Gifimage.
Для роботи із цим компонентом його необхідно правильно встановити:
у папці з Delphi (c:\program files\borlan\delphi7) створіть папку для зберігання зовнішніх компонентів (наприклад папка з іменем components);
скопіюйте в цю папку всі файли, що відносяться до компонента, що додається (усього їх 3);
запустіть Delphi. Виконайте команду Tools - Environment Options. На закладці Library розкрийте поле Library Path, у наступному вікні вкажіть ім’я створеної папки Components і клацніть на кнопці Add;
для установки модуля Gifimage виконайте команду Component - Install Component. У полі Unit file name виберіть файл із ім'ям Gifimage.pas, розташований у створеній вами папці (Components) і клацніть на кнопці ОК;
для установки компонента pdbimage повторите дії, зазначені в попередньому пункті, але виберіть файл Udbimages.pas
 У результаті на закладці Data Controls з'явиться новий значок встановленого компонента.
Після нанесення даного компонента на форму в діалогах Openpicturedialog і Savepicturedialog автоматично з'являються формати *.gif і *.jpeg.
Зауваження. Графічні файли в полях таблиць БД зберігаються у двійковому виді, тому при роботі з файлами JPEG у БД Mysql виникає спотворення зображення. Це відбувається тому, що кодування даних в Delphi - cp1251, а кодування даний в Mysql - UTF8, отже двійкове представлення символів різне й файл спотворюється. Вирішенням даної проблеми є переведення сервера Mysql на кодування cp1251 або написання програм з використанням версії Delphi не нижче Delphi 2005. Дана версія підтримує кодування Unicode (UTF8, UTF16).  (початок) 
2. Робота з бібліотекою Infopower
Сторонні розроблювачі пропонують для використання додаткові бібліотеки компонентів, які значно розширюють можливості стандартних компонентів. Такі бібліотеки як правило мають більш розширений набір властивостей. Багато функцій, які в стандартних компонентах доводилося програмувати, у таких компонентах задаються властивостями або викликом певного методу.
Для роботи із БД бібліотека Infopower є однієї з найбільш потужних. Установка бібліотеки проводиться за допомогою стандартного інсталятора Windows.
Після установки в середовищі Delphi з'являється три закладки: IP Control, IP Dialog, IP Access, на яких розташовані компоненти бібліотеки. При цьому деякі компоненти панелі можуть використовуватися не тільки при роботі із БД, а в інших додатках. При цьому такі компоненти мають додаткові візуальні ефекти, що дозволяють зробити інтерфейс вашого додатка більш привабливим. Розглянемо деякі з них.
 
Компонент wwdbedit (Ipcontrols)
Являє собою звичайне текстове поле, що має властивості:
Editalignment - вирівнювання тексту в полі в режимі редагування;
Frame - ефекти видозміни поля при одержанні й втраті фокуса, при наведенні мишею;
Picture - маска введення. Дозволяє задати маску для тексту, що вводиться. Символи, які не підходять для маски, ігноруються.
Компонент wwdbspinedit (Ipcontrols)
Являє собою лічильник для редагування числових полів, що має властивості:
Editalignment - вирівнювання тексту в полі в режимі редагування;
Frame - ефекти видозміни поля при одержанні й втраті фокуса, при наведенні мишею;
Increment - крок зміни значення лічильника. На відміну від стандартних компонентів дозволяється використовувати дробове значення кроку;
Minvalue, Maxvalue - максимальне й мінімальне значення лічильника. якщо вказати 0, то необмежено;
Value - значення лічильника.
Компонент wwcheckbox (Ipcontrols)
Являє собою аналог звичайного прапорця Checkbox і має властивості:
Images - задає список Imagelist, у якому потрібно зберігати два зображення. Ці зображення будуть відігравати роль прапорця (включене або виключене);
Centervertical - задає вертикальне вирівнювання напису прапорця щодо графічного зображення;
Dynamiccaption - включає динамічну зміну напису прапорця при включенні або вимиканні. Самі написи задаються у властивостях Displayvaluechecked (напис при вмиканні) і Displayvalueunchecked (напис при вимиканні).
Frame - те ж, що й для текстового поля.
Компонент wwradiogroup (Ipcontrols)
Компонент являє собою групу перемикачів. Крім стандартних властивостей має такі:
Buttonframe - аналогічно властивості Frame для інших компонентів;
Glyphimages - вказує компонент Imagelist із зображеннями, які з'являться біля кожного перемикача;
Images - вказує компонент Imagelist із двома зображеннями, якими буде замінятися сам перемикач при вмиканні або вимиканні;
Items - назви перемикачів;
Itemindex - номер активного перемикача (нумерація з 0);
Show... - перелік властивостей, керуючих відображенням різних елементів групи перемикачів: рамки, заголовка рамки, заголовків перемикачів і т.п.;
Values - список значень, які відповідають кожному перемикачу групи. Користувач вибирає перемикач, а в БД заноситься значення, яке задано для цього перемикача в Values. Порядок перемикачів у властивості Itms і порядок зазначений у властивості Values повинні збігатися.
 Розглянуті компоненти можуть бути пов'язані з полями таблиць БД за допомогою властивостей Datasource і Datafield.
Основне призначенням бібліотеки Infopower - це забезпечення більш зручної й простої роботи із БД, створення більш наочного й ефективного інтерфейсу при роботі з даними. Усі компоненти мають властивості Datasource і Datafield, за допомогою яких можна зв'язати компонент із полем БД. Крім цього кожний компонентів має свої особливі властивості. Також одні компоненти можна вмонтувати в інші. (початок) 
3. Робота із сіткою wwdbgrid
Даний компонент створений на підставі звичайної сітки Dbgrid. Тому компонент має ті ж властивості, що й звичайна сітка, а також низку додаткових властивостей:
Fixedcols - кількість фіксованих стовпчиків у сітці;
Footerheight - висота рядка підвалу сітки. Колір такого рядка й комірки задається властивостями Footercellcolor і Footercolor;
Groupfieldname - ім'я поля для групування даних у сітці;
Hidealllines - приховує або відображає всі лінії сітки;
Indicatorbutton - включає відображення кнопки в лівому верхньому куті сітки. Для даної кнопки можна призначити потрібну подію;
Keyoptions - включає або виключає можливість використання гарячих клавіш у сітці: Enter працює як Tab, Ctrl+Del видаляє запис у сітці, Insert додає новий запис у сітку;
Linecolors, Linestyle - задає колір і вид ліній сітки;
Memoattributes - задає параметри відображення Memo полів у сітці: msizeble - можливість зміни розміру вікна редактора, mwordwrap - можливість переносу тексту на новий рядок, mgridshow - можливість відображення вмісту поля Memo у сітці (уповільнюється робота програми), mviewonly - можливість редагування даних у сітці, mdisabledialog - можливість виклику контекстного меню для роботи з текстом;
Options - має набір властивостей, стандартних для звичайної сітки Dbgrid. Однак тут же перебувають і інші властивості: dgwordwrap - перенесення тексту; dgperfectrowfit - підгонка висоти рядків у сітці; dgshowfooter - відображає рядок підвалу в сітці; dgnolimitcolsize - не обмежує зміну розміру стовпчика в сітці; dgtrailingellipsis - відображає три крапки в комірці, якщо текст не поміщається по ширині; dgshowcellhint - відображає спливаючі підказки з повним умістом комірки, якщо текст не поміщається по ширині; dgtabexitsonlastcol  - при натисканні в останній комірці на клавішу Tab фокус переходить на наступний компонент на формі (новий запис не додається);  dgfixedresizable - включає зміну розміру фіксованих стовпчиків; dgfixededitable - включає можливість редагування фіксованих стовпчиків; dgproportionalcolresize  - пропорційна зміна ширини колонок у сітці; dgrowresize - можливість зміни висоти рядків у сітці; dgrowlinesdisablefixed, dgcollinesdisablefixed - відображає лінії сітки у фіксованих колонках; dgdblclickcolsizing – включає підгонку розміру ширини стовпчика по подвійному клацанню заголовка сітки;
Paintoptions - задає графічне оформлення рядків і комірок сітки: Activerecordcolor - колір комірок активного рядка; Alternatingrowcolor - колір парних рядків сітки; Alternatingrowregions - задає яка частина парного рядка буде пофарбована (фіксовані комірки, усі комірки даних, активна комірка в рядку); Backgroundbitmap  - малюнок для використання як фона сітки; Backgrounddrawstyle - параметри відображення малюнка (розтягування, центрування й т.п.); Backgroundoptions - задає які комірки сітки потрібно зафарбувати зазначеним малюнком;
Rowheightpercent - висота рядка в сітці у відсотках;
Selected - список стовпчиків сітки і їх параметри;
Titlealignment, Titlecolor, Titlefont - список властивостей для заголовка сітки;
Titlebuttons - включає можливість клацання по заголовках сітки;
Titlelines - задає кількість рядків, займаних рядком заголовка. Використовується для створення складних шапок таблиць.
 Робота з полями сітки
За замовчуванням, якщо сітку зв'язати з таблицею за допомогою властивості Datasource, те в сітці відобразяться всі поля таблиці. Однак сітка wwdbgrid має потужні засоби для значного розширення можливостей колонок. Для роботи з колонками клацніть два рази на сітці. Відкриється вікно, що відрізняється від редактора стовпчиків звичайної сітки.
За допомогою кнопки Add Fields  можна додати в сітку потрібні стовпчики. Кожний стовпчик, обрана в лівій частині вікна має ряд властивостей, розбитих на кілька вкладок:
закладка Display дозволяє задати ширину (Width), заголовок (Title - допускається використовувати символ "~" для переносу тексту на новий рядок), блокувати для редагування (Read Only), заголовок для об'єднаної комірки (Group Name);
закладка Editcontrol - дозволяє вказати компонент, який буде відображатися у стовпчику: Field - простий уміст поля (обране за замовчуванням), Bitmap - графічне зображення; Imageindex - іконка з компонента Imagelist, Url-link - поле-гіперпосилання, Customedit - вказується ім'я компонента, який буде відображатися у стовпчику, . Потрібний компонент повинен попередньо бути нанесений на форму. У якості компонентів, що вбудовуються, можна використовувати тільки компоненти бібліотеки Infopower, а для графічних полів можна використовувати Dbimage або pdbimage. За замовчуванням такий компонент відображається в сітці тільки при переході в комірку даного стовпчика. Для автоматичного відображення компонента включіть прапорець Control Always Paints;
закладка Masks - дозволяє задати для стовпчика маску введення, захищаючи поле від невірного введення даних. Правила створення масок, приклади масок можна прочитати в довідці.
 Даний редактор не дозволяє створювати порожні стовпчики. Для таких стовпчиків потрібно в самій таблиці створити попередньо в самій таблиці поля, що обчислюються (див. лекцію 11).
При вбудовуванні в сітку зовнішніх компонентів і при включенні прапорця Control Always Paints програма автоматично завантажує в сітку вміст полів, у тому числі й великих (графіка, Memo і т.п.). У цьому випадку швидкість роботи програми може сильно знизитися. Тому включати прапорець Control Always Paints не завжди доцільно (на розсуд розроблювача).
 
Створення складеної шапки в сітці
У сітці можна створювати заголовки, що складаються із декількох об'єднаних комірок. Для створення такого заголовка спочатку у властивості сітки Titlelines укажіть скільки рядків буде займати заголовок.  Подвійним клацанням відкрийте вікно редактора колонок. У списку перетаскуванням розмістите поруч стовпчики, які будуть поєднуватися в групу. На закладці Display зніміть прапорець Store display settings in Tfields і для потрібних стовпчиків у полі Groupname уведіть назву для загальної комірки цих стовпчиків.
Після завдання всіх параметрів не забудьте обов'язково включити прапорець Store display settings in Tfields.
 
Методи сітки
Незважаючи на те, що компонент wwdbgrid аналогічний звичайній сітці, проте набір подій у цього компонента більше. З однієї сторони це дозволяє обробити більшу кількість дій із сіткою, але з іншої компонент не має деяких подій, звичних для сітки Dbgrid.
Для сортування даних використовують такий же підхід, що й для звичайної сітки, але замість події Ontitleclick використовують метод Ontilebuttonclick. Відмінність у тому, що за замовчуванням сітка wwdbgrid не реагує на клацання по заголовках сітки. Для цього потрібно встановити властивість сітки Titlebutton=True.
При клацанні на комірках сітки замість події Oncellclick виникає подія Oncellenter.
Для розфарбовування комірок у сітці замість події Ondrawcolumncell використовують подію Ondrawdatacell, Ondrawtitlecell і  Ondrawfootercell залежно від того, які комірки ви прагнете зафарбовувати (комірки даних, комірки заголовка або комірки підвалу). Для фарбування окремої комірки ім'я поля перевіряється не за допомогою параметра column.fieldname, а за допомогою параметра field.fieldname.
 
Збереження параметрів сітки
Сітка може автоматично зберігати до реєстру свої параметри й відновлювати їх при відкритті програми. Для цього необхідно спочатку настроїти властивість сітки Iniattributes:
Checknewfields - чи потрібне зберігати нові стовпчики сітки;
Delimiter - задає роздільник при збереженні параметрів;
Enabled - включає можливість збереження настроювань;
Filename - задає ім'я гілки реєстру або ім'я файлу, для збереження настроювань;
Savetoregistry - якщо встановлений в true, то настроювання зберігаються до реєстру, інакше у файл
 Для збереження настроювань (звичайно при виході із програми) потрібно викликати метод:
 
wwdbgrid1.Savetoinifile;
 
Для читання настроювань (звичайно при створенні форми) потрібно викликати метод:
 
wwdbgrid1.Loadfrominifile;
 
Робота з підвалом сітки
Підвал (Footer) - це рядок, відображуваний внизу таблиці. Цей рядок потрібен для відображення довідкових даних: суми, середнього й т.п. також можна відображати будь-який довільний тест. Кожний стовпчик сітки має властивість, що дозволяє відобразити під даним стовпчиком який-небудь текст. Для звертання до підвалу сітки використовують запис:
 
wwdbgrid1.columnbyname('ім'я поля').footervalue
 
Дана властивість є текстовою, тому числові значення повинні конвертуватися в рядок.
За замовчуванням рядок Footer у сітці не відображається. Для його відображення необхідно встановити властивість сітки Options - dgshowfooter = true. Також потрібно встановити властивості: Footerheight - висота рядка в пікселях, Footercolor - колір фона рядка підвалу.
Після створення рядка підвалу сам код відображення даних пишуть у події сітки Onupdatefooter.
 Розглянемо відображення сумарного окладу співробітників у підвалі під коміркою поля oklad.
Для цього нанесіть на форму компонент Adoquery. У властивості Connection укажіть Adoconnection1, у властивості SQL введіть текст запиту:
 
select sum(oklad) as sumoklad from sotr
 
У події форми Oncreate додайте команду:
 
adoquery1.active:=true;
 
У події сітки Onupdatefooter додайте команду:
 
wwdbgrid1.columnbyname('oklad').footervalue:=vartostr(adoquery1.fieldbyname('maxoklad').value); (початок) 
4. Робота з компонентами Infopower
Робота зі списками
Для створення списків, що випадають, бібліотека Infopower має компоненти:
 wwdbcombobox - звичайний список, що випадає, який можна через властивість Items заповнити значеннями й зв'язати з полем таблиці;
wwdblookupcombo - список, що випадає, який заповнюється значеннями за допомогою даних іншої таблиці або запиту. Для цього використовують властивості Listsource і Listfield;
wwdblookupcombodlg - список аналогічний попередньому, але замість списку значень дозволяє відобразити цілу сітку для більш правильної ідентифікації значення при виборі.
Дані компоненти можна вбудовувати в сітку, створюючи тим самим списки для стовпчиків сітки. Наприклад, для поля dolgnost створити список з переліком наявних значень.
Нанесіть на форму компонент Adoquery (ADO). У властивості Connection укажіть Adoconnection1, у властивості SQL введіть текст запиту:
 
select distinct dolgnost from sotr
 
Двічі клацніть на компоненті Adoquery1, у вікні редактора полів викличте контекстне меню й виберіть команду Add All Fields для відображення поля dolgnost.
У події форми Oncreate додайте команду:
 
adoquery1.active:=true;
 
Нанесіть на форму компонент wwdbcombobox (Ipcontrols). Для компонента задайте властивості: Lookuptable=Adoquery1, Lookupfield=dolgnost.
Двічі клацніть на сітці wwdbgrid1. У списку полів виберіть поле dolgnost, на закладці Editcontrol у списку Controltype виберіть Customedit, у списку Controlname укажіть wwdblookupcombo1. Після цього при переході в поле dolgnost сітки автоматично буде з'являтися список значень.
При видаленні або зміні даних вміст цього списку повинне обновлятися. Для цього в події Afterdelete і Afterpost таблиці Adotable1 укажіть код оновлення запиту:
 
adoquery1.refresh;
 
Робота з календарями
Бібліотека Infopower має два компоненти для роботи з датами й часом:
wwdbmonthcalendar - календар для вибору дати. На відміну від звичайного календаря компонент має властивості Datasource і Datafield. Це дозволяє автоматично прив'язати компонент до поля з датою;
wwdbdatetimepicker - поле з календарем, що випадає. Також може бути прив'язане до поля таблиці за допомогою властивостей Datasource і Datafiled.
 Календарі можна вмонтувати в сітку. Для цього нанесіть на форму потрібний календар. Клацніть два рази по сітці. У списку виберіть поле, у якому зберігається дата або час. На закладці Editcontrol  у списку Controltype виберіть Customedit, у списку Controlname укажіть ім'я вашого календаря.
 
Робота з редактором для полів Memo
Якщо поле містить великий обсяг тексту, у тому числі й форматований, то для роботи з таким полем можна використовувати компонент wwdbrichedit. Даний компонент зв'язується з полем як звичайно за допомогою властивостей Datasource і Datafiled. Крім цього компонентів має властивості:
Autodisplay - включає автоматичне відображення вмісту поля в компоненті (впливає на швидкість роботи програми);
Autourldetect - включає автоматичне розпізнавання гіперпосилань у тексті;
Editoroption - параметри вбудованого редактора при роботі з текстом;
Popupoptions - задає набір команд контекстного меню, відображуваних для поля.
 Компонент wwdbrichedit має вбудоване контекстне меню. Набір цих команд настроюється у властивості Popupoptions. Основною командою є команда Edit, яка відкриває вікно редактора для роботи з текстом і його форматування.
Компонент можна вмонтувати в сітку. Для цього клацніть два рази по сітці. У списку виберіть поле Memo. На закладці Editcontrol  у полі в списку Controltype виберіть Richedit, у списку Controlname укажіть компонент wwdbrichedit
 
Робота із графічними полями
У сітку можна вмонтувати графічне зображення. Для цього нанесіть на форму компонентів Dbimage або pdbimage. Клацніть два рази по сітці. У списку виберіть поле для зберігання графіки. На закладці Editcontrol  у списку Controltype виберіть Customedit, у списку Controlname укажіть компонент pdbimage.
Потрібно бути уважними із прапорцем Control Always Paints. Якщо його включити, то вміст усіх записів автоматично відобразиться в сітці. Якщо записів багато, то таке завантаження займе багато часу. якщо ж прапорець виключений, то вміст поля ви зможете побачити тільки при клацанні по комірці поля мишею.
 
Навігаційна панель wwdbnavigator
Дана панель зовні схожа на звичайну панель Dbnavigtor, однак по набору властивостей і можливостей панель значно функціональніше. Панель має властивості:
Buttons - основна властивість, що дозволяє створювати потрібні кнопки на панелі й задавати їм властивості;
Images - посилання на компонент Imagelist з іконками для кнопок;
Layout - задає горизонтальне або вертикальне розміщення кнопок на панелі
 Для настроювання параметрів роботи панелі використовують властивість Buttons. При відкритті властивості відкриється редактор кнопок. За допомогою панелі інструментів редактора можна створювати й видаляти кнопки. Кнопки можна перетаскувати, змінюючи їх порядок. Кожна кнопка має властивості:
Caption - текст напису на кнопці;
Hint - текст спливаючої підказки;
Imageindex - номер картинки зі списку Imagelist;
Showtext - включає відображення назви кнопки;
Style - головна властивість. Задає дію, яка буде виконувати кнопка. Серед дій є команди навігації, команди редагування й команди виклику діалогів
Переклад елементів Infopower
Інтерфейс редактора для полів Memo, діалогів і інших компонентів англомовний. Для перекладу необхідно нанести на форму компонент wwintl (IP Dialogs). Серед властивостей компонента знайдіть те, ім'я якого збігається з іменем використовуваного вами компонента бібліотеки InfoPower. Розкрийте цю властивість і введіть російські назви для елементів. Після перекладу встановіть властивість Connected=true. (початок) 
5. Створення складених елементів у сітці
Якщо в таблиці існує безліч полів, то відобразити їх в один рядок не завжди можливо. У цьому випадку поля можна групувати за деякою ознакою й відображати у вигляді стовпчика значень або у вигляді списку полів.
 
Створення стовпчика полів
Для створення полів у вигляді стовпчика використовують компонент wwdatainspector. За допомогою властивості Datasource компонент можна зв'язати із БД. За допомогою властивостей Captioncolor і Color задайте колір для комірок заголовка і комірок даних.
Подвійним клацанням на компоненті відкривається вікно редактора полів. За допомогою кнопки Newitem створіть список полів. Кожне поле має властивості:
Сaption - текст заголовка для поля в компоненті;
Datafields - ім'я поля, відображуване в компоненті;
Customcontrol - ім'я компонента, який буде підставлений у компонент для редагування поля.
Після настроювання компонента його потрібно вмонтувати в сітку. Для цього:
у таблиці Adotable створимо порожнє поле, що обчислюється. Клацніть на компоненті Adotable два рази, у контекстному меню редактора полів виберіть команду New Field. Уведіть ім'я поля й будь-який тип даних;
клацніть два рази на сітці. За допомогою кнопки Add Fields додайте створене вами поле, що обчислюється. Для поля на закладці Editcontrol у полі Controltype укажіть Customcontrol, а в полі Controlname укажіть компонент wwdatainspector;
в компоненті wwdatainspector поля відображаються в кілька рядків, тому потрібно змінити висоту рядка сітки. Для цього у властивості сітки Rowheightpercent укажіть відсоток висоти рядка з розрахунку 110 відсотків на 1 рядок (наприклад, три рядки рівні 330).
Створення списку полів
Список також дозволяє групувати дані в сітці, при цьому не потрібно збільшувати висоту рядка. Висота автоматично збільшитися при розкритті списку й зменшится при закритті.
Для створення списку, що розкривається, використовують компонент wwexpandbutton. Компонент має властивості:
Buttonalignment - вирівнювання кнопки в полі;
Сaption - текст напису на кнопці;
Grid - ім'я компонента, відображуваного при розкритті списку. Можна вказати як сітку wwdbgrid так і компонент wwdatainspector;
Showtext - включає відображення напису на кнопці.
 Для створення списку, що розкривається, можна використовувати такі дії:
нанесіть на форму компонент wwdatainspector і відобразіть в ньому потрібні поля таблиці (див.вище);
на форму нанесіть компонентів wwexpandbutton і у властивості Grid укажіть компонент wwdatainspector;
у таблиці Adotable створимо порожнє поле, що обчислюється. Клацніть на компоненті Adotable два рази, у контекстному меню редактора полів виберіть команду New Field. Уведіть ім'я поля й будь-який тип даних;
клацніть два рази на сітці. За допомогою кнопки Add Fields додайте створене вами поле. Для поля на закладці Editcontrol у полі Controltype укажіть Customcontrol, а в полі Controlname укажіть компонент wwexpandbutton. (початок) 
6. Робота зі зв'язаними таблицями
Принцип списку, що розкривається, зручно використовувати для роботи зі зв'язаними таблицями. Нехай на формі є два компоненти Adotable, які зв'язані між собою за допомогою властивостей Mastersource і Masterfield, а також дві сітки wwdbgrid, у кожній з яких відображаються дані з головної й підлеглої таблиць.
Для зв'язування таблиць за допомогою списку, що випадає, необхідно:
нанести на форму компонент wwexpandbutton. У властивостях Datasource і Datafield укажіть ключове поле головної таблиці. У властивості Grid укажіть сітку wwdbgrid підлеглої таблиці, у властивості Showtext укажіть true;
подвійним клацанням відкрийте редактор полів сітки головної таблиці. Виділіть ключове поле цієї таблиці, на закладці Editcontrol у полі Controltype укажіть Customcontrol, а в полі Controlname укажіть компонент wwexpandbutton. (початок) 
Питання для самоперевірки
1. Який компонент дозволяє відображати із БД графічну інформацію у форматах JPEG і GIF. Як установити цей компонент?
2. Опишіть основні властивості таких компонентів як wwdbedit, wwspinedit, wwcheckbox з бібліотеки Infopower.
3. Опишіть основні властивості компонента Radiogroup з бібліотеки Infopower.
4. Опишіть основні властивості сітки wwdbedit з бібліотеки Infopower.
5. Опишіть основні властивості окремого стовпчика в сітці wwdbgrid з бібліотеки Infopower.
6. Як зберегти й відновити параметри сітки wwdbgrid з бібліотеки Infopower через реєстр?. Приклад
7. Як працювати з підвалом сітки wwdbgrid з бібліотеки Infopower? Які властивості відображають рядок підвалу? Приведіть код відображення даних у рядку підвалу.
8. Які компоненти є в бібліотеці Infopower для роботи з датами, приведіть властивості цих компонентів. Який компонент служить для роботи з  Memo полями, приведіть властивості цього компонента
9. Опишіть основні властивості компонента wwdbnavigator з бібліотеки Infopower.
10. Опишіть принцип відображення стовпчика полів таблиці в сітці wwdbgrid з бібліотеки Infopower.
11. Як створити список полів, що розкривається, у сітці wwdbgrid з бібліотеки Infopower?
Лекція № 15
Тема: «Створення звітів в Delphi»
 
План
1. Загальні відомості
2. Проектування звичайного звіту
3. Групування даних у звіті
4. Створення звіту для зв'язаних таблиць
5. Друк й експорт звіту
 
1. Загальні відомості
У більшості випадків дані, які зберігаються в таблицях БД, необхідно тим або іншим способом публікувати, створюючи так звані звіти. Уже в першу версію Delphi були включені засоби генерації звітів. Перехід на компонентний рівень дозволив використовувати природню для Delphi техніку візуального програмування, що суттєво спростило як розробку програм, так і їх поширення – компоненти є вбудованими в програму «цеглинками» і не мають потреби в яких-небудь зовнішніх засобах для виконання покладених на них завдань. Від версії до версії ці компоненти удосконалювалися, їхній набір розширювався, так що в Delphi 6 на вкладці QReport розміщалося вже більше 20 компонентів, за допомогою яких програміст міг порівняно легко створювати досить складні звіти.
В Delphi 7 є пакет dclqrt70.bpl з компонентами QReport, але за замовчуванням він не встановлюється. Якщо ви хочете працювати з технологією Quick Report установіть цей пакет. Для цього виберіть команду Component - lnstall Packages, клацніть на кнопці Add і вкажіть цей файл, який знаходиться в папці Bin каталогу розміщення Delphi. У результаті на палітрі компонентів з'явиться нова закладка QReport з набором компонентів необхідних для створення звітів.
 
2.Проектування звичайного звіту
Центральним компонентом при побудові звіту є компонент QuickRep (QReport), що визначає властивості звіту в цілому. Цей компонент завжди поміщається на окрему порожню форму, утворюючи з її допомогою візуальне середовище конструювання звіту.
Після нанесення компонентів на формі створюється макет чистого аркуша паперу (його поля обкреслені пунктирними лініями). На цей макет поміщаються інші компоненти точно так, ніби створювалася звичайна форма.
 
Настроювання параметрів сторінки
Для настроювання параметрів сторінки звіту виконайте подвійне клацання на аркуші звіту. У результаті відкриється вікно настроювання параметрів:
у групі Page Size вказують розмір і орієнтацію аркуша;
у групі Margins вказують величину полів, число стовпчиків і відстань між колонками;
у групі Other вказують параметри шрифту звіту;
у групі Page frame задають параметри малювання рамки навколо аркуша звіту.
Задавання переліку смуг звіту
Звіт в основному будується з компонентів-смуг QRBand, за допомогою яких формуються різні його фрагменти, такі як спільний заголовок, заголовок кожної сторінки, заголовки стовпчиків звіту, область для відображення даних з таблиці БД і т.п.
Для завдання потрібного переліку смуг на звіті у вікні настроювань аркуша звіту в групі Bands прапорцями відзначте потрібні смуги:
Page header – верхній колонтитул;
Title – заголовок звіту. Відображається тільки в верхній частині першої сторінки звіту;
Column header – містить заголовок стовпців звіту (шапку таблиці);
Detail band – смуга, що відображає дані таблиць БД;
Page footer – нижній колонтитул;
Summary – рядок підвалу звіту для відображення результуючих даних (сума, кількість, середнє й т.п.)
Обов'язкової є смуга Detail. Інші смуги потрібні для оформлення.
 
Додавання на сторінку звіту візуальних компонентів
Після створення смуг можна приступати до проектування звіту. На сторінку можна додавати тільки компоненти, розташовані на закладці QReport. У будь-якій смузі можна розмістити будь-який компонент із цієї закладки.
Усі компоненти мають властивість Autosize=true, тобто ширина компонента підганяється під розмір тексту в цьому компоненті. Це не дозволяє правильно задати розмір і положення компонентів на сторінці. Рекомендується цю властивість установлювати в false.
Для розміщення полів з таблиці БД сам звіт зв'язують із таблицею БД за допомогою властивості DataSet. Після підключення звіту до таблиці в смузі Detail розміщають потрібні компоненти й за допомогою властивостей DataSet і DataField їх зв'язують із полями таблиці. Зауваження: з полями бази даних можна зв'язати тільки ті компоненти, які у своїй назві мають префікс DB (QRDBText, QRDBRichText, QRDBImage). Якщо у компоненті відображається числова інформація, то у властивості Mask компонента можна задати шаблон відображення чисел після коми.
 
 
Малювання рамок у звіті
Якщо звіт видається у вигляді таблиці, то доводиться малювати рамки навколо чарунок. Для малювання рамки потрібно виконати такі дії:
спочатку рамка малюється зверху і знизу смуги звіту. Для цього кожна смуга має властивість Frame, у якій задають колір, тип і товщину лінії рамки, а також сторони для малювання рамки;
потім навколо кожнього візуального компонента малюють ліву і праву лінію рамки. Для цього кожен компонент має властивість Frame, Компоненти розміщують так, щоби вони торкалися один одного, а також верхньої границі смуги;
висоту смуги зменшують таким чином, щоби її нижня лінія торкалася знизу візуальних компонентів.
Вставка графічної інформації у звіт
У звіт можна вставляти як статичні зображення (емблема організації, герб і т.п.), так і вміст blob-полів.
У першому випадку використовується компонент QRImage, для якого задається властивість Picture і Stretch. Даний компонент можна розміщати в будь-якій смузі звіту.
У другому випадку використовується компонент QRDBimage, який може розміщатися тільки в смузі Detail і має властивості Dataset і Datafield.
 
Використання формул у звіті
У звіті крім статичних написів або вмісту полів таблиць можна широко використовувати формули. Формули можуть містити знаки операцій, функції, числа й імена полів. Для впровадження формули у звіт використовують компонент QRExpr, у властивості Expression якого вводять формулу для розрахунків.
При виборі властивості Expression відкривається вікно для введення формули. Для введення функції використовують кнопку Function, яка відкриває список доступних функцій, розбитих на групи.
Якщо компонент QRExpr розмістити усмузі Summary, а в якості функції використовувати sum, count, max, min, то можна підрахувати загальні показники по всьому звіту.
 
Використання шаблонів у звіті
Компонент Qrexprmemo дозволяє чередувати текстові константи й імена полів таблиць БД. Таке чередування дозволяє створювати аналог шаблонів, аналогічно шаблонам Word або Excel.
У властивості компонента Lines уводять текст шаблону, при цьому в тексті вводять імена полів у фігурних скобках, наприклад:
 
Прізвище: {fam};
Ім'я: {imya};
По батькові: {otch};
 
Використання системних змінних
Крім функцій і формул у звіти можна вставляти системні змінні: номер сторінки, дата, час, номер рядка й т.п.
Такі змінні можна додати за допомогою компонента QRSysData. У компонента є властивість Data, у якій вибирають тип відображуваної інформації.
 
Умовне форматування звіту
Інколи треба, щоби в залежності від певної умови дані друкувалися із різним форматуванням. Для виконання цієї дії треба написати код у події BeforPrint відповідної смуги звіту (найчастіше у якості такої полоси виступає панель Deatil зі списком полів).
Приклад. У смузі DetailBand знаходиться компонент для розрахунку суми стипендії. Компонент має ім'я QRExpr1. Треба написати код, який розфарбує смуги звіту в залежностя від розміру стипендії: 0 - перший колір, 400 - другий колір, 450 - третій колір.
У події BeforPrint смуги DetailBand1 введіть код:
 
procedure TForm2.DetailBand1BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean);
begin
    if qrexpr1.value.intResult=0 then
        DetailBand1.color:=$00ACCCF7
    else if qrexpr1.value.intResult=400 then
        DetailBand.color:=$00BDEBB8
    else
        DetailBand.color:=$00AFF3ED;
end;
 
3. Групування даних у звіті
Якщо поле таблиць має повторювані дані, то такі дані можна згрупувати, а для кожної групи розрахувати загальні показники. Для групування треба відсортувати дані по полю, по якому буде групуватися інформація. Додайте на форму компонент QRGroup (QuickRep), у властивості Expression ведіть ім'я поля, по якому буде виконуватися групування.
Після створення групування у звіт потрібно внести деякі зміни: поле, по якому виконується групування, потрібно перемістити зі смуги Detail у смугу Group Header. Також у смугу Group Header потрібно перемістити заголовки стовпчиків звіту (шапку таблицю).
 
Розрахунки підсумкових показників по групі
Для відображення підсумкових даних потрібно додати на звіт нову смугу. Нанесіть на форму компонент QRBand (QuickRep). Виділіть смугу Group Header і у властивості FooterBand укажіть ім'я доданої смуги. У результаті смуга одержить ім'я Group Footer.
У даній смузі можна розмістити компоненти QRExpr і для них задати потрібні функції для розрахунків. Для розрахунку функції по кожній групі окремо необхідно для компонента QRExpr обов'яково встановити властивість ResetAfterPrint=true.
 
4. Створення звіту для зв'язаних таблиць
Якщо звіт будується по зв'язаних таблицях, то спочатку будується звичайний звіт для головної таблиці. Потім для підлеглої таблиці на звіт додають смугу QRSubDetail (QuickRep). У властивості DataSet цієї смуги вкажіть посилання на підлеглу таблицю. У цій смузі розмістіть потрібні візуальні компоненти й зв'яжіть їх з полями підлеглої таблиці.
 
Розрахунки підсумкових показників по групі
Для відображення підсумкових даних по підлеглій таблиці потрібно додати на звіт нову смугу. Нанесіть на форму компонент QRBand (QuickRep). Виділіть смугу SubDetail і у властивості FooterBand укажіть ім'я доданої смуги. У результаті смуга одержить ім'я Group Footer.
У даній смузі можна розмістити компоненти QRExpr і для них задати потрібні функції для розрахунків. Для розрахунку функції по кожній групі підлеглих записів окремо необхідно для компонента QRExpr обов'яково задати властивості Mask=SubDetail1, ResetAfterPrint=true.
 
5. Друк і експорт звіту
Після створення звіту його можна переглядати, друкувати або зберігати у файл. Звіт перебуває на окремій формі, тому викликати його можна за допомогою команди:
 
form2.quickrep1.preview;
 
Найчастіше форма зі звітом не повинна створюватися при запуску програми, тому її переміщають у список Available Forms. У цьому випадку виклик форми може мати вигляд:
 
form2:=tform2.create(self);
form2.quickrep1.preview;
 
В обох випадках з'являється вікно попереднього перегляду. На панелі інструментів вікна є кнопки для зміни масштабу перегляду, переходу між аркушами звіту, друку й настроювання принтера, збереження й відкриття збереженого звіту.
 
Експорт звіту
При збереженні звіту створюється файл із розширенням *.qrt. Такий формат можна відкрити тільки в програмі, що підтримує технологію Quickreport. Даний формат не є розповсюдженим, тому звіт потрібно експортувати в більш розповсюджений тип: текстовий файл або HTML.
Для організації експорту необхідно на форму зі звітом додати компоненти Qrtextfilter або Qrhtmlfilter. Після додавання цих компонентів при збереженні звіту стане доступною можливість вибору таких типів файлів як Text File і HTML Document.
Файли після экспорту не завжди мають зовнішній вигляд, що збігається з виглядом оригіналу, проте їх можна відкрити й відредагувати.
 
Питання для самоконтролю
1. Як установити бібліотеку QuickReport? З якого компонента починається проектування звіту?
2. Як задати параметри сторінки для звіту QuickReport?
3. Які смуги може містити звіт QuickReport, як їх додати на звіт?
4. Які візуальні компоненти можна додавати на звіт QuickReport? Як компоненти зв'язуються з полями таблиці?
5. Опишіть принцип малювання рамок у звітах QuickReport. За допомогою яких компонентів можна відобразити у звіті графічну інформацію?
6. Опишіть вставку у звіт QuickReport формул, системних змінних і шаблонів.
7. Опишіть процедуру групування даних у звіті QuickReport.
8. Опишіть процедуру створення звіту QuickReport по зв'язаних таблицях.
9. Опишіть принцип перегляду, друку й експорту звіту QuickReport.
 
Лекція № 16
Тема: "Створення WEB додатків у середовищі Delphi"
 
План
1. Основні поняття WEB додатків
2. Створення модуля Web
3. Використання форм HTML
4. Приклад побудови WEB додатка
5. Відображення даних із БД у вигляді таблиці
6. Організація сортування даних із БД
7. Організація редагування даних
 
1. Основні поняття WEB додатків
Середовище програмування Delphi має кілька технологій створення WEB додатків. Для перевірки роботи таких додатків на машині розроблювача повинен бути встановлений WEB-сервер із підтримкою виконання спеціальних WEB програм. У якості такого сервера можна використовувати Denwer, у якого є всі необхідні можливості. При цьому в теці home/localhost є спеціальна тека cgi, у яку й потрібно буде поміщати створені програми й інші елементи, необхідні для їхньої роботи (шаблони WEB сторінок, файли БД і т.п.). Для запуску такої програми у вікні браузера потрібно ввести команду:
 
localhost/cgi/ім'я_програми.exe
 
Для побудови таких додатків поряд з компонентами й операторами самого середовища Delphi широко використовуються теги мови HTML. WEB додатки на Delphi можуть створювати статичні сторінки, за допомогою яких у вікні браузера можна відображати довільну, постійну інформацію. Однак, найцікавішими є динамічні сторінки. У цьому випадку серверу від клієнта надсилається динамічний запит на виконання деякої EXE програми. Сервер обробляє його, за допомогою виконаної програми динамічно формує документ HTML і посилає його користувачеві.
 
2. Створення модуля Web
Серверні додатки будуються в Delphi на основі WEB-компонента WEBModule. Цей компонент може служити контейнером для низки інших компонентів. Сервер типу WEBModule відсутній на закладках компонентів. Щоб спроектувати його, треба виконати команду File - New - Other і в діалоговому вікні New Items на сторінці New вибрати піктограму Web Server Application. Відкриється вікно, у якому потрібно вказати тип сервера.
 

 
Виберіть тип "CGI Stand-alone executable. Після цього відкриється порожнє вікно модуля, у якому можна розміщати різноманітні компоненти.
Основна властивість модуля — Actions. Це список дій модуля. Заповнюється це список спеціальним редактором дій, викликуваним клацанням на кнопці із трьома крапками поруч із властивістю Actions. Це ж вікно відкриється, якщо ви виконаєте подвійне клацання на порожньому тлі у вікні модуля.
 

 
У вікні, що відкрилося, кнопкою Add New (перша на панелі інструментів) ви можете додати нову дію, кнопкою Delete Selected (друга) – вилучити виділену дія, кнопками зі стрілками – змінити послідовність дій.
Кожна дія – об'єкт зі своїми властивостями, методами й подіями. Властивість Default задає дію за замовченням. Якщо властивість в одній з дій установлена в true, то ця дія є дією за замовчуванням. Основна властивість дії – PathInfo. Щоб зрозуміти її призначення, треба розглянути деякі додаткові відомості про URL. У загальному випадку URL може виглядати так:
 
http://myserv.com/cgi/program.exe/action1?value=5&resp=yes
 
Починається URL із зазначення протоколу (HTTP). Далі іде ім'я хоста — адреса сервера (у наведеному прикладі "myserv.com"). Потім іде ім'я серверного додатка й шлях до нього (у наведеному прикладі "/cgi/program.exe"). Після цього, починаючись із останнього символу слеша й аж до знаку питання записується необов'язкова частина URL, іменована PathInfo. У наведеному прикладі URL це "/action1". Ця інформація визначає, яку дію зі списку потрібно виконати. У нашому випадку при запуску серверного додатка запуститься дія, у якої властивість PathInfo="/action1".
Після символу знаку питання іде частина URL, називана Query – запит. Звичайно вона складається зі списку, що включає ідентифікатори, символи рівності й значення цих ідентифікаторів. Окремі елементи списку відділяються друг від друга символом "&". У наведеному прикладі введене ім'я value зі значенням "5" і ім'я resp зі значенням "yes". Це інформація, яка передається процедурі серверного додатка для обробки.
Кожна дія модуля має подію OnAction, у якій уводиться код, виконуваний цією дією. При цьому подія має ряд параметрів.
Параметр Request визначає об'єкт запиту. Основна властивість цього об'єкта Query — рядок типу string, що представляє частину Query запиту URL. У наведеному вище прикладі URL вона має вигляд: "value=5&resp=yes". Інша властивість об'єкта запиту – QueryFields. Ця властивість представляє Query запиту URL у вигляді списку рядків. У наведеному прикладі він буде містити два рядки: "value=5" і "resp=yes". Таким чином, через об'єкт QueryFields оброблювач події отримує доступ до інформації, що міститься у запиті. Звертатися до значень параметрів запиту зручно за допомогою методу Request.QueryFields.Values['resp'] (поверне рядок "yes").
Параметр Response визначає об'єкт відповіді. Основна властивість цього об'єкта Content – відповідь користувачеві у вигляді тексту HTML, імені файлу HTML і деяких інших видів.
 
3. Використання форм HTML
Часто WEB додатки є інтерактивними. Вони дають можливість для користувача брати участь у роботі програми: додавати, редагувати й видаляти дані, задавати запити на пошук інформації й т.п.
Подібну можливість надають форми, описувані тегом HTML. У формах можуть використовуватися стандартні компоненти однорядкових і багаторядкових полів редагування, кнопок, списків, що випадають, перемикачів, індикаторів і інших компонентів.
Уведені клієнтом у форму дані кодуються в спеціальний формат і посилають на сервер.
Форма починається з тегу <form>,  у якому треба задати кілька атрибутів. Атрибути задаються у форматі "ім'я=значення". Адреса URL одержувача даних, внесених користувачем у компоненти форми, вказується атрибутом action. Наприклад:
action=http://myserver.com/cg /test.ехe
 
або
 
action=http://myserver.com/cg /test.ехe/edit
 
У першому випадку вказується, що дані форми будуть оброблятися програмою test.exe (подією за замовчуванням).
У другому випадку вказується, що дані форми будуть оброблятися програмою test.exe (подією, у якої властивість PathInfo="/edit").
Для створення коду форми доцільно використовувати один зі спеціальних WEB редакторів. При цьому для коректного вирівнювання полів форми рекомендується спочатку створювати порожню форму, потім на формі розміщати таблицю, а вже в чарунках таблиці розміщати елементи форми: написи й компоненти.
Серверному додатку посилають значення всіх компонентів на формі. Прочитати їхні значення можна за допомогою властивості:
 
Request.ContentFields.Values ['ім'я_компонента']
 
HTML форми зберігаються у зовнішніх HTML файлах. Для їхнього використання в серверному додатку використовується спеціальний компонент DataSetPageProducer (Internet). У властивості HTMLFile даного компонента вказують ім'я зовнішнього файлу зі створеним шаблоном форми (файл цього шаблону повинен знаходитися в одній папці з файлом серверного додатка або до нього повинен бути зазначений повний шлях на WEB сервері).
Для відображення зв'язаного шаблону у вікні браузера в модулі WEB додатка створіть дію й уведіть код:
 
response.content:=datasetpageproducer1.content;
 
Підстановка даних на формі
При відкритті форми у вікні браузера необхідно, щоб деякі (або всі) елементи форми заповнювалися значеннями за замовчуванням.
Для вирішення даного завдання потрібно виконати дві дії:
- у шаблонові форми для потрібних компонентів задати значення властивості value у вигляді:
 
value="<#значення>"
 
- у коді WEB додатка в події OnHTMLTag компонента DataSetPageProducer уведіть код виду:
 
if tagstring='значення' then
    replacetext:='значення, що підставляється';
 
4. Приклад побудови WEB додатка
Створимо додаток для перевірки знань таблиці множення. У вікні браузера відображається форма виду:
 

 
Спочатку в редакторі FrontPage створимо шаблон HTML сторінки для майбутньої програми. Сторінка має дві форми: перша для введення даних і перевірки результату, друга для генерування нових чисел.
На першій формі поля мають імена: num1, num2, result. Перші два поля форми будуть заповнюватися деякими значеннями за замовчуванням, тому для них задамо властивість value: перше поле – value="<#num1>"; друге поле – value="<#num2>".
Кожна форма обробляється програмою mult.exe. При цьому перша форма обробляється дією зі значенням властивості PathInfo = "/result", а друга – дією за замовчуванням.
Повний код шаблону форми має вигляд:
<html></p>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">        <title>Лекция 15</title>    </head>    <body>        <form method="post" action="http://localhost/cgi/mult.exe/result">        <div align="center">        <table border="1" width="50%" id="table1">            <tr>                <td colspan="2">Перевірте таблицю множення</td>            </tr>            <tr>                <td width="32%">Перше число</td>                <td width="65%">                <input type="text" name="num1" size="20" value="<#num1>"></td>            </tr>            <tr>                <td width="32%">Друге число</td>                <td width="65%">                <input type="text" name="num2" size="20" value="<#num2>"></td>            </tr>            <tr>                <td width="32%">Відповідь</td>                <td width="65%"><input type="text" name="result" size="20"></td>            </tr>            <tr>                <td width="97%" colspan="2" align="center">                <input type="submit" value="Перевірити" name="post"></td>            </tr>        </table>        </div>        </form>        <form method="POST" action="http://localhost/cgi/mult.exe">            <input type="submit" value="Нові числа" name="new">        </form>    </body>    </html>
 
У середовищі Delphi виконайте команду File – New – Other. На закладці New виберіть тип додатка Web Server Application. У вікні, що з'явилося, виберіть тип додатка "CGI Stand-alone executable". Відкриється вікно модуля програми. Збережіть проект у папку й помістіть в неї створений шаблон HTML сторінки.
Для використання шаблону в WEB додатку додайте у вікно модуля компонент DataSetPageProducer (Internet) і у властивості HTMLFile укажіть файл шаблону форми й вилучіть шлях до файлу.
При відкритті сторінки у вікні браузера перші два поля повинні заповнюватися значеннями за замовчуванням. Для цього потрібно описати дві глобальні змінні.
 
var num1,num2:integer;
 
У події OnHTMLTag компонента DataSetPageProducer уведіть код:
 
//якщо поле має значення value="<#num1>"
if tagstring = 'num1' then
begin
    //записуємо в це поле значення змінної num1
    replacetext:=inttostr(num1);
end
//якщо поле має значення value="<#num2>"
else if tagstring = 'num2' then
begin
    //записуємо в це поле значення змінної num2
    replacetext:=inttostr(num2);
end;
  
При запуску WEB додатка запуститься дія за замовчуванням, яка заповнює два перші поля на формі випадковими числами. Ця ж дія обробляє дані для другої кнопки (для кнопки "Нові числа"). У вікні модуля програми виконайте подвійне клацання на порожньому тлі. У вікні списку дій клацніть на першій кнопці для створення нової дії й задайте властивість Default = True (дія за замовчуванням). У події OnAction цієї дії введіть код:
 
//генеруємо випадкові числа
randomize;
num1:=random(8)+1;
num2:=random(8)+1;}
//передаємо шаблон сторінки на машину клієнта
response.content:=pageproducer1.content;
 
Перша форма (кнопка "Перевірити") обробляється подією, у якої властивість PathInfo="/result".
У вікні модуля програми виконайте подвійне клацання на порожньому тлі. У вікні списку дій клацніть на першій кнопці для створення нової дії й задайте властивість PathInfo = /result. У події OnAction цієї дії введіть код:
 
//якщо добуток уведений правильно
if request.contentfields.values['result']=
    inttostr(strtoint(request.contentfields.values['num1'])*
    strtoint(request.contentfields.values['num2'])) then
        //видаємо повідомлення про успіх
        response.content:='Поздоровляємо! Ви блискучий математик!'
//якщо добуток уведений не правильно
else
    //видаємо повідомлення про невдачу
    response.content:='Ви забули таблицю множення! Спробуйте ще раз';
 
Відкомпілюйте проект. Скопіюйте отриманий EXE файл і файл шаблону сторінки в теку home/localhost/cgi сервера Denwer. Запустіть Denwer і у вікні браузера введіть адресу:
 
localhost/cgi/ім'я_програми.exe
 
5. Відображення даних із БД у вигляді таблиці
Тепер розглянемо роботу із базами даних. Найбільш простим прикладом є організація перегляду даних БД у вигляді таблиці.
Нехай є новий проект WEB з ім'ям primerdb.
Для роботи із БД у вікні модуля потрібно розмістити компонент ADOConnection (ADO) для створення підключення до БД і компонент ADOTable або ADOQuery (ADO) для завдання таблиці або запиту.
Для відображення даних і БД у вигляді таблиці використовується компонент DataSetTableProducer (Internet). Даний компонент має ряд властивостей:
- DataSet визначає посилання на джерело даних, з якого будуть відображатися записи (ADOTable або ADOQuery);
- Header визначає команди HTML, які повинні розташовуватися в документі перед таблицею. Це можуть бути команди виводу назви таблиці:
 
<html>
<body>
    <h3 align="center">Список співробітників</h3>
 
- Footer визначає команди HTML, які повинні виконуватися після таблиці. У нашому випадку це можуть бути команди:
</body>
</html>
- Title - Caption визначає заголовок таблиці.
- Maxrows встановлює максимальне число рядків таблиці. Якщо число записів виявиться менше, то число рядків таблиці визначиться фактичним числом записів. Але якщо число записів у таблиці більше, то на екран буде видано тільки Maxrows перших записів.
Для побудови таблиці з даними виконайте подвійне клацання на компоненті DataSetTableProducer. У результаті відкриється вікно редактора.
 

 
У вікні потрібно вказати поля набору даних, які повинні відображатися в таблиці. Це можна зробити або швидкою кнопкою Add New — додати поле (перша на панелі інструментів), або кнопкою Add All Fields – додати всі поля (передостання). Втім, ця кнопка буде доступна, тільки якщо в ADOTable або ADOQuery ви задали перелік полів і їх властивості.
Кожне поле в списку має властивості: FieldName = ім'я поля, Title – Caption = текст напису.
Індикатори в лівій панелі вікна редактора дозволяють установити загальні властивості таблиці. Зокрема, поле Border дозволяє задати ширину ліній сітки таблиці. Поле Width визначає ширину таблиці у відсотках від ширини сторінки. Якщо встановити 100%, то при перегляді в браузері ширина таблиці буде вибиратися автоматично виходячи із ширини вікна браузера й буде змінюватися при зміні ширини таблиці. Якщо задати Width < 100%, то ширина таблиці буде фіксованою.
Для відображення такої таблиці у вікні браузера у вікні модуля створіть нову дію, задайте для нього властивість Default=True (дії за замовчуванням) і в події ОnAction уведіть код:
 
adotablet.active:= true;
response.content:=datasettableproducerl.content;
adotablel.active := false;
 
Відкомпілюйте проект. Скопіюйте файл primerdb.exe і файл БД у папку home/localhost/cgi, запустіть Denwer і у вікні браузера введіть адресу:
 
localhost/cgi/primerdb.exe
 
6. Організація сортування даних із БД
Для сортування даних треба над таблицею з даними створити нову таблицю із переліком гіперпосилань, кожне з яких виконує сортування даних по конкретному полю.
 

 
При цьому сортування будемо виконувати за допомогою нової дії, у якої властивість PathInfo буде рівним "/order". Номер поля для сортування будемо задавати за допомогою цілого числа.
В WEB редакторі підготуйте таблицю, у чарунках якої перебувають гіперпосилання для запуску WEB додатка із зазначеним номером поля для сортування:
 
primerdb.exe/order?1 – сортування по першому полю
primerdb.exe/order?2 – сортування по другому полю і т.д.
 
Для відображення таблиці сортування над таблицею з даними із БД у властивості Header компонента DataSetTableProducer1 додайте HTML код створеної таблиці сортування:
 
<table border="1" width="350" id="table1">
    <tr>
        <td colspan="2"><p align="center">Порядок сортування</td>
    </tr>
    <tr>
        <td align="center" width="173">
        <a href="http://localhost/cgi/primerdb.exe/order?1"> по першім полю</a></td>
        <td align="center" width="173">
        <a href="http://localhost/cgi/primerdb.exe/order?2"> по другім полю</a></td>
    </tr>
    <tr>
        <td align="center" width="173">
        <a href="http://localhost/cgi/primerdb.exe/order?3"> по третьому полю</a></td>
        <td align="center" width="173">
        <a href="http://localhost/cgi/primerdb.exe/order?4"> по четвертім полю</a></td>
    </tr>
</table>
 
Кожне гіперпосилання запускає на виконання WEB додаток з дією, у якої PathInfo="/order". Створимо цю дію в програмі.
У вікні модуля виконайте подвійне клацання на порожньому тлі вікна. У списку дій за допомогою кнопки Add New додайте нову дію й задайте властивість PathInfo="/order".
У події OnAction цієї дії введіть код:
 
//перевіряємо, з яким значенням параметра виконана подія
//і задаємо поле для сортування даних у таблиці
case strtoint(request.query) of
    1: adotable1.indexfieldnames :='tab';
    2: adotable1.indexfieldnames :='fam';
    3: adotable1.indexfieldnames :='imya';
    4: adotable1.indexfieldnames :='otch';
    5: adotable1.indexfieldnames :='datar';
    6: adotable1.indexfieldnames :='srbal';
end;
//підключаємося до таблиці
adotable1.active:=true;
//посилаємо вміст у вікно браузера клієнта
response.content:=datasettableproducer1.content;
//відключаємося від таблиці
adotable1.active:=false;
 
Відкомпілюйте проект. Скопіюйте оновлений файл primerdb.exe у теку home/localhost/cgi, запустіть Denwer і у вікні браузера введіть адресу:
 
localhost/cgi/primerdb.exe
 
Перевірте роботу функції сортування.
 
7. Організація редагування даних
Для редагування даних потрібно виконати кілька умов:
- у таблиці з даними повинен знаходитися елемент для позначки потрібного запису;
- на формі з таблицею потрібно створити кнопки для виконання основних операцій: додавання, редагування, видалення;
- потрібно розробити HTML шаблон форми для редагування полів обраному запису;
- створити код потрібних дій для роботи функцій WEB додатка.
 
Додавання в таблицю поля для позначки записів
Для позначки даних можна створити новий стовпчик з набором перемикачів. Користувач вибирає потрібний перемикач, і програма розуміє, яку саме запис потрібно редагувати або видаляти.
На малюнку наведений фрагмент таблиці, у якої в останньому стовпчику відображається список перемикачів.
 

 
Для створення такого стовпчика подвійним клацанням на компоненті DataSetTableProducer1 відкрийте редактор полів таблиці. За допомогою кнопки Add New додайте нове поле й задайте властивості: FieldName = довільне ім'я поля, Title – Caption = текст напису для стовпчика.
У події OnFormatCell компонента DataSetTableProducer1 потрібно написати код, що створює перемикачі в цьому стовпчику.
Наприклад, нехай таблиця БД має шість полів, ключове поле має ім'я "tab". Потрібно в новому сьомому стовпчику створити список перемикачів. При цьому кожний перемикач має ім'я "R1", а значення кожного перемикача буде збігатися зі значенням ключового поля "tab". У події OnFormatCell компонента введемо код:
 
//якщо таблиця не порожня і має рядки (cellrow>0)
//і якщо стовпчик 7 (нумерація з 0)
if (cellrow>0) and (cellcolumn=6) then
    //то в чарунці цього стовпчика створюємо перемикач (type="radio")
    //значення перемикача збігається зі значення поля tab (value="…")
    //перемикач обраний за замовчуванням (checked)
    //ім'я перемикача R1 (name="R1")
    celldata:='<input type="radio" value="'+adotable1.fieldbyname('tab').asstring+'" checked name="R1">';
 
Додавання кнопок для додавання, редагування й видалення даних
Для створення кнопок потрібно створити форму, яка містить список перемикачів, відображуваних в останньому стовпчику таблиці, і список кнопок, відображуваних під таблицею. Тобто маємо таку особливість, що форма починається над таблицею з даними, а закінчується під нею.
У властивості Header компонента DataSetTableProducer1 додамо код заголовка форми:
 
<form method="post" action="http://localhost/cgi/primerdb.exe/data">
 
У властивості Footer компонента DataSetTableProducer1 додамо код закінчення опису форми:
Начало формы
Конец формы
 
    <p align="left"><input type="submit" value="Додати" name="B1">
    <input type="submit" value="Редагувати" name="B2">
    <input type="submit" value="Вилучити" name="B3">
</form>
 
Як видно з коду на формі створюється три кнопки B1, B2, B3. Кожна з них має власний напис (value="…"). Крім цього форма обробляється дією WEB додатка, у якої PathInfo="/data". Створення цієї дії розглянемо пізніше.
 
Розробка HTML шаблону форми для редагування запису
В WEB редакторі створіть форму для введення значень полів поточного запису таблиці БД. Наприклад:
 

 
Дана форма повинна оброблятися деякою дією, у якої PathInfo буде рівним, наприклад, "/record".
Якщо запис редагується, то в кожному полі форми за замовчуванням повинні відображатися дані поточного запису. Тому кожному полю потрібно привласнити деяке значення за замовчуванням. Наприклад:
 
value="<#ім'я_поля>"
 
При відкритті форми на ній потрібно десь зберігати значення ключового поля таблиці. За допомогою цього значення ми будемо визначати чи є поточний запис новим або таким, що редагується (якщо ключове поле порожнє, то запис новий, інакше – такий, що редагується). В мові HTML є тег створення прихованих полів, до яких можна звертатися за ім'ям name.
 
<input type="hidden" name="…">
 
З урахуванням усього сказаного код шаблону може мати вигляд (зверніть увагу, що приховане поле має ім'я name="id"):
Начало формы
Конец формы
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body>
    <form method="POST" action="http://localhost/cgi/primerdb.exe/record">
    <table border="1" width="300" id="table1">
        <tr>
            <td width="142">Табельний номер</td>
            <td><input type="text" name="tab" size="20" value="<#tab>"></td>
        </tr>
        <tr>
            <td width="142">Прізвище</td>
            <td><input type="text" name="fam" size="20" value="<#fam>"></td>
        </tr>
        <tr>
            <td width="142">Ім'я</td>
            <td><input type="text" name="imya" size="20" value="<#imya>"></td>
        </tr>
        <tr>
            <td width="142"> По батькові</td>
            <td><input type="text" name="otch" size="20" value="<#otch>"></td>
        </tr>
        <tr>
            <td width="142">Дата народження</td>
            <td><input type="text" name="datar" size="20" value="<#datar>"></td>
        </tr>
        <tr>
            <td width="142">Середній бал</td>
            <td><input type="text" name="srbal" size="20" value="<#srbal>"></td>
        </tr>
    </table>
    <p><input type="hidden" name="id" size="20" value="<#id>"> </p>
    <p align="left"><input type="submit" value="Зберегти" name="B1">
    <input type="submit" value="Скасувати" name="B2"></p>
    </form>
</body>
</html>
Помістіть створений шаблон у теку з WEB додатком.
 
Як було розглянуто раніше для роботи з такими шаблонами помістіть у вікно модуля компонент DataSetPageProducer (Internet). Задайте властивість HTMLFile=файл створеного шаблону й вилучіть шлях до цього файлу.
Для відображення в полях форми значень поточного запису в події ONHTmltag компонента DataSetPageProducer уведіть код:
 
//кожному полю на формі привласнюємо
//значення одноіменного поля із таблиці
if tagstring='tab' then
    replacetext:=adotable1.fieldbyname('tab').asstring
else if tagstring='fam' then
    replacetext:=adotable1.fieldbyname('fam').asstring
else if tagstring='imya' then
    replacetext:=adotable1.fieldbyname('imya').asstring
else if tagstring='otch' then
    replacetext:=adotable1.fieldbyname('otch').asstring
else if tagstring='datar' then
    replacetext:=adotable1.fieldbyname('datar').asstring
else if tagstring='srbal' then
    replacetext:=adotable1.fieldbyname('srbal').asstring
//прихованому полю на формі привласнюємо
//значення ключового поля із таблиці
else if tagstring='id' then
    replacetext:=adotable1.fieldbyname('tab').asstring;
end;
 
Створення дії для кнопок додавання, редагування й видалення даних
Форма із цими кнопками обробляється дією, у якої PathInfo="/data". Створимо цю дію.
У вікні модуля виконаєте подвійне клацання на порожньому тлі вікна. У списку дій за допомогою кнопки Add New додайте нову дію й задайте властивість PathInfo="/data".
У події OnAction цієї дії введіть код:
 
//якщо натиснута кнопка "Додати"
if request.Contentfields.values['B1']='Додати' then
begin
    //у таблицю БД додаємо новий запис
    adotable1.active:=true;
    adotable1.Append;
    //передаємо в браузер клієнта шаблон форми для редагування даних
    response.Content:=datasetpageproducer1.Content;
    adotable1.active:=false;
end
//якщо натиснута кнопка "Редагувати"
else if request.Contentfields.values['B2']='Редагувати' then
begin
    //стаємо на обраний запис у таблиці
    adotable1.active:=true;
    adotable1.locate('tab',request.Contentfields.values['R1'],[]);
    //передаємо в браузер клієнта шаблон форми для редагування даних
    response.Content:=datasetpageproducer1.Content;
    adotable1.active:=false;
end
//якщо натиснута кнопка "Вилучити"
else if request.Contentfields.values['B3']='Вилучити' then
begin
    //стаємо на обраний запис у таблиці
    adotable1.active:=true;
    adotable1.locate('tab',request.Contentfields.values['R1'],[]);
    //видаляємо запис із таблиці
    adotable1.delete;
    //відкриваємо головну сторінку WEB додатка
    // для перегляду таблиці БД зі змінами
    response.Sendredirect('http://localhost/cgi/primerdb.exe');
    adotable1.active:=false;
end;
 
Створення дії для шаблону форми редагування даних
Форма із цими кнопками обробляється дією, у якої PathInfo="/record". Створимо цю дію.
У вікні модуля виконайте подвійне клацання на порожньому тлі вікна. У списку дій за допомогою кнопки Add New додайте нову дію й задайте властивість Pathinfo="/data".
У події OnAction цієї дії введіть код:
 
//якщо натиснута кнопка "Зберегти"
if request.Contentfields.values['B1']='Зберегти' then
begin
    adotable1.active:=true;
    //якщо приховане поле порожнє (запис новий)
    if request.Contentfields.values['id']='' then
        //додаємо в таблицю новий запис
        adotable1.Append
    //інакше, якщо приховане поле не порожнє (запис, що редагується)
    else
    begin
        //стаємо на запис у таблиці
        adotable1.locate('tab',request.Contentfields.values['id'],[]);
        //переводимо запис у режим редагування
        adotable1.edit;
    end;
    //кожне поле таблиці БД заміняємо на значення полів форми
    adotable1.fieldbyname('tab').asstring:=request.Contentfields.values['tab'];
    adotable1.fieldbyname('fam').asstring:=request.Contentfields.values['fam'];
    adotable1.fieldbyname('imya').asstring:=request.Contentfields.values['imya'];
    adotable1.fieldbyname('otch').asstring:=request.Contentfields.values['otch'];
    adotable1.fieldbyname('datar').asstring:=request.Contentfields.values['datar'];
    adotable1.fieldbyname('srbal').asstring:=request.Contentfields.values['srbal'];
    adotable1.post;
    //відображаємо головну сторінку WEB додатка для перегляду результату
    response.Sendredirect('http://localhost/cgi/primerdb.exe');
    adotable1.active:=false;
end
//якщо натиснута кнопка "Скасувати"
else if request.Contentfields.values['B2']='Скасувати' then
    //повертаємося на головну сторінку WEB додатка
    response.Sendredirect('http://localhost/cgi/primerdb.exe');
 
Відкомпілюйте проект. Скопіюйте оновлений файл primerdb.exe і файл HTML шаблону форми в теку home/localhost/cgi, запустіть Denwer і у вікні браузера введіть адресу:
 
localhost/cgi/primerdb.exe
 
Перевірте роботу всіх кнопок додатка.
 
Питання для самоконтролю
1. Які можливості має Delphi для розробки WEB додатків? Як виконати такий додаток?
2. Опишіть принцип створення WEB додатка в Delphi. Як створити перелік дій?
3. З яких частин складається URL?
4. Як написати оброблювач для дії в WEB додатку? Які параметри має цей оброблювач?
5. Як при описі HTML форми вказати, що вона обробляється дією з WEB додатка Delphi?
6. Як звернутися до полів на HTML формі в коді WEB додатка Delphi?
7. Який компонент дозволяє використовувати в WEB додатках Delphi шаблони HTML файлів?
8. Як за допомогою WEB додатка виконати підстановку в HTML шаблон потрібних значень?
9. За допомогою якого компонента можна відобразити в WEB додатку дані БД у вигляді таблиці? Опишіть властивості цього компонента.
10. Як у таблицю із даними БД додати новий стовпчик і заповнити його потрібними значеннями?
Лекція № 17
Тема: «Створення інсталяційних пакетів»
 
План
1. Загальні відомості
2. Створення інсталяційного пакета
3.Вставка сценаріїв для створення БД
 
1. Загальні відомості
Якщо проект створений, протестований і готів до використання, то його в принципі можна поширювати у вигляді файлу, що виконується, який просто потрібно запустити на машині користувача.
Дуже часто проект складається з більш ніж одного файлу: файл, що виконується, файли бібліотек, файли бази даних, файли допомоги й т.і. Такий проект потрібно поширювати у вигляді теки. Якщо хоча б один з файлів буде вилучений або ушкоджений, то програма може виявитися неробочою. Більше того, такий набір файлів незручно поширювати через інтернет або через пошту.
Навіть, якщо проект поширюється у вигляді теки, то від користувача потрібні знання по копіюванню теки, винесенню ярлика програми на Робочий стіл або в меню кнопки Пуск. Для видалення програми користувач буде змушений вилучити теку із програмою й усі ярлики. На жаль, не всі користувачі можуть виконати подібні операції.
Вирішенням проблеми є створення інсталяційного пакета – архіву з переліком усіх необхідних файлів. При запуску такого пакета відбувається автоматичне копіювання програми в зазначену теку, створення всіх необхідних ярликів і створення інтсрументів для видалення програми.
Створення таких пакетів не викликає особливих труднощів і виконується за допомогою спеціальних програм. Середовище Delphi 7 має такий пакет Install Shield. Однак він є урізаним по функціях і англомовним.
Для зручності роботи, управління всіма параметрами створення інсталяційних пакетів рекомендується використовувати інші програми. Однією з найбільш вдалих програм є IndogoRose Setup Factory.
Програма має простий, але в той же час багатофункціональний русифікований інтерфейс.
 
2. Створення інсталяційного пакета
При запуску програми відкриється вікно, у якому потрібно вибрати режим роботи: створення нового проекту або відкриття існуючого. Якщо ви оберете створення нового проекту, то за допомогою прапорця можна вказати, що необхідно запустити майстер створення пакета. Майстер дозволяє в простому режимі задати потрібні параметри проекту.
 
Кроки майстра
 
На першому кроці вказується інформація про програму і її автора (назва продукту, компанії, номер версії і сайт автора).
 

 
На другому кроці вказується тека, у якій знаходиться ваш готовий проект. Рекомендується, щоб у цій теці перебували тільки файли, потрібні для роботи програми.
 

 
На третьому кроці вибирається стиль вікна установки.
 

 
На четвертому кроці вибирається тема оформлення вікон проекту.
 

 
На п'ятому кроці вибираються мови, на яких можна виконати операцію інсталяції програми.
 

 
На шостому кроці потрібно відзначити бібліотеки, необхідні для роботи програми. Дані бібліотеки потрібні для роботи програм, написаних на Visual Basic або Visual C++. Якщо програма написана на Delphi, то нічого відзначати не потрібно.
 

 
На сьомому кроці відзначають операційні системи, під якими буде працювати ваша програма.
 

 
Робота з файлами
 
Після створення проекту за допомогою майстра потрібно настроїти низку параметрів. Усі параметри зібрані по групах. Назви груп і їх команди відображаються в лівій частині вікна програми.
Перша група Файли дозволяє додати файл у проект, якщо він був відсутній у теці при запуску майстра; вилучити файл із проекту, якщо в папці перебував файл, який не потрібний для роботи готової програми.
 

 
Найголовніша команда – Редагувати властивості файлу. Цю команду потрібно послідовно викликати для кожного файлу й задати низку властивостей: на закладці Ярлики за допомогою прапорців укажіть, де буде створений ярлик для файлу (якщо ярлик не потрібний, то всі прапорці зніміть), у полі Опис уведіть назву ярлика, під яким ярлик з'явиться в зазначеному вами місці; у групі Значок за допомогою перемикача Настроїти можна вказати файл іконки, яка буде привласнена створеному ярлику (якщо параметр не заданий, то відображається значок файлу, що виконується).
 
Зміна настроювань проекту
 
У групі Настроювання перебувають команди для виконання таких операцій:
Змінні сесії – дозволяє задати значення для всіх змінних проекту (інформація про продукт і автора, шлях установки й т.п.);
Фон вікна – дозволяє задати фон вікна інсталяції, задати заголовки вікон майстра установки;
Системні вимоги – дозволяє задати список припустимих операційних систем, а також вимоги до апаратної частини комп'ютера користувача. На закладці Додатково можна вказати режим «прихованої» установки, задати іконку для майбутнього файлу інсталяції
Безпека – дозволяє ввести перелік серійних номерів для установки пакета, а також обмеження на використання пакета за часом або кількості запусків програми.
Мови – дозволяє додати або вилучити мови пакета інсталяції.

 
Робота з екранами
Група Екрани містить такі команди:
Теми проекту – дозволяє вибрати тему оформлення майстра інсталяції. За допомогою кнопки Виправлення можна змінити параметри теми.
Перед інсталяцією – дозволяє настроїти параметри всіх вікон майстра, які відображаються до початку установки програми. У списку вікон за допомогою кнопок зі стрілками можна змінити їхній порядок, за допомогою кнопки Вилучити можна деякі вікна прибрати з майстра, за допомогою кнопки Виправлення можна задати настроювання вікон. Особлива увагу приділіть вікну з ліцензійною угодою. У цьому вікні потрібно або ввести текст угоди, або завантажити текстовий файл, але в цьому випадку файл повинен бути включений у папку проекту.
Під час інсталяції – настроюється вікно відображення процесу копіювання програми на комп'ютер користувача.
Після інсталяції – задаються параметри вікна, відображуваного по закінченню процесу установки програми.

 
Створення деінсталлятора
 
У групі Деінсталяція перебувають команди для завдання параметрів видалення проекту з комп'ютера користувача. Група має такі команди:
Настроювання – за допомогою прапорця відзначається необхідність створення деінсталлятора. Без цього прапорця всі інші параметри не мають сенсу.
Фон – задаються параметри фона вікна деінсталяції й текст написів у вікні.
Панель керування – за допомогою прапорця вказується необхідність поміщати програму в список Установка й видалення програм панелі керування. У полі Режим значка можна вказати ярлик для цієї програми в такому списку.
Ярлик – у полі Опис можна ввести ім'я, під яким деінсталлятор з'явиться в меню кнопки Пуск і інших зазначених у проекті місцях, у групі Значок можна вказати файл іконки для ярлика деінсталлятора.
Екрани – можна настроїти параметри вікон майстра деінсталяції. Особливо зверніть увагу на екран After Install, на якому некоректно відображається російський текст, і його потрібно підправити.

 
Збирання пакета
 
Після завдання всіх параметрів збережіть проект і натисніть на кнопку Зібрати на панелі інструментів  INCLUDEPICTURE "http://rpo.16mb.com/delphi/lekcii/lekc15_12.jpg" \* MERGEFORMATINET  або виконайте команду Видання - Збирання. Запуститься майстер. На першому кроці вкажіть розмір файлу, на який буде розбитий ваш настановний пакет, на другому кроці вкажіть папку й ім'я майбутнього інсталяційного файлу.
По завершенню процесу збирання ви отримаєте інсталяційний файл для вашого проекту.
 
3.Вставка сценаріїв для створення БД
Якщо ваш проект використовує клієнт/серверну базу даних, то її неможливо просто помістити в теку із проектом для інсталяції. Така база даних знаходиться на сервері в спеціальному форматі й встановити її на сервер можна тільки за допомогою спеціальних команд, записаних у файл скриптів.
 
Створення скриптового файлу БД MySQL
 
Для створення скриптового файлу можна скористатися програмою SQL Manager for MySQL. В лівій частині оберіть потрібну базу даних і виконайте команду Інструменти - Витягання бази даних.
У вікні майстра на першому кроці оберіть БД для витягнення і встановіть прапорець.
 

 
На наступному кроці вкажіть шлях та ім'я файлу для експорту БД.
 

 
На наступному кроці встановіть всі прапорці. В результаті буде створений скриптовий файл БД.
 

 
Створення скриптового файлу БД SQL Server
 
У вікні утиліти "SQL Server Management Studio" клацніть правою кнопкою миші на потрібній БД і оберіть команду "Задачи - Сформировать сценарии". З'явиться вікно майстра створення скрипта.
На першому кроці оберіть перемикач "Внести в сценарий всю базу данных и все объекты базы данных" для переноса всех элементов БД.
На наступному кроці вкажіть шлях та ім'я для файлу скрипта. ОБов'язково клацніть на кнопці "Дополнительно" для задавання додаткових параметрів. К таким параметрам відносяться версія SQL Server та типи даних. За замовченням параметр "Типи даних" має значення "Тільки схема". Це означає, що до скрипта переносяться пусті таблиці без даних. Для переносу даних оберіть значення "Схема і дані".
 

 
Після задавання всіх параметрів клацніть на кнопці "Далее" и "Готово".
 
Використання скриптового файлу для встановлення БД MySQL
 
 Якщо у вас створений скриптовый файл MySQL, то виконати його можна за допомогою команди виду:
 
mysql.exe –h ім'я_сервера –u ім'я_користувача –pпароль < ім'я_скриптового файлу
 
Наприклад, якщо файл скрипта має ім'я test.sql, то команда може мати вигляд:
 
mysql.exe –h localhost –u root –p111 < test.sql
 
У цьому випадку установка виконується на локальний комп'ютер (localhost) під логіном root і паролем 111.
 
Зверніть увагу, що в команді присутня виклик програми mysql.exe. Дана програма повинна знаходитися в одній теці із файлом скрипта. Якщо на машині встановлена СУБД MySQL, то цей файл можна скопіювати із теки c:\program files\mysql\bin.
 
В реальних умовах ім'я сервера, логін або пароль можуть бути різними, тому ця команда повинна виконуватися з параметрами, через які будуть передаватися реєстраційні дані. Для вирішення цієї задачі треба створити *.bat файл для виконання експорту скриптового файлу. Цей файл може мати наступний код:
 
cls
@echo off
mysql -h %1 -u %2 -p%3 < test.sql
if %errorlevel% == 0 goto m1
echo БД не установлена.
echo Проверьте параметры регистрации и наличие работающего сервера MySQL.
pause
goto end
:m1
echo БД установлена успешно.
pause
:end
 
Зауваження. Переконайтеся, що *.bat файл має кодування MS_DOS.
 
Використання скриптового файлу для встановлення БД SQL Server
 
 Якщо у вас створений скриптовый файл SQL Server, то виконати його можна за допомогою команди виду:
 
sqlcmd.exe -S ім'я_сервера -U ім'я_користувача -P пароль -i ім'я_скриптового файлу
 
Наприклад, якщо файл скрипта має ім'я test.sql, то команда може мати вигляд:
 
sqlcmd.exe –h pc01202 –u sa –p111 -i test.sql
 
У цьому випадку установка виконується на комп'ютер  pc01202 під логіном sa і паролем 111.
 
Зверніть увагу, що в команді присутня виклик програми sqlcmd.exe. Дана програма повинна знаходитися в одній теці із файлом скрипта і не може працювати без файлу sqlcmd.rll(який теж треба скопіювати у теку з файлом скрипта). Якщо на машині встановлена СУБД SQL Server, то ці файл можна скопіювати із теки c:\program_files\microsft sql server\tools\binn
 
В реальних умовах ім'я сервера, логін або пароль можуть бути різними, тому ця команда повинна виконуватися з параметрами, через які будуть передаватися реєстраційні дані. Для вирішення цієї задачі треба створити *.bat файл для виконання експорту скриптового файлу. Цей файл може мати наступний код:
 
cls
@echo off
sqlcmd -h %1 -u %2 -p %3 -i test.sql
if %errorlevel% == 0 goto m1
echo БД не установлена.
echo Проверьте параметры регистрации и наличие работающего сервера SQL Server.
pause
goto end
:m1
echo БД установлена успешно.
pause
:end
 
Зауваження. Переконайтеся, що *.bat файл має кодування MS_DOS.
 
 
Підготовка БД до інсталіцїї
Для коректної інсталяції БД MySQL рекомендується у теці із проектом створити нову теку, в якій розмістити: скриптовий файл БД, файл mysql.exe, створений *.bat файл для встановлення БД на сервер.
Для інсталяції БД SQL Server аналогічно у теці із проектом створити нову теку, в якій розмістити: скриптовий файл БД, файли sqlcmd.exe та sqlcmd.rll, а також створений *.batфайл для встановлення БД на сервер.
Додайте всі ці файли в проект за допомогою команди Додати файли із групи Файли.
 
Приклад. Нехай у теці із проектом є вкладена тека Baza, у якій знаходяться файли mysql.exe, baza.sql (файл скрипта) і baza.bat (файл для запуску файлу скрипта на виконання).
Необхідно, щоб після установки програми автоматично виконався даний скрипт, а потім папка Baza видалилася з диска.
Зпочатку у групі Файли клацніть команду Додати файли і вкажіть всі файли із теки Baza. перевірте, щоб для жодного з цих файлів не створювалися ярлики запуску.
 
Створення екрану введення реєстраційних даних
Встановлення БД треба виконувати після встановлення основної програми. При цьому перед встановленням необхідно вказати реєєстраційні дані: сервер, логін та пароль. Введення таких даних будемо здійснювати за допомогою допоміжного екрану
У групі Екрани клацніть на команді Після інсталяції. Клацніть на кнопці Додати і вкажіть тип екрану Custom.
 

 
За допомогою кнопок зі стрілками перемістіть створену форму першою у списку.
За допомогою кнопки Правка розкрийте створену форми і за допомогою кнопки Вставка додайте на форму текстові поля, написи та кнопки.
 

 
Подвійним клацанням на текстових полях відкрийте вікно властивостей, у якому вкажіть ім'я поля для звертання до нього в проекті та текст за замовченням.  Наприклад, дамо такі імена:%user%, %password%, %server%.
 

 
Значення за замовченням для цих полів: root, 111, localhost.
Розмістіть створені компоненти так, як показано на малюнку.
 

 
Створення коду для встановлення БД
Для введення коду екрану перейдіть на закладку Дії, а потім на закладку On Ctrl Messages. Ця закладка містить код для обробки подій від двох кнопок. Наш екран теж має дві кнопки, тому треба лише ввести потрібні команді у відповідні гілки оператора if.
Для введення потрібної дії можна скористатися майстром, який викликається кнопкою Додати дію.
Для встановлення БД (код першої кнопки) видаліть весь код у першій гілці оператора if, клацніть на кнопці Додати дію. У вікні виберіть команду File.Run.
 

 
У наступному вікні у полі FileName укажіть *.bat файл для запуску. У полі Args вкажіть список аргументів у вигляді: SessionVar.Expand("%server% %user% %password%"). У полі WorkingFolder вкажіть ім'я теки, з якої запускається *.bat файл. У списку WaitForReturn оберіть значення true. Це означає, що інсталяція не буде продовжуватися поки не закінчиться робота *.bat файлу.
 

 
Після клацання на кнопці Готово в коді з'явится команда:
 
result = File.Run(SessionVar.Expand("%AppFolder%\\Baza\\backup.bat"), SessionVar.Expand("%server% %user% %password%"), "%AppFolder%\\Baza", SW_SHOWNORMAL, true);
 
Видалення теки в параметрами встановлення БД
Після встановлення БД та ODBC драйверу потрібно видалити теку Baza, в якій знаходяться файли, необхідні для встановлення БД.
Для цього перейдіть на закладку OnNext. на закладці буде команда переходу на наступний екран інсталятора. Установіть курсор перед цією командою і клацніть на кнопці Додати дію. У вікні виберіть команду Folder.DeleteTree.
 

 
У наступному вікні у полі вкажіть шлях до теки Baza: "%AppFolder%\\Baza"
 

 
Після клацання на кнопці Готово в коді з'явится команда:
 
Folder.DeleteTree("%AppFolder%\\Baza", nil);
 
 
Після введення всіх параметрів виконайте збирання проекта і запустіть створений інсталятор для перевірки його роботи.
Зауваження: для встановлення БД необхідно, щоби у користувача вже був попередньо встановлений і запущений сервер MySQL.
 
Питання для самоконтролю
1. У чому переваги використання інсталяторів для поширення програми серед користувачів.
2. Опишіть всі кроки майстра створення проекту інсталяції в програмі Setup factory.
3. Опишіть основні операції із файлами проекту у програмі Setup factory.
4. Опишіть основні настроювання проекту у програмі Setup Factory.
5. Як виконати настроювання деінсталятора в проекті програми Setup Factory?
6. Як створити скриптовий файлБД MySQL?
7. Як встановити БД MySQL на сервер за допомогою скриптового файлу?
8. Як додати в проект програми Setup Factory новий екран і нанести на нього компоненти?
9. Як у проекті програми Setup Factory створити код для компонентів на формі?
10. Як створити Збирання проекту програми Setup Factory в файл інсталяції?

Практичне заняття № 1 
 
ТЕМА: Розрахунки виразів на Delphi
ЦІЛЬ РОБОТИ: отримати практичні навички по використанню стандартних функцій Object Pascal при рішенні задач
 
Хід роботи
 
1. Скласти програму для знаходження значення складних арифметичних функцій. При цьому оформити програму в такий спосіб:
 
 
 
Вікно програми повинне запускатися по центру екрана, виключити можливість зміни розміру вікна й прибрати кнопку для розгортання вікна на весь екран. Назва програми "Розрахунки функції". Для програми задайте довільний значок-іконку;
 
2. У вікні розмістіть три текстові поля для введення вихідних даних і одне поле для відображення результату. Кожне поле повинне мати різний колір фона, спливаючу підказку. Вирівнювання в полях, шрифт, розмір і накреслення символів довільне. У полі для відповіді відключити можливість його редагування із клавіатури. Для кожного поля за допомогою написів присвойте гарячі клавіші;
 
3 Розмістіть на формі кнопку для виконання розрахунків. Кнопка повинна мати малюнок і реакцію на натискання ENTER або пробіл. При наведенні покажчика миші на кнопку, вид покажчика повинен мінятися на заданий; 
 
4 Розмістіть на формі кнопку для очистки усіх текстових полів. Кнопка повинна мати малюнок і реакцію на натискання ESCAPE. При наведенні покажчика миші на кнопку, вид покажчика повинен мінятися на заданий. При цьому повинне запитуватися дозвіл на виконання операції. Якщо дозвіл отриманий (відповідь "Так"), то всі поля очищаються. А якщо ні, то нічого не відбувається;        
 
5. Функція для розрахунків має вигляд:
 
 
 
При цьому повинне запитуватися дозвіл на виконання обчислень. Якщо дозвіл отриманий (відповідь "Так"), то запитується із клавіатури значення четвертої змінної d і обчислюється значення функції. Перевірка: при a=1, b=8, c=3, d=2 відповідь=2,644;
 
6. При виході із програми запитувати дозвіл на виконання даної операції;
 
Виконання роботи
 
1. Для форми задайте наступні властивості: Borderstyle=bssingle (вікно не розтягується), Bordericons - Bimaximize=false (немає кнопки розгортання вікна), Caption=Розрахунки функції (заголовок форми), Icon=укажіть файл іконки (значок форми), Position=podesktopcenter;
 
2. На формі розмістіть три текстові поля, для яких установіть наступні властивості: Text очистити (початкове значення поля), Color=укажіть колір (колір фона), Alignment = на вибір, Font=параметри шрифту в полі, Hint = текст спливаючої підказки, Showhint=true (відображення спливаючої підказки). У полі Edit4 установіть властивість Enabled=false (блокування доступу до поля на формі). Біля кожного з полів розмістіть мітку й у властивості Caption уведіть текст для підписування кожного поля, при цьому перед потрібною буквою в напису введіть  символ &. Для прив'язки напису до поля у властивості напису Focuscontrol укажіть ім'я поля, до якого прив’язується напис;
 
3. На формі розмістіть кнопку Bitbutton, задавши їй наступні властивості: Kind=bkyes (заготовка з малюнком), Default=true (реакція кнопки на клавішу Enter); Caption=Розрахунки (напис на кнопці), Cursor=будь-який вид покажчика миші при наведенні на кнопку, name=Bitbtn1;
 
4. На формі розмістіть кнопку Bitbutton, задавши їй наступні властивості: Kind=bkno (заготовка з малюнком), Cancel=true (реакція кнопки на клавішу Enter); Caption=Розрахунки (напис на кнопці), курсор=будь-який вид покажчика миші при наведенні на кнопку, name=Bitbtn2;
Для події Click даної кнопки напишемо код:
 
procedure tform1.bitbtn2click(sender: tobject);
begin
//видаємо запит на очищення полів
if application.messagebox('Ви підтверджуєте очищення всіх полів?', 'Підтвердьте операцію', mb_yesno+mb_iconquestion+mb_defbutton2)=idyes then
begin
//якщо користувач відповів так, то очищаємо поля
edit1.text:='';
edit2.text:='';
edit3.text:='';
edit4.text:='';
//установлюємо курсор у перше поле
edit1.setfocus;
end;
end;
 
5. Для події Click кнопки Bitbtn1 напишемо код:
 
procedure tform1.bitbtn1click(sender: tobject);
//описуємо змінні для розрахунків
var a,b,c,d,e:real;
begin
//видаємо запит на виконання розрахунків
if application.messagebox('Ви підтверджуєте розрахунки функції?',''Підтвердьте операцію', mb_yesno+mb_iconquestion+mb_defbutton2)=idyes then
begin
//якщо користувач відповів так, то рахуємо
//конвертуємо текстові поля в числа й записуємо в змінні
a:=strtofloat(edit1.text);
b:=strtofloat(edit2.text);
c:=strtofloat (edit3.text);
// уводимо четверту змінну із клавіатури
// і перетворюємо введене значення в число
d:=strtofloat(inputbox('Уведіть четверте значення для розрахунків','Вікно введення','1'));
//виконуємо розрахунок функції
e:= (7+exp(sqrt(a)+1))/(sqrt(power(ln(power(b,2)-5),3)-4)+ sin(power(c,2)))+power(sin(d),(3/4));
//виводимо відповідь у текстове поле на формі
// при цьому функція roundto округляє відповідь до трьох знаків
//цифра з мінусом указує на те, що округлення виконується до 3знаків
//після коми
edit4.text:=floattostr(roundto(e,-3));
end;
end;
 
6. Для обробки виходу із програми виділіть форму, у вікні завдання властивостей перейдіть на вкладку Events, знайдіть подію Onclosequery і в у правому стовпці потрібної події клацніть два рази. З'явиться процедура події, у якій напишіть код виду:
 
procedure tform1.formclosequery(sender: tobject; var canclose: boolean);
begin
//видаємо запит на вихід із програми
if application.messagebox('Вийти із програми?','Вихід',mb_yesno+mb_iconquestion+mb_defbutton2)=idno then
//якщо користувач відповів ні, то вікно програми не закривається
canclose:=false;
end;
Практичне заняття № 2 
ТЕМА: Створення програм з варіантами
ЦІЛЬ РОБОТИ: отримати практичні навички по використанню прапорців, перемикачів, смуг прокручування, списків у програмах на Delphi 
 
Хід роботи
 
1. Створити форму вигляду:
 

 
Форма повинна запускатися по центру екрана, мати фіксовані границі, кнопку розкриття на весь екран відключити;
 
2. На формі створити дві закладки;
 
3. На першій закладці створити лічильник для введення першого числа й список для вибору другого числа;
 
4. Під списком створити панель  із компонентами для редагування списку. У полі можна ввести число й додати його в список за допомогою кнопки "+". За допомогою кнопки "-" можна вилучити зі списку обраний рядок;
 
5. За допомогою компонента Radiogroup створіть перемикачі для вибору типу розрахунків;
 
6. Під перемикачами створіть панель, а на ній два прапорці для вибору виду видачі результату;
 
7. Під панеллю створіть кнопку для виконання розрахунків і кнопку для виходу із програми;
 
8. На другій закладці розмістіть панель, а на ній два прапорці для настроювання параметрів програми:
 

 
9. Перший прапорець блокує або розблокує текстове поле лічильника для введення даних із клавіатури;
 
10. Другий прапорець ховає або відображає панель із компонентами для редагування списку;
 
Виконання роботи
 
1. Для форми задайте властивості: Borderstyle=bssingle; Bordericon-bimaximize=false; Caption=Створення програм з варіантами; Icon=довільну іконку; Name=Form1;
 
2. Для створення закладок виберіть компонент Pagecontrol (Win32) і нанесіть його на форму. У контекстному меню компонента виберіть команду New Page для створення двох закладок. Для кожної закладки у властивості Caption  уведіть назви "Основна" і "Параметри";
 
3. Для створення лічильника у текстового поля установіть властивості: Readonly = True (заборонимо користувачеві вводити текст із клавіатури); Text=1; Name= Edit1. На вкладці Win32 виберіть елемент Updown  і задайте йому властивості: Associate=Edit1; Min=1; Position=1;
4. Для введення другого числа на формі створіть список за допомогою елемента Listbox (Standard) і задайте йому властивості: Name=Listbox1; Items=уведіть перелік значень списку. При старті програми необхідно, що перший рядок у списку була обраний. Для цього в події Oncreate форми напишіть код:
 
procedure tform1.formcreate(sender: tobject);
begin
listbox1.itemindex:=0;
end;
 
 5. Для редагування списку на формі розмістіть компонент Groupbox (Standard). Для додавання нового значення в список на формі розмістіть текстове поле із властивостями: Name=Edit2; Text очистити. Під полем розмістіть кнопку із властивостями Caption="+"; Name=Button1. Клацніть на кнопці два рази й напишіть код:
 
procedure tform1.button1click(sender: tobject);
begin
//перевіряємо, чи є в полі значення для додавання
if edit2.text<>'' then
//якщо значення є, те додаємо
listbox1.items.add(edit2.text)
//якщо значення ні, то видаємо повідомлення
else
application.messagebox('Немає даних для додавання','Операція перервана',mb_ok+mb_iconstop);
end;
 
6. Для видалення значення зі списку на формі створіть кнопку із властивостями Caption="-"; Name=Button2. Клацніть на кнопці два рази й напишіть код:
 
procedure tform1.button2click(sender: tobject);
begin
//перевіряємо, чи є в списку обраний рядок для видалення
if listbox1.itemindex<>-1 then
//якщо є, то видаємо запит на видалення
begin
if application.messagebox('Вилучити значення?','Видалення',mb_yesno+mb_iconquestion+mb_defbutton2)=idyes then
begin               
//якщо користувач відповів так, то видаляємо обраний рядок
listbox1.items.delete(listbox1.itemindex);
//установлюємо курсор на перший рядок списку
listbox1.itemindex:=0;
end
end
else
//якщо в списку немає обраних рядків, то видаємо повідомлення
application.messagebox('Не обраний рядок для видалення','Операція перервана',mb_ok+mb_iconstop);
end;
 
7. Для створення групи перемикачів скористайтеся елементом Radiogroup на вкладці Standard, для якого задайте властивості: Caption=Вид розрахунків; Items=Сума, різниця, добуток, частка; Itemindex=0 (завдання першого перемикача як включеного за замовчуванням);
 
8. Для створення групи прапорців розмістіть на формі елемент Groupbox із властивістю Caption=Вид виводу. На цьому елементі створіть два компоненти Checkbox, для яких задайте властивості: Name=Checkbox1 і Checkbox2; для компонента Checkbox1 задайте властивість Checked=True (прапорець включений за замовчуванням);
 
9. Для виводу відповіді в новому вікні створимо нову форму за допомогою команди Файл-Створити-Форма. Для форми задамо властивості: Borderstyle=bssingle; Bordericon-bimaximize=false; Caption=Результат розрахунків; Icon=довільну іконку; Name=Form2; Height=75; width=300. На формі розмістіть елемент Label (Standard) із властивостями: Caption=Порожній символ; Aligmnent=tacenter; Font=параметри шрифту. Для підключення створеної форми до головної форми перейдіть на головну форму, виконайте команду File - Use Unit і в списку виберіть модуль Unit2.
 
10. Для виконання розрахунків на головній формі створіть кнопку із властивостями: Caption=Розрахунок; Name=Button3. Клацніть на кнопці два рази й напишіть код:
 
procedure tform1.button3click(sender: tobject);
//описуємо змінні для розрахунків
var a,b,c:real;
begin
//конвертуємо значення лічильника в змінну а
a:=updown1.position;
//конвертуємо значення зі списку в число  й записуємо в змінну b
b:=strtofloat(listbox1.items.strings[listbox1.itemindex]);
// в залежності від обраного перемикача рахуємо значення
case radiogroup1.itemindex of
0: c:=a+b;
1: c:=a-b;
2: c:=a*b;
3: c:=a/b
end;
//в залежності від обраного прапорця видаємо результат
//якщо включений перший прапорець, але виключений другий
if (checkbox1.checked=true) and (checkbox2.checked=false) then
//видаємо відповідь повідомленням
showmessage ('відповідь: '+floattostr(c))
//якщо включений другий прапорець, але виключений перший
else if (checkbox2.checked=true) and (checkbox1.checked=false) then
//видаємо відповідь у новому вікні
begin
form2.label1.caption:='Відповідь: '+floattostr(c);
form2.showmodal;
end
//якщо включені обидва прапорця
else if (checkbox1.checked=true) and (checkbox2.checked=true) then
begin
//видаємо відповідь повідомленням
showmessage ('відповідь: '+floattostr(c));
// і в новому вікні
form2.label1.caption:='Відповідь: '+floattostr(c);
form2.showmodal;
end
//якщо не включено жодного прапорця
else if (checkbox1.checked=false) and (checkbox2.checked=false) then
//видаємо повідомлення про помилку
application.messagebox('Не обраний тип висновку','Операція перервана',mb_ok+mb_iconstop);
end;
 
11. Для виходу із програми створіть на формі кнопку із властивостями: Caption=Очистити; Name=Button4. Клацніть на кнопці два рази й напишіть код:
 
procedure tform1.button4click(sender: tobject);
begin
//завершуємо роботу із програмою
close;
end;
 
12. Для обробки виходу із програми виділіть головну форму, у вікні властивостей перейдіть на вкладку Events й клацніть два рази в рядку Onclosequery. Напишіть код:
 
procedure tform1.formclosequery(sender: tobject; var canclose: boolean);
begin
//видаємо запит на вихід із програми
if application.messagebox('Вийти із програми?','Вихід',mb_yesno+mb_iconquestion+mb_defbutton2)=idno then
//якщо користувач відповів ні, то не виходимо
canclose:=false;
end;
 
13. На другій закладці розмістіть панель Groupbox (Standard), а на панелі два прапорці для настроювання параметрів програми.
 
14. Для першого прапорця задайте властивості: Caption=Редагувати лічильник, Name=Checkbox3. Для прапорця в події Onclick уведіть код:
 
procedure tform1.checkbox3click(sender: tobject);
begin
//якщо прапорець включений
if checkbox3.checked=true then
begin
//розблокуємо поле лічильника
edit1.readonly:=false;
//переходимо на першу закладку
pagecontrol1.pages[0].show;
//ставимо курсор у поле лічильника
edit1.setfocus;
end
//якщо прапорець виключений
else
begin
//блокуємо поле лічильника
edit1.readonly:=true;
//переходимо на першу закладку
pagecontrol1.pages[0].show;
//ставимо курсор у поле лічильника
edit1.setfocus;
end
end;
 
15. Для другого прапорця задайте властивості: Caption=Редагувати список, Name=Checkbox4. Для прапорця в події Onclick уведіть код:
 
procedure tform1.checkbox4click(sender: tobject);
begin
//якщо прапорець включений
if checkbox4.checked=true then
begin
//відображаємо панель для редагування списку
groupbox1.visible:=true;
//переходимо на першу закладку
pagecontrol1.pages[0].show;
end
//якщо прапорець виключений
else
begin
//приховуємо панель для редагування списку
groupbox1.visible:=false;
//переходимо на першу закладку
pagecontrol1.pages[0].show;
end;
end;
Практичне заняття № 3
ТЕМА: Створення найпростішого текстового редактора
ЦІЛЬ РОБОТИ: отримати практичні навички по роботі з компонентами Edit, Memo, по масштабуванню компонентів, по роботі з компонентом Fontdialog
 
Хід роботи
 
1. Створити програму, яка:
1.1 При завантаженні видає вікно введення пароля:
 

 
Пароль розбивається на чотири частини по 5 символів. У кожному полі передбачити автоматичний перехід у наступне поле при введенні 5 символів у поточному полі. У випадку невірного введення програма повинна видати повідомлення про помилку й пропонує ввести пароль знову (переходить у перше текстове поле). У випадку трьох невірних спроб кнопка ОК блокується й запуск програми стає неможливим;
 
1.2 При вірному уведенні пароля на екрані з'являється вікно редактора, що складається з багаторядкового текстового поля й кнопок.
 

 
За допомогою кнопки Формат повинен відкриватися діалог форматування символів. Сам діалог повинен містити кнопку Застосувати. За допомогою кнопки Колір повинен відкриватися діалог для вибору кольору фона компонента Memo. Кнопки Зберегти й Відкрити запитують уведення із клавіатури  імені файлу й зберігають вміст поля у файл або завантажують вміст файлу в поле. Передбачити перевірку наявності файлу на диску.
      
1.3. Для вікна редактора передбачити можливість масштабування елементів на формі: при розтягуванні вікна текстове поле повинне розтягуватися пропорційно вікну, а кнопки повинні залишатися внизу. Вікно не може зменшуватися менше його початкового розміру;
 
1.4 При закритті вікна редактора необхідно проаналізувати, чи змінювався текст. Якщо так, то видати повідомлення, якщо ні, то також видати повідомлення;
 
Виконання роботи
 
1. Для першої форми задайте властивості: Caption=Реєстрація; Borderstyle=bsdialog; Position=podesktopcenter. На формі розмістіть п'ять текстових полів Edit, для яких задайте властивості: Maxlength=5 (довжина в 5 символів), Passwordchar=* (символ для заміни тексту на екрані), Text очистити.
 
2. Для автоматичного переходу курсору між полями при введенні пароля в події Change кожного поля введемо код:
 

 
 
3. Додамо на форму кнопку із властивостями: Default=True; Caption=OK
Для підрахунку кількості спроб уведення пароля необхідно описати глобальну змінну K у розділі Interface. Для цього послові слова Var вставимо рядок виду:
 

 
4. Для кнопки напишемо код:
 

 
5. Додамо в проект нову форму й задамо їй властивість Caption=Редактор, Width=700, Height=470. Щоб форма не зменшувалася менше початкового розміру установіть властивості форми: Constraints - Minwidth = 700, Constraints - Minheight = 470.
На формі розмістіть компонент Memo, розташований на вкладці Standard. Для масштабування компонента на формі у властивості Anchors установіть всі параметри в True. На формі розмістіть кнопки як показано на малюнку. Для масштабування кнопок у їхній властивості Anchors установіть параметр akbuttom=true, інші параметри установіть в false;
 
6. На формі розмістіть компонент Fontdialog, розташований на вкладці Dialogs. У властивості Options установіть параметр fdapplybutton=true для відображення кнопки Застосувати.
Для форматування тексту для кнопки "Формат" напишемо код:
 

  
Для роботи кнопки Застосувати виділіть на формі компонентів Fontdialog, у вікні завдання властивостей перейдіть на вкладку Events, клацніть два рази в рядку Onapply і введіть код:
 
 
 
7. На формі розмістіть компонент Colordialog, розташований на вкладці Dialogs.
Для зміни кольору фона поля Memo для кнопки "Колір" напишемо код:
 

 
8. Для збереження вмісту поля у файл опишіть у розділі interface модуля глобальну змінну строкового типу:
 

 
При створенні форми необхідно цієї змінній привласнити деяке початкове значення:
 

 
Для кнопки Зберегти напишемо код:
 

 
9. Для кнопки Відкрити напишемо код:
 

 
10. При закритті форми редактора потрібно закрити головне вікно програми (вікно введення пароля) і перевірити, чи змінювався вміст тексту в редакторі. Для цього виділіть форму, у вікні завдання властивостей перейдіть на вкладку Events, клацніть два рази в рядку Onclose і введіть код:
 

Практичне заняття № 4
Тема: Робота із файлами в Delphi
Ціль роботи: отримати практичні навички по обробці файлів і використанню компонентів для роботи із файлами
 
Хід роботи
 
Задача № 1
1. Создайте форму вида:

 
Вказівки: Для форми задайте властивості: BorderStyle=bsSingle, BorderIcons - Maximized = false, Caption = оБРАБОТКА ФАЙЛОВ, Position= poDesktopCenter.
Нанесіть на форму 4 компоненти Label для відображення написів на Формі. Для четвертого напису (на рисунку він червоний) задайте властивості: Caption -очистити, Alignment = alCenter, Font = червоний.
Для задавання імен файлів нанесіть на форму 2 поля Edit і розмістіть їх під 2 і 3 написами.
Для відображення вмісту файлів нанесіть на форму 3 компоненти Memo і задайте властивості: Lines - очистити, ReadOnly = true.
Додайте на форму 2 кнопки button. Для кнопок задайте властивість Caption. Для 2 кнопки задайте властивість Enabled = false.
 
Кнопка "Завантажити файл" виводить діалог вибору текстового файлу. Після вибору вміст файла загружається в ліве текстове поле.
 
Вказівки: нанесіть на форму компонент OpenDialog (Dialogs) і задайте властивість Filter = Текстовые файлы|*.txt
 
В коді опишемо глобальнe змінну. Вона буде зберігати ім'я вихідного файлу із діалогу.
 
f:string;
 
В події OnClick кнопки введіть код:
 
procedure TForm1.Button1Click(Sender: TObject);
begin
    //якщо файл не обраний, то підпрограмма завершує свою роботу   
    if not (opendialog1.execute) then exit;
 
    //записуємо у глобальну змінну ім'я обраного файлу   
    f := openDialog1.FileName;
    //у ліве багаторядкове поле загружаємо вміст обраного фалу   
    memo1.lines.loadfromfile(f);
    //у напису вверху форми відображаємо ім'я файлу (без повного шляху)
    label4.Caption := extractfilename(f);
    //розблоковуємо другу кнопку   
    button2.Enabled := true;
end;
 
Для перевірки роботи функції підготуйте текстовий файл, в який введіть на різних рядках довільні  позитивні, нульові та негативні числа.
 
Кнопка "Опрацювати файл" дозволяє обробити вміст вихідного текстового файлу за алгоритмом: позитивні і нульові елементи записуються до першого файлу, негативні - до другого. Імена файлів вказуються у полях над багаторядковими полями. Самі файли зберігаються в теку з програмою.
 
Вказівки: для 2 кнопки у події OnClick напишемо код:
 
procedure TForm1.Button2Click(Sender: TObject);
var   
    //описуємо екземпляри класу для зчитування вихідного файлу 
    //і створення двох нових        
     f1,f2,f3: TStringList;
    //описуємо змінну для лічильника циклу
    i:integer;
begin
    //якщо не заповнені поля 1 або 2 (імена нових файлів)
    if (edit1.Text = '') or (edit2.Text ='') then
    begin
        //видаємо повідомлення про помилку
        //функція срк(13) використовується для перенесення тексту повідомлення
        //на новий рядок
        Application.MessageBox(pchar('Недостаточно введенной информации.'+chr(13)+'Укажите в полях имена файлов."),
                        'Ошибка ввода',
                        mb_ok+mb_iconerror);
        //ставимо курсор в поле з ім'ям першого файлу
        edit1.SetFocus;
        //підпрограма завершує роботу
        exit;
    end;          
    //змінна f1 створюється у пам'яті і зв'язується з вихідним файлом
    f1:=TStringList.Create;
    f1.LoadFromFile(file);
   
    //змінні f2, f3 створюються у пам'яті для обробки вихідного файлу
    f2:=TStringList.Create;
    f3:=TStringList.Create;
 
    //організуємо цикл до кінця вихідного файлу
    //змінна sr пов'язана з вихідним файлом
    for i:=0 to f1.Count-1 do
    begin
        //якщо число у i-му рядку файла позитивне
        if strtofloat(f1.strings[i])>0 then
            //воно записується у перший вихідний файл
            f2.add(f1.strings[i])
        //інакше, якщо число негативне
        else
            //воно записується у другий вихідний файл
            f3.add(f1.strings[i]);
    end;
 
    //зберігаємо створені у пам'яті класи у теці з програмою 
    //під іменами, задами в текстових полях       
    f2.SaveToFile(extractfilepath(application.exename)+edit1.tex');
    f3.SaveToFile(extractfilepath(application.exename)+edit2.text);
 
    //загружаємо отримані файли у 2 і 3 багаторядкові поля
    memo2.Lines.LoadFromFile(extractfilepath(application.exename)+edit1.text);
    memo3.Lines.LoadFromFile(extractfilepath(application.exename)+edit2.text);
 
    //видаляємо із пам'яті створені екземпляри класів
    f1.free;
    f2.free;
    f3.free;
end;
 
Задача № 2
1. Створіть форму, яка наведена на рисунку
 

 
Вказівки: Для форми задайте властивості: Align=alcustom, Borderstyle=bssingle, Bordericons-bimaximized=false, Caption=Робота з файлами, Position=podesktopcenter.
Для створення першого лічильника нанесіть на форму компонент Edit (Standart) і задайте для нього властивості Readonly=true, Text=0. Нанесіть на форму компонент Updown (Win32), розмістіть його біля компонента Edit1, задайте властивість Max=1000.
 
2. Поля-лічильники повинні заповнюватися із кроком 0,1
 
Вказівки: Для того, щоб лічильник заповнювався дробовими значеннями із кроком 0,1 в події Onclick компонента Updown напишіть код:
 
 
Повторіть цю же операцію для створення другого й третього лічильників. При цьому код для другого компонента Updown буде мати вигляд:
 
 
Для третього компонента Updown код має вигляд:
 

 
3. Кнопка "Розрахувати" виводить у поле Memo таблицю значень функції y=sin4x на відрізку [a,b] із заданим кроком. При цьому перевіряються ситуації, щоб початок відрізка не перевищував кінець відрізка, щоб крок не був рівний 0.
При видачі таблиці значень функції потрібно видати заголовок, шапку таблиці, а потім значення.
При видачі таблиці може виникати ситуація, коли в полі Memo може перебувати текст із результатами попереднього розрахунків. У цьому випадку потрібно видавати запит на перезапис значень або додавання нових значень у кінець  поля.
 
Вказівки: Нанесіть на форму компонент Memo (Standard) і задайте властивості: Alignment=tacenter, Font=CourierNew, Lines=очистити,  ReadOnly=true, ScrollBars=ssNone.
 
Якщо вміст поля перевіщує висоту поля, то потрібно відображати полосу прокрутки. В іншому випадку - прибирати.
 
В події OnChange поля введіть код:
 
procedure TForm1.Memo1Change(Sender: TObject);
//змінна для зберігання поточної позиції курсора
var i:integer;
begin
    //запам'ятовуємо поточну позицію курсора
    i:=memo1.selstart;
    //якщо кількість рядків в полі більше 21 (не вміщується по вертикалі)
    if memo1.Lines.count>21 then
        //відображаємо вертикальну полосу прокрутки
        memo1.ScrollBars:=ssVertical;
    //в іншому випадку (текст вміщується по вертикалі)
    else
        //прибираємо полосу прокрутки
        memo1.ScrollBars:=ssnone;
    //ставимо курсор у збережену позицію курсора
    memo1.selstart:=i;
end; 
Нанесіть на форму кнопку Button (Standard) і задайте властивість Caption=Розрахувати.
Для виконання розрахунків у події Onclick кнопки напишемо код:
 



 
4. Кнопка "Зберегти" дозволяє зберегти в зазначений файл вміст поля Memo. При цьому з'являється вікно діалогу збереження файлу. Якщо зазначений при збереженні файл уже існує на диску, то потрібно видати запит на перезапис файлу або додавання в нього нової інформації.
 
Вказівки: Для збереження вмісту поля Memo  у текстовий файл на форму нанесіть компонент Savedialog (Dialogs) і задайте властивості: Filter='Текстові файли | *.txt', Defaultext=txt.
На форму нанесіть кнопку Button (Standard) і задайте властивості: Caption=Зберегти, Enabled=False. Для кнопки напишемо код:
 


 
5. Кнопка "Експорт" дозволяє зберегти в зазначений файл вміст поля Memo. При цьому вміст поля порядково форматується в HTML і записується до файлу.Ім'я файлу зазначається за допомогою діалогу збереження файлу.
 
Вказівки: Для збереження вмісту поля Memo у HTML файл на форму нанесіть другий компонент Savedialog (Dialogs) і задайте властивості: Filter='HTML файли | *.htm', Defaultext=htm.
На форму нанесіть кнопку Button (Standard) і задайте властивості: Caption=Експорт, Enabled=False. Для кнопки напишемо код:
 


 
6. Кнопка "Очистити" очищує поле Memo.
 
Вказівки: Для очищення поля Memo на форму нанесемо компонентів Button (Standard) і задамо властивості: Caption=Очистити, Enabled=False. Для кнопки напишемо код:
 

 
  
7. Якщо користувач розрахує таблицю значень функції й без збереження результату спробує вийти із програми, то потрібно видати повідомлення про необхідність збереження даних і обробити відповідь користувача.
 
Вказівки: Для форми в події OnClose напишемо код:
 

Практическое занятие № 5
 
Тема: Работа с графикой в Delphi
Цуль работы: получить практические навыки по работе с компонентами отображения графических данных
 
Ход работы
 
 
Создайте форму для просмотра графических файлов вида:
 

 
Указания: для формы задайте свойства: Caption=Выбор изображения.
Нанесите на форму компонент ShellTreeView1 для отображения дерева папок. Нанесите на форму компонент ShellListView1 для отображения списка элементов в выбранной папке. Для отображения в списке только графических файлов для компонента ShellListView в событии OnAddFolder введите код:
 
procedure TForm1.ShellListView1AddFolder(Sender: TObject; AFolder: TShellFolder; var CanAdd: Boolean);
      //переменная - признак добавления файла в список элеметов папки (1 - добавить, 0 - нет)
var yes:integer;
    //переменная для выделения расширения из файла
    ext:string;
begin
    //предполагаем, что текущий элемент не подходит для добавления
    yes:=0;
    //если очередной элемент - папка
    if AFolder.IsFolder then
        //то включаем признак добавления
        yes:=1
    else
    //иначе, если очередной элемент не папка, т.е. файл
    begin
        //извлекаем расширение из имени файла
        ext:=ExtractFileExt(AFolder.PathName);
        //если расширение - это расширение графического файла
        if (ext='.jpg') or (ext='.bmp') or (ext='.gif') or (ext='.png') then
            //то включаем признак добавления
            yes:=1;
    end;
 
    //если признак добавления не включен
    if yes=0 then
        //отменяем добавление очередного элемента
        CanAdd:=false;
end;
 
Под деревом папок нужно отображать содержимое выбранного графического файла.
 
Указания: нанесите на форму компонент Image (Additional) и задайте свойства: Stretch = true - масштабирование рисунка, Proportional = true -масштабироание с сохранением пропорций сторон, center = true - выравнивать изображение по центру компонента.
Для работы с 4 основными графическими форматами необходимо:
- формат bmp поддерживается автоматически;
- формат jpg поддерживается, но для работы с ним нужно подключить модуль JPEG;
- формат gif не поддерживается. Для работы с ним скачайте файл GifImage.zip, поместите содержимое архива в папку с вашим проектом и подключите модуль GifImage;
- формат png не поддерживается. Для работы с ним скачайте файл PngImage.zip, поместите содержимое архива в папку с вашим проектом и подключите модуль PngImage.
 
Отображение файла в компоненте Image должно выполняться после щелчка на файле в списке. Для этого в событии OnClick компонента ShellListViewвведите код:
 
procedure TForm1.ShellListView1Click(Sender: TObject);
begin
    //если в списке выбран не пустой элемент (щелкнули не на пустом фоне окна)
    if (ShellListView1.Selected<>nil) and
        //и выбранный элемент в списке не папка
        not (ShellListView1.SelectedFolder.IsFolder) then
            //в компонент Image1 загружаем выбранный файл
            Image1.Picture.LoadFromFile(ShellListView1.SelectedFolder.PathName)
end;
 
По двойному щелчку на компоненте Image открывается новое окно с увеличенным изображением.
 
Указания: добавьте в проект новую форму. Для формы задайте свойства: Caption = Просмотр изображения, Position = poDesktopCenter. В свойствах проекта перенесите созданную форму в список Available Forms.
Нанесите на форму компонент Image и задайте для него свойства: Align = alClient - компонент заполняет всю форму, Stretch = true - масштабирование рисунка, Proportional = true - масштабироание с сохранением пропорций сторон, center = true - выравнивать изображение по центру компонента.
Перейдите на главную форму и для компонента Image в событии OnDblClick введите код:
 
procedure TForm1.Image1DblClick(Sender: TObject);
begin
    //если изображения в компоненте Image нет, то конец работы процедуры
    if Image1.Picture.Graphic=nil then
        exit;
    //создаем в памяти экземпляр формы
    Form2:=TForm2.Create(nil);
    //отображаем форму как модальную
    Form2.ShowModal;
end;
 
При отображении второй формы на ней в компоненте Image должно отображаться изображение из Image на главной форме. Для этого в событии OnShowвторой формы введите код:
 
procedure TForm2.FormShow(Sender: TObject);
begin
    //загружаем в компонент Image содержимое компонента Image главной формы
    Image1.Picture.Assign(Form1.Image1.Picture);
end;
 
Для удаления созданной формы из памяти перейдите на вторую форму и в событии OnClick введите код:
 
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    action:=cafree;
end;
 
Для выполнения работы с изображением на главной форме для компонента Image создадим контекстное меню.
 

 
Указания: нанесите на форму компонент PopupMenu. Двойным щелчком на нем откройте редактор меню и введите команды: Сохранить..., Разделитель, Вырезать, Копировать, Вставить, Разделитель, Изменить размер...
Для присваивания созданного меню для компонента Image в свойстве PopupMenu укажите созданное меню.
Команды контекстного меню нужно блокировать и разблокировать в зависимости от состояния изображения и буфера обмена.
Для работы с буферолм обмена подключите модуль ClipBrd.
В событии OnPopup компонента PopupMenu введите код:
 
procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin
    //если изображения в Image нет
    if Image1.Picture.Graphic=nil then
    begin
        //блокируем кроманды Сохранить..., Вырезать, Копировать, Изменить размер...
        n1.Enabled:=false;
        n3.Enabled:=false;
        n4.Enabled:=false;
        n7.Enabled:=false;
    end
    //иначе, если изображения в Image есть
    else
    begin
        //разблокируем кроманды Сохранить..., Вырезать, Копировать, Изменить размер...
        n1.Enabled:=true;
        n3.Enabled:=true;
        n4.Enabled:=true;
        n7.Enabled:=true;
    end;
 
    //если в буфере обмена графическая информация   
    if not Clipboard.HasFormat(cf_picture) then
        //команда Вставить разблокируется       
        n5.Enabled:=false
    //иначе, если в буфере обмена не графическая информация       
    else
        //команда Вставить блокируется          
        n5.Enabled:=true;
end; 
Команда Сохранить... должна выдавать диалог и предлагать пользователю выбрать один из 4 типов файлов.
 
Указания: нанесите на форму компонент SavePictureDialog. Для компонента задайте свойства: Filter = Bitmaps (*.bmp)|*.bmp|JPEG Image (*.jpg)|*.jpg|GIF Image (*.gif)|*.gif|PNG Image (*.png)|*.png - список форматов для сохранения, DefaultExt = bmp - тип файла по умолчанию.
При изменении типа файла в диалоге нужно менять расширение по умолчанию. Для этого в событии OnTypeChange диалога введите код:
 
procedure TForm1.SavePictureDialog1TypeChange(Sender: TObject);
begin
    //номер типа файла находится в свойстве FilterIndex (нумерация с 1)
    //проверяем какой тип файла был выбран и задаем соотвествующее расширение
    case SavePictureDialog1.FilterIndex of
        1: SavePictureDialog1.DefaultExt:='bmp';
        2: SavePictureDialog1.DefaultExt:='jpg';
        3: SavePictureDialog1.DefaultExt:='gif';
        4: SavePictureDialog1.DefaultExt:='png';
    end;
end;
 
Напишем код для команды Сохранить... Двойным щелчком откройте меню PopupMenu и двойным щелчком откройте код команды Сохранить... Введите код:
 
procedure TForm1.N1Click(Sender: TObject);
    //переменные для работы с файлами в разных форматах
var bmp:TBitmap;
    jpg:TJpegImage;
    gif:TGifImage;
    png:TPngObject;
begin
    //очищаем предыдущее имя файла
    SavePictureDialog1.FileName:='';
   
    //если файл в диалоге сохранения не указан, конец работы процедуры
    if not SavePictureDialog1.Execute then
        exit;
 
    //в зависимости от выбранного типа файла (свойство FilterIndex)
    //сохраняем содержимое Image в соотвествующий формат
    case SavePictureDialog1.FilterIndex of
    //если выбран первый формат (bmp)
    1: begin
            //создаем экземпляр класса для работы с форматом bmp
            bmp:=TBitmap.Create;
            //загружаем в класс содержимое компонента Image (конвертируем изображение)
            bmp.Assign(Image1.Picture.Graphic);
            //сохраняем полученное изображение в файл
            bmp.SaveToFile(SavePictureDialog1.FileName);
            //удаляем экземпляр класса из памяти       
            bmp.Free;
        end;
    //аналогично формат jpg
    2: begin
            jpg:=TJpegImage.Create;
            jpg.Assign(Image1.Picture.Graphic);
            jpg.SaveToFile(SavePictureDialog1.FileName);
            jpg.Free;
        end;
    //аналогично формат gif
    3: begin
            gif:=TGifImage.Create;
            gif.Assign(Image1.Picture.Graphic);
            gif.SaveToFile(SavePictureDialog1.FileName);
            gif.Free;
        end;
    //формат png можно получить только из bmp формата
    4: begin
            //создаем экземпляр класса для работы с форматом bmp
            bmp:=TBitmap.Create;
            //загружаем в класс содержимое компонента Image (конвертируем изображение)
            bmp.Assign(Image1.Picture.Graphic);
            //создаем экземпляр класса для работы с форматом png           
            png:=TPngObject.Create;
            //загружаем в png изображение bmp (происходит конвертирование)           
            png.Assign(bmp);
            //сохраняем полученное изображение           
            png.SaveToFile(SavePictureDialog1.FileName);
            //удаляем созданные экземпляры классов
            png.Free; bmp.free;
        end;
    end;
end;
 
Реализуйте возможность работы с графикой через буфер обмена.
 
Указания: двойным щелчком откройте меню PopupMenu и двойным щелчком откройте процедуру команды Вырезать. Введите код:
 
procedure TForm1.N3Click(Sender: TObject);
begin
    //копируем содержимое Image в буфер обмена
    Clipboard.Assign(Image1.Picture);
    //очищаем содержимое Image
    Image1.Picture:=nil;
end;
 
Для команды Копировать напишите код:
 
procedure TForm1.N4Click(Sender: TObject);
begin
    //копируем содержимое Image в буфер обмена
    Clipboard.Assign(Image1.Picture);
end;
 
Для команды Вставить напишите код:
 
procedure TForm1.N5Click(Sender: TObject);
begin
    //если в буфере графическая информация   
    if Clipboard.HasFormat(cf_picture) then
        //в компонент Image помещается содержимое буфера обмена   
        Image1.Picture.Assign(Clipboard);
end;
 
Для команды Изменить размер... организуйте вывод новой формы с возможностью задания нового размера изображения.
 
Указания: создайте новую форму и задайте для нее свойства: Caption = Новый размер, BorderStyle = bsDialog, Position = poDesktopCenter. В окне свойст проекта перенесите форму в список Available Forms. двойным щелчком откройте меню PopupMenu и двойным щелчком откройте процедуру команды Изменить размер... Введите код:
 
procedure TForm1.N7Click(Sender: TObject);
begin
    //создаем экземпляр формы в памяти
    form3:=tform3.create(nil);
    //отображаем созданную форму как модальную
    form3.showmodal;
end;
 
При закрытии формы она должна удаляться из памяти. Перейдите на созданную форму и в событии OnClose ведите код:
 
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    action:=cafree;
end;
 
Форму задания размера файла оформите как показано на рисунке. При открытии формы поля Ширина и Высота должны автоматически заполняться реальными размерами изображения, отображаемого в компоненте Image главной формы. При вводе ширины или высоты значение в соседнем поле должно автоматически изменяться с соблюдением пропорций рисунка.
 

 
Указания: нанесите на форму две надписи, два текстовых поля и две кнопки. Для перовой кнопки задайте свойство Default = true, для второй - Cancel = true.
Для сохранение пропорций сторон рисунка опишем глобальную переменную для хранения коэффициента соотношения сторон:
 
prop:real;
 
В событии OnCreate формы заполним поля  реальными размерами изображения и вычислим коэффициент пропорции.
 
procedure TForm3.FormCreate(Sender: TObject);
begin
    //первое поле - ширина изображения из Image на главной форме
    edit1.Text:=inttostr(Form1.Image1.Picture.Width);
    //второе поле - высота изображения из Image на главной форме
    edit2.Text:=inttostr(Form1.Image1.Picture.Height);
    //коэффициент пропорции = ширина/высота
    prop:=Form1.Image1.Picture.Width/Form1.Image1.Picture.Height;
end;
 
При изменении значения ширины высота должна автоматически пересчитываться с учетом коэффициента. В событии OnKeyDown поля Edit1 введите код:
 
procedure TForm3.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
    edit2.Text:=floattostr(round(strtoint(edit1.Text)/prop));
end;
 
При изменении значения  высотs ширина должна автоматически пересчитываться с учетом коэффициента. В событии OnKeyDown поля Edit2 введите код:
 
procedure TForm3.Edit2KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
    edit1.Text:=floattostr(int(strtoint(edit2.Text)*prop));
end;
 
Кнопка Отмена закрывает окно.
 
procedure TForm3.Button2Click(Sender: TObject);
begin
    close;
end;
 
Кнопка ОК изменяет размер рисунка и помещает его в компонент Image на главной форме.
 
procedure TForm3.Button1Click(Sender: TObject);
//переменные для работы с изображением
//bmp - исходное изображение
//tempbmp - полученное изображение после изменения размера
var
    bmp,tempbmp:Tbitmap;
begin
    //если один из размеров изображения не указан   
    if (edit1.text='') or (edit2.text='') then
    begin
        //выдаем сообщение об ошибке    
        application.MessageBox('Выполнение операции невозможно. Укажите правильно размер изображения',
                               'Ошибка',mb_ok+mb_iconerror);
        //завершаем работу процедуры
        exit;
    end;
   
    //создаем экземпляр класса для исходного изображения
    bmp:=Tbitmap.create;
    //помещаем в класс изображение из  компонента Image на главной форме
    bmp.assign(form1.Image1.Picture.Graphic);
    //создаем экземпляр класса для нового изображения
    tempbmp:=Tbitmap.create;
    //задаем новому изображению ширину и высоту из полей на форме
    tempbmp.width:=StrToInt(edit1.text);
    tempbmp.Height:=StrToInt(edit2.text);
    //задаем параметры нового изображения
    tempbmp.pixelFormat:=pf24bit;
    //задаем для нового изображения гладкое массштабирование
    SetStretchBltMode(tempbmp.canvas.handle,4);
    //копируем исходное изображение в новое (происходит увеличение)
    StretchBlt(tempbmp.canvas.handle,0,0,StrToInt(edit1.text),StrToInt(edit2.text),
               bmp.canvas.handle, 0,0,bmp.width,bmp.height,SRCCOPY);
    //в компонент Image на главной форме помещаем полученное изображение
    form1.image1.picture.assign(tempbmp);
    //удаляем из памяти экземпляры класса
    tempbmp.free;
    bmp.free;
    //выдаем ссобщение об успешном завершении операции
    application.MessageBox('Обработка завершена. Можете сохранить изображение в файл',
                           'Операция завершена',mb_ok+mb_iconinformation);
    //закрываем форму
    close;
end;
Практическое занятие № 6
Тема: работа с табличными данными. Построение графиков и диаграмм.
Цель работы: получить практические навыки для отображения и обработки табличных данных, а также построения графиков и диаграмм.
 
Ход работы
 
Создать программу для работы с табличными данными. При этом главная форма программы имеет вид:
 

 
Указания: для формы задайте свойства: Caption = текст заголовка, BorderStyle = bsSingle, BorderIcons - Maximized = false, Position = poDesktopCenter.
Для создания сетки нанесите на форму компонент StringGrid (Additional) и задайте для него свойства: ColCount = 8, RowCount=5, Options (включитеgoEditing, goTab).
Для настройки параметров шапки таблицы в событии OnCreate формы введите код:
 
procedure TForm1.FormCreate(Sender: TObject);
begin
    //задаем ширину колонки с указанным номером
    stringgrid1.ColWidths[0]:=40;
    //задаем текст надписи в первой строке (нумерация с 0)
    //и колонке с указанным номером
    stringgrid1.Cells[0,0]:='№ п/п';
    stringgrid1.ColWidths[1]:=100;
    stringgrid1.Cells[1,0]:='Фамилия';
    stringgrid1.ColWidths[2]:=100;
    stringgrid1.Cells[2,0]:='Имя';
    stringgrid1.ColWidths[3]:=100;
    stringgrid1.Cells[3,0]:='Отчество';
    stringgrid1.ColWidths[4]:=100;
    stringgrid1.Cells[4,0]:='Дата рожд.';
    stringgrid1.ColWidths[5]:=40;
    stringgrid1.Cells[5,0]:='Пол';
    stringgrid1.ColWidths[6]:=60;
    stringgrid1.Cells[6,0]:='Ср.балл';
    stringgrid1.ColWidths[7]:=60;
    stringgrid1.Cells[7,0]:='Стипендия';
end;
 
При вводе среднего балла строки в сетке должны закрашиваться цветами: 5 - зеленый, 4 - синий, 3 - желтый, 2 - красный. Активная ячейка в сетке должна окрашиваться салатовым цветом. Текст в ячейках выравнивается так: ФИО - по левому краю, остальные - по центру.
 
Указания: в событии OnDrawCell сетки введите код окрашивания:
 
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
//метка для перехода к блоку выдачи текста в сетке
begin
 
    //если ячейка относится к фиксированной области, то конец
    if (acol=0) or (arow=0) then exit;
   
    //если ячейка активная, то фон для нее салатовый
    if gdFocused in state then
        stringgrid1.Canvas.Brush.Color:=cllime;
 
    //если в 7 колонке нет данных (средний балл не введен)
    if stringgrid1.cells[6,arow]='' then
        //цвет фон ячеек белый
        stringgrid1.Canvas.Brush.Color:=clwhite;
    //если балл 5
    else if strtofloat(stringgrid1.Cells[6,arow])=5 then
        //цвет фона зеленый
        stringgrid1.Canvas.Brush.Color:=clgreen
    //если средний балл 4 и выше
    else if strtofloat(stringgrid1.Cells[6,arow])>=4 then
        //цвет фона синий
        stringgrid1.Canvas.Brush.Color:=clblue
    //если средний балл 3 и выше
    else if strtofloat(stringgrid1.Cells[6,arow])>=3 then
        //цвет фона желтый
        stringgrid1.Canvas.Brush.Color:=clyellow
    else
        //во всех остальных случая цвет фона красный
        stringgrid1.Canvas.Brush.Color:=clred;
 
    //заливаем строку сетки указанным фоном
    stringgrid1.Canvas.FillRect(rect);
 
    //блок вывода текста в сетку
    //если колонки не 1, не 2 или не 3 (не ФИО)
    if (acol<>1) or (acol<>2) or (acol<>3) then
        //выдаем текст по центру ячейки
        stringgrid1.Canvas.TextOut((rect.left+(rect.right-rect.left-Canvas.TextWidth(stringgrid1.Cells[acol,arow]))div 2), rect.Top+2,stringgrid1.Cells[acol,arow])
    //ячейки с ФИО выдаем по левому краю
    else
        stringgrid1.Canvas.TextOut(rect.left+2, rect.Top+2,stringgrid1.Cells[acol,arow]);
end;
 
Колонка "Стипендия" рассчитывается по формуле: средний балл * 120. При этом необходимо отфильтровать ввод в колонку "Средний балл", чтобы пользователь не мог ввести никаких данных кроме оценок в диапазоне от 2 до 5.
 
Указания: в событии сетки OnSetEditText введите код:
 
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol,ARow: Integer; const Value: String);
//переменная для считывания значения из ячейки сетки
var ch:real;
begin
    //если редактируется не 7 колонка (не средний балл)
    if acol<>6 then
        //процедура завершает свою работу   
        exit;
 
    //пытаться выполнить код
    try
        //конвертируем содержимое ячейки 7 колонки в число
        ch:=strtofloat(stringgrid1.Cells[6,arow]);
        //если конвертирование удалось, но значение не попадает в диапазон от 2 до 5
        if (ch>5) or (ch<2) then
        begin
            //колонки "Средний балл" и "Стипендия" очищаются
            stringgrid1.Cells[6,arow]:='';
            stringgrid1.Cells[7,arow]:='';
        end;
    //если конвертирование не удалось (в ячейке не число)
    except
        //колонки "Средний балл" и "Стипендия" очищаются
        stringgrid1.Cells[6,arow]:='';
        stringgrid1.Cells[7,arow]:='';
    end;
 
    //если все прошло успешно, и средний балл не пуст
    if stringgrid1.Cells[6,arow]<>'' then
        //считаем стипендию по формуле
        stringgrid1.Cells[7,arow]:=floattostr(strtofloat(stringgrid1.Cells[6,arow])*120);
end;
 
Замечание: в приведенном коде присутствует команда обработки исключений
 
try
    . . .
except
    . . .
end;
 
По умолчанию данный оператор не выполняется при компиляции программы. Для работы оператора необходимо выполнить настройки среды: выполните команду Tools - Debugger Options и на закладке Language Exception снимите флажок Stop on Delphi Exception.
 
Так как колонка "Стипендия" рассчитывается по формуле, то необходимо заблокировать возможность установки в нее курсора для редактирования.
 
Указания: В событии сетки OnSelectCell введите код:
 
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,ARow: Integer; var CanSelect: Boolean);
begin
    //если колонка 8 (Стипендия)
    if acol=7 then
        //блокируем установку в нее курсора
        CanSelect:=false;
end;
 
При закрашивании сетка не отображает цвет строки корректно: закрашивается только активная ячейка и ячейка с расчетной стипендией. Остальные ячейки не успевают перерисоваться..
 
Указания: для решения данной проблемы нужно перерисовывать сетку при окончании ввода среднего балла. Окончание ввода может произойти в нескольких случаях:
- курсор перевели на другую ячейку в сетке (событие сетки OnSelectCell);
- курсор перевели за пределы сетки (событие сетки OnExit);
- пользователь нажал клавишу Enter (событие формы OnKeyDown).
 
В событии OnSelectCell добавьте команду
 
//перерисовать сетку
StringGrid1.repaint;
 
В событии OnExit введите код:
 
procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
    //перерисовать сетку
    StringGrid1.repaint;
end;
 
Для реакции нажатия на клавишу Enter для формы установите свойство KeyPreview = true. В событии OnKeyDown сетки введите код:
 
procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);
begin
    //и нажата клавиша Enter
    if (key=vk_return then
        //перерисовать сетку
        stringgrid1.Repaint;
end;
 
Реализуйте возможность сохранения и восстановления данных сетки через INI файл.
 
Указания: для работы с INI файлом подключите модуль INIFiles.
Для сохранения данных сетки в событии OnClose формы введите код:
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
//переменные для работы с INI фалом и счетчики циклов
var ini:tinifile; i,j:integer;
begin
    //создаем экземпляр класса и связываем с файлом
    ini:=tinifile.create(extractfilepath(application.exename)+'settings.ini');
    //сохраняем в INI файл количнство строк сетки
    ini.writeinteger('grid','rowcount',stringgrid1.rowcount);
 
    //в цикле сохраняем в INI файл содержимое ячеек
    //при этом для каждой колонки создаем отдельный раздел COL с номером колонки
    for i:=0 to stringgrid1.colcount-1 do
        for j:=0 to stringgrid1.rowcount-1 do
            ini.WriteString('Col'+inttostr(i),'Row'+inttostr(j),stringgrid1.Cells[i,j]);
    //удаляем экземпляр класса из памяти
    ini.Free;
end;
 
Для считывания сохраненных данных в сетку необходимо в событие OnCreate формы внести изменения.
Опишите вспомогательные переменные:
 
//переменные для работы с INI фалом и счетчики циклов
var ini:tinifile; i,j:integer;
 
После кода задания параметров шапки сетки добавьте фрагмент:
 
//создаем экземпляр класса и связываем с файлом
ini:=tinifile.create(extractfilepath(application.exename)+'settings.ini');
 
//для сетки считываем количество сохраненных строк
stringgrid1.RowCount:=ini.ReadInteger('grid','rowcount',2);
 
//в первой колонке (№ п/п) отображаем порядковые номера строк
for i:=1 to stringgrid1.RowCount-1 do
    stringgrid1.cells[0,i]:=inttostr(i);
 
//в цикле все ячейки кроме фиксированных заполняются сохраненными в файле INI данными
for i:=1 to stringgrid1.colcount-1 do
    for j:=1 to stringgrid1.rowcount-1 do
        stringgrid1.Cells[i,j]:=ini.ReadString('Col'+inttostr(i),'Row'+inttostr(j),'0');
ini.Free;
 
Организуем добавление данных в сетку через вспомогательную форму вида:
 

 
Указания: добавьте новую форму и перенесите ее в спиcок Available Forms. Для формы задайте свойства: Caption = Данные, BorderStyle = bsDialog, Position = poDesktopCenter. Форма должна при закрытии удаляться из памяти. для этого в событии OnClose формы введите код:
 
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    action:=cafree;
end;
 
Нанесите на форму надписи и текстовые поля, а также две кнопки. Кнопка отменить просто закрывает окно:
 
procedure TForm2.Button2Click(Sender: TObject);
begin
    close;
end;
 
Поле "Средний балл" должно фильтровать ввод: можно ввести оценку в диапазоне от 2 до 5. Для этого в событии OnChange поля введите код:
 
procedure TForm2.Edit6Change(Sender: TObject);
//переменная для считывания содержимого поля
var ch:real;
begin
    //пытаться выполнить действия
    try
        //конвертируем поле в число
        ch:=strtofloat(edit6.Text);
        //если конвертирование удалось, но полученное число не в допустимом диапазоне
        if (ch<2) or (ch>5) then
            //поле очищается
            edit6.Text:='';
    //если конвертирование не удалось (в поле не число)
    except
        //поле очищается
        edit6.Text:='';
    end;
end;
 
Кнопка "Сохранить" добавляет в сетку новую строку и заполняет колонки сетки полями из формы.
 
procedure TForm2.Button1Click(Sender: TObject);
begin
    //если ФИО или средний балл не введены, то процедура не выполняется
    if (edit1.text='') or (edit2.text='') or (edit3.text='') or (edit6.text='') then
        exit;
 
    //увеличиваем количество строк на 1
    form1.StringGrid1.rowcount:=form1.StringGrid1.rowcount+1;
    //заполняем колонки сетки полями из формы
    form1.StringGrid1.Cells[0,form1.StringGrid1.rowcount-1]:=
                                inttostr(form1.StringGrid1.rowcount-1);
    form1.StringGrid1.Cells[1,form1.StringGrid1.rowcount-1]:=edit1.text;
    form1.StringGrid1.Cells[2,form1.StringGrid1.rowcount-1]:=edit2.text;
    form1.StringGrid1.Cells[3,form1.StringGrid1.rowcount-1]:=edit3.text;
    form1.StringGrid1.Cells[4,form1.StringGrid1.rowcount-1]:=edit4.text;
    form1.StringGrid1.Cells[5,form1.StringGrid1.rowcount-1]:=edit5.text;
    form1.StringGrid1.Cells[6,form1.StringGrid1.rowcount-1]:=edit6.text;
    form1.StringGrid1.Cells[7,form1.StringGrid1.rowcount-1]:=
                                floattostr(strtofloat(edit6.text)*120);
    //закрываем форму
    close;
end;
 
На главной форме разместите кнопку Добавить и введите для нее код:
 
procedure TForm1.Button1Click(Sender: TObject);
begin
    form2:=tform2.create(nil);
    form2.showmodal;
end;
 
Организуйте удаление выбранной строки из сетки.
 
Указания: нанесите на главную форму кнопку и для нее напишите код:
 
procedure TForm1.Button5Click(Sender: TObject);
//переменные для организации цикла
var i,j:integer;
begin
    //если число строк в сетке =1 (только шапка)
    if stringgrid1.rowcount=1 then
        //завершаем работу процедуры
        exit;
 
    //выдаем запрос на удаление текущей строки
    //если на запрос ответили нет, то завершаем работу процедуры
    if application.MessageBox(pchar('Удалить данные о студенте: '
                                    +stringgrid1.cells[1,stringgrid1.Row]+' '
                                    +stringgrid1.cells[2,stringgrid1.Row]+' '
                                    +stringgrid1.cells[3,stringgrid1.Row]),
                                    'Подтвердите операцию',mb_yesno+mb_iconquestion)=idno then
        exit;
 
    //в цикле смещаем все строки под удаляемой на 1 позицию вверх
    for i:=0 to stringgrid1.ColCount-1 do
        for j:=stringgrid1.Row to stringgrid1.RowCount-2 do
            stringgrid1.Cells[i,j]:=stringgrid1.Cells[i,j+1];
 
    //уменьшаем в сетке количество строк на 1
    stringgrid1.rowcount:= stringgrid1.rowcount-1;
end;
 
Организовать вывод графика или диаграммы на основании данных о стипендии студентов.
 
Указания: нанесите на форму компонент Chart (Additional). Двойным щелчком откройте его и задайте свойства: Series - добавьте два типа диаграммы (график и столбчатая диаграмма).
Для переключения типа отображения данных на диаграмме добавьте на форму компонент RadioGroup, для которого задайте свойства: Columns - 2 (две колонки), Items - названия переключателей, ItemIndex = 0 (выбран по умолчанию первый переключатель).
Так как график должен перестраиваться при наступлении множества событий (при открытии формы, при редактировании среднего балла в сетке, при добавлении или удалении данных в сетке), то оформим код построения в виде отдельной процедуры без параметров.
Вверху кода модуля формы добавьте заголовок процедуры:
 
procedure ShowChart;
 
В основном коде добавьте код процедуры:
 
procedure tform1.ShowChart;
//переменная для цикла
var i: Integer;
begin
    //задаем заголовок диаграммы
    Chart1.Title.Text.Clear;
    Chart1.Title.Text.Add('Данные о сумме стипендии');
 
    //очищаем первый тип диаграммы от данных
    chart1.Series[0].clear;
 
    //в цикле наполняем ряд значениями из сетки
    //стипендия - это данные
    //фамилия - это подпись для данных
    for i := 1 to stringgrid1.RowCount-1 do
    begin
        //при этом, если стипендия не пустая
        if stringgrid1.Cells[7,i]<>'' then
            //то в качестве значения добавляется ее значение
            chart1.Series[0].Add(strtofloat(stringgrid1.Cells[7,i]),stringgrid1.Cells[1,i])
        else
            //в противном случае, если стипендия не посчитана, то добавляется 0
            chart1.Series[0].Add(0,stringgrid1.Cells[1,i]);
    end;
 
    //первая диаграмма становится активной (отображается)
    chart1.series[0].active:=true;
    //вторая диаграмма пока не активна (не отображается)
    chart1.series[1].active:=false;
    //группа переключателей устанавливается на первый элемент
    radiogroup1.ItemIndex:=0;
end;
 
Для вызова данной процедуры используйте команду вида:
 
ShowChart;
 
Вызов  процедуры нужно добавить в конец кода следующих событий:
- OnCreate формы;
- OnSetEditText сетки;
- OnClick для кнопки "Удалить".
 
На второй форме для кнопки "Сохранить" вызов процедуры выпролняют с указание имени формы:
 
form1.ShowChart;
 
С помощью группы переключателей организуйте переключение типа отображаемой информации на диаграмме.
 
В событии OnClick компонента RadioGroup веедите код:
 
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
    //если выбран первый тип (график)
    case radiogroup1.ItemIndex of
    0: begin
            //первую тип диаграммы отображаем
            chart1.Series[0].Active:=true;
            //второй тип скрываем
            chart1.Series[1].Active:=false;
       end;
    //если выбран второй тип (диаграмма)   
    1: begin
            //для второго типа диаграммы загружаем данные из первого типа,
            //который заполняется по умолчанию в разных событиях
            chart1.Series[1].assign(chart1.Series[0]);
            //первый тип диаграммы скрываем
            chart1.Series[0].Active:=false;
            //второй тип отображаем
            chart1.Series[1].Active:=true;
       end;
    end;
end;
Практическое занятие 7
 
Тема: Работа с данными в формате дата/время. Использование компонентов для работы с датами.
Цель работы: получить практические навыки по использованию функций для работы с датой/временем. Отработать навыки использования компонентов для работы с датами.
 
Ход работы
 
Создайте учебную форму для проверки возможностей работы с датами и временем.
 

 
Указания: для формы задайте свойства: Caption='Работа с датами', BorderStyle=bsSingle, BorderIcom-biMaximized=false, Position=poDesktopCenter.
Процесс создания содержимого формы разобьем на несколько простых шагов, указанных ниже.
 
Создать форму с панелью инструментов, у которой в правой части отображается текущая дата и время
 

 
Указания: Нанесите на форму компонент Statusbar (Win32). Двойным щелчком откройте окно панелей компонента и с помощью первой кнопки на панели инструментов создайте две панели. Выделите первую панель и задайте свойство width таким, чтобы вторая панель имела ширину, показанную на рисунке.
Для работы с датами и временем подключите модуль dateutils.
 
В событии OnCreate формы напишем команду отображения текущей даты.
 

 
Время должно обновляться каждую секунду. Для этого нанесите на форму компонент Timer (System). В его событии OnTimer введите тот же код, что был введен ранее.
 
На панели разместить два выпадающих поля с календарем для задания диапазона поиска данных. При этом первый календарь по умолчанию отображает первое число текущего месяца, а второй - текущую дату.
 

 
 
Указания: нанесите на форму компонент Panel и задайте свойство Caption='Задание 1 (поиск)'. На панели разместите два компонента DataTimePicker (Win32). Для отображения в компонентах значений, указанных в задании в событие OnCreate формы добавьте команды:
 

 
Пусть имеется текстовый файл, в котором записаны некоторые показатели в формате
 
дата    число1    число2    число3
 
Необходимо реализовать функцию, при которой в поле Memo выдаются только те данные из файла, даты которых попадают в заданный диапазон.
 
Указания: В текстовом редакторе создайте такой файл и сохраните на диске. На панели разместите компонент Memo (Standard) и очистите свойство Lines.
Внизу разместите две кнопки Button (Standard) и в свойстве Caption задайте надписи на них.
Для открытия текстового файла нанесите на форму компонент OpenDialog
(Dialogs) и задайте свойство Filter=Текстовые файлы|*.txt.
 
Для первой кнопки напишем код:
 

   

 
Для второй кнопки напишите код:
 

 
Создайте панель для вычисления диапазона даты/времени.
 

 
 
Указания: нанесите на форму компонент Panel и задайте свойство Caption='Задание 2 (диапазоны)'. На панели разместите два компонента DataTimePicker (Win32). Как и ранее, в первом поле отобразим первый день текущего месяца, а во втром - текущую дату. Для этого в событие OnCreate формы добавьте команды:
 

 
Ниже разместите компонент RadioGroup (Standard) и в свойстве Items введите названия переключателей. Для задания активным первого переключателя задайте свойство ItemIndex=0.
 
Разместите текстовое поле Edit (Standard) для отображения результата. Задайте свойства: ReadOnly=true, Text очистить.
Разместите кнопку Button (Standard). В свойстве Caption укажите надпись на кнопке.
 
Для кнопки введите код:
 

 
Реализуйте возможность изменения даты на указанное количество лет, месяцев или дней. При этом результат выводится в форматах для разных СУБД.
 

 
Указания: нанесите на форму компонент Panel и задайте свойство Caption='Задание 3 (расчет)'. На панели разместите компонент DataTimePicker (Win32).Для отображения в нем текущей даты в событие OnCreate формы добавьте команду:
 

 
Разместите текстовое поле Edit (Standard) для ввода значения изменения даты. Очистите свойство Text.
 
Ниже разместите компонент RadioGroup (Standard) и в свойстве Items введите названия переключателей. Для задания активным первого переключателя задайте свойство ItemIndex=0.
Рядом разместите еще один компонент RadioGroup (Standard) и в свойстве Items введите названия форматов вывода. Для задания активным первого переключателя задайте свойство ItemIndex=0.
 
 
Разместите текстовое поле Edit (Standard) для отображения результата. Задайте свойства: ReadOnly=true, Text очистить.
Разместите кнопку Button (Standard). В свойстве Caption укажите надпись на кнопке.
 
Для кнопки введите код:
 

 
Практичне заняття № 8
Тема: «Робота з базами даних в Delphi»
Ціль роботи: отримати практичні навички по створенню програм для роботи із БД
 
Хід роботи
 
1. У СУБД Access спроектуйте базу даних, що має таблицю з ім'ям «Sotr» і містить інформацію про співробітників:
 
Ім'я поля Тип Розмір
Табельний номер Числовий Ціле, ключове
Прізвище Текстовий 15
Ім'я Текстовий 10
По батькові Текстовий 15
Дата народження Дата/час  
Посада Текстовий 15
Оклад Числовий Одинарної точності із плаваючою комою
Фото Поле об'єкта OLE  
 
Заповніть таблицю, увівши в неї п'ять записів (поле Фото не заповнювати).
Також у базі даних створіть таблицю-довідник "Dolg" для зберігання переліку посад підприємства. Таблиця  складається з одного ключового поля Посада. Відкрийте таблицю й введіть 5 будь-яких посад.
 
2. У середовищі Delphi створіть програму для роботи з даними таблиць. При цьому форма повинна мати вигляд:
 

 
У сітці відображаються поля (табельний номер, прізвище, ім'я, по батькові). Усі поля повинні мати назву зрозумілою мовою, прийнятну ширину стовпців. Сама сітка заблокована для редагування даних.
 
3. Додайте на сітку поле Премія, яке обчислюється по формулі: 20% від окладу (оклад*0,2)
 
4. Для поля Оклад установіть обмеження: значення поля не може бути менш 700 грн. Якщо менше, то видати повідомлення про помилку й скасувати введення
 
5. На формі розмістіть дві кнопки для додавання й видалення даних.
При цьому за допомогою кнопки Додати можна ввести нового співробітника через допоміжну сторінкову форму. Кнопка Вилучити видаляє поточний запис. Подвійне клацання на запису в сітці відкриває допоміжну сторінкову форму для редагування даних.
Допоміжна сторінкова форма має вигляд:
 

 
Фото співробітника заповнюється через діалог вибору графічного файлу після подвійного клацання на графічному полі. Поле Дата народження заповнюється за допомогою календаря, поле Посада заповнюється через список, значення якого вибираються з довідкової таблиці Посади.
Кнопка Зберегти закриває вікно й зберігає зміни в таблиці. При цьому, якщо не заповнене поле Табельний номер, то збереження неможливе.
Кнопка Скасувати закриває вікно й скасовує внесені зміни.
 
Виконання роботи
 
Для головної форми задайте властивості: Caption="Список співробітників", Position="Desktopcenter", Borderstyle="bssingle". На форму нанесіть компонент Adoconnection (ADO). У властивості Connectionstring клацніть на кнопці Build, виберіть рядок зі словом Jet 4 і вкажіть ім'я файлу бази даних, видаливши шлях. У властивості Loginprompt укажіть false, щоб програма не запитувала пароль при з'єднанні з базою даних.
Нанесіть на форму компонент Adotable (ADO). У властивості Connection виберіть ім'я з'єднання Adoconnection1, у властивості Tablename виберіть таблицю Sotr.
 
Для того, щоб програма коректно підключала таблицю в події форми Oncreate введіть код:
 
procedure Tform1.Formcreate(Sender: Tobject);
begin
//підключаємо таблицю до програми
adotable1.Active:=true;
end;  
 
Для того, щоб програма коректно відключала таблицю, в події форми Ondestroy введіть код:
 
procedure Tform1.Formdestroy(Sender: Tobject);
begin
//відключаємо таблицю від програми
adotable1.Active:=false;
end;
 
Проектування сітки
 
Нанесіть на форму компонент Datasource (Dataaccess). Установіть його властивість Dataset =Adotable1.
Нанесіть на форму компонент Dbgrid (Datacontrols). У властивості Datasource укажіть ім'я компонента Datasource1.Для блокування сітки у властивості Readonly укажіть True.
Для того, щоб у сітці Dbgrid відображалися тільки поля Табельний номер, Прізвище, Ім'я, По батькові клацніть два рази на компоненті Adotable1. У вікні, що з'явилося, викличте контекстне меню, виберіть команду Add All Fields. У результаті у вікні з'явиться список усіх полів таблиці. Утримуючи клавішу Ctrl виділіть тих поля, які не потрібно відображати й у властивості Visible  укажіть False.
 
Створення поля"Премія", що обчислюється
 
Для створення поля для премії двічі клацніть на Adotable1, у вікні, що з'явилося, викличте контекстне меню й виберіть команду Newfield.
Заповніть поля: Name=Prem, Component=Prem, Type=Float, Fieldtype=Calculated і клацніть ОК.
Виділіть створене поле й задайте властивості: Alignment=tacenter, Displaylabel=Премія.
Для введення формули виділіть компонент Adotable і в події Oncalcfields уведіть код:
 
procedure Tform1.Adotable1Calcfields(Dataset: Tdataset);
begin
adotable1.Fieldbyname('prem').Value:=adotable1.Fieldbyname('oklad').Value*0.2;
end;
 
Контроль уведення для поля "Оклад"
 
Для поля оклад потрібно ввести обмеження, при якому у полі не можна вести число менше 700. Для цього клацніть два рази на компоненті Adotable1, виділіть поле Oklad і в його події Onvalidate уведіть код:
 
procedure Tform1.Adotable1Okladvalidate(Sender: Tfield);
begin
//якщо поле менше 700   
if adotable1.Fieldbyname('oklad').value<700 then
begin
//видаємо повідомлення про помилку       
application.Messagebox('Оклад не може бути менш 700 грн','Помилка введення',mb_ok+mb_iconstop);
//скасовуємо введення       
abort;
end;
end;
 
Редагування поточного запису в сітці співробітників буде проводиться за допомогою подвійного клацання на потрібному записі. При цьому буде відкриватися інша сторінкова форма (Form2). Для цього додайте в проект нову форму Form2. Виконайте команду Project-Options. На закладці Forms перенесіть форму Form2 у список Available Forms.
У коді першої форми підключіть модуль другої форми (Unit2) за допомогою команди File - Use Unit. У події Ondblclick компонента Dbgrid, напишемо код:
 
procedure Tform1.Dbgrid1Dblclick(Sender: Tobject);
begin
//переводимо таблицю в режим редагування
adotable1.Edit;
//створюємо й відкриваємо допоміжну сторінкову форму як модальну
form2:=tform2.create(nil);
form2.showmodal;
form2.Repaint;
end; 
Створення кнопок
 
Нанесіть на форму компонент Button (Standard). У властивості кнопки Caption укажіть текст Додати. Дана кнопка додає новий запис і відкриває її для редагування в іншій формі (Form2). Для кнопки напишемо код:
 
procedure Tform1.Button1Click(Sender: Tobject);
begin
//додаємо новий запис
adotable1.Insert;
//створюємо й відкриваємо допоміжну сторінкову форму як модальну
form2:=tform2.create(nil);
form2.showmodal;
form2.Repaint;
end;
 
Нанесіть на форму компонент Button (Standard). У властивості кнопки Caption укажіть текст Вилучити. Дана кнопка видає запит на видалення поточного запису й видаляє її. При цьому, якщо записів ні, то кнопка не реагує на натискання. Для кнопки напишемо код:
 
procedure Tform1.Button2Click(Sender: Tobject);
begin
//якщо число записів у таблиці не 0
if adotable1.Recordcount >0 then
//видаємо запит на видалення даних
if application.messagebox ('Вилучити запис?','Запит на видалення',mb_yesno+ mb_iconquestion)=idyes then
//видаляємо поточний запис
adotable1.delete
end;
 
Робота зі сторінковою формою
 
Форма Form2 буде створюватися в пам’яті динамічно, тому необхідно подбати про те, щоб при її закритті відбувалося коректне видалення форми в пам'яті. Для цього в події форми Onclose напишемо код:
 
procedure Tform2.Formclose(Sender: Tobject; var Action: Tcloseaction);
begin
//при закритті сторінкової форми вилучити її з пам'яті
action:=cafree;
end;
 
Для форми задайте властивості: Caption=Анкета, Borderstyle=bsdialog, Position=poownerform.
За допомогою команди File - Use Unit підключіть модуль головної форми (Unit1).
 
Додавання візуальних компонентів
 
На форму нанесіть 6 компонентів Dbedit (Datacontrols), один компонент Dbimage і один компонент Dblookupcombobox. Для кожного компонента у властивості Datasource укажіть значення Form1.Datasource1, у властивості Datafield укажіть ім'я поля, яке буде відображатися у відповідному візуальному компоненті.
Розмістіть компоненти так, як показано на зразку форми й підпишіть їх за допомогою компонента Label (Standard).
 
Заповнення поля Фото
 
Поле Фото містить зображення співробітника. Його заповнення будемо виконувати подвійним клацанням на компоненті Dbimage і вибираючи зображення за допомогою діалогу Openpicturedialog.
Для компонента Dbimage укажіть властивості: Datasource=Datasource1, Datafield=foto, Stretch=true.
Нанесіть на форму компонентів Openpicturedialog (Dialogs) і в події Ondblclick компонента Dbimage напишіть код:
 
procedure Tform2.Dbimage1Click(Sender: Tobject);
begin
//відкриваємо діалог вибору графічного файлу
if openpicturedialog1.Execute = true then
//завантажуємо в поле foto обраний файл
tblobfield(form1.adotable1.fieldbyname('foto')).loadfromfile(openpicturedialog1.Filename);
end;
 
Для використання функції tblodfield підключіть у коді форми модуль db.
 
Заповнення поля Дата народження
 
Поле Дата народження будемо заповнювати за допомогою календаря: компонента Datetimepicker (Win32). Нанесіть на форму компонент Datetimepicker, задайте йому властивість Visible=False і розмістіть його так, щоб він по розміру й положенню повністю збігався з полем Дата народження.
Як тільки користувач ставить курсор у поле Дата народження, на місці цього поля повинен з'являтися календар, і в календар завантажується та дата, яка відображається в полі Дата народження.
 
У події Onenter поля Дата народження напишемо код:
 
procedure Tform2.Dbedit5Enter(Sender: Tobject);
begin
//відображаємо календар
datetimepicker1.Visible:=true;
//відображаємо в календарі значення з поля (якщо поле не порожнє)
if dbedit5.text<>'' then
datetimepicker1.Date:=strtodate(dbedit5.text);
//становимо курсор в поле з календарем
datetimepicker1.setfocus;
end;
 
Як тільки користувач виходить із поля календаря, знову з'являється поле Дата народження й у ньому відображається дата, обрана в календарі. Для цього в події Onexit компонента Datatimepicker напишемо код:
 
procedure Tform2.Datetimepicker1Exit(Sender: Tobject);
begin
//робимо календар не видимим
datetimepicker1.Visible:=false;
//завантажуємо в поле обрану в календарі дату
dbedit5.text:=datetostr(datetimepicker1.Date);
end;
 
Створення поля-довідника посад
 
Поле Посада заповнюється за допомогою списку, що випадає. При цьому значення для списку беруться зі спеціальної таблиці-довідника Dolg. Для створення такого списку поле Посада повинне заповнюватися за допомогою компонента Dblookupcombobox (Datacontrols).
Спочатку потрібно підключити до форми таблицю Dolg.
Нанесіть на форму компонент Adotable (ADO). У властивості Connection виберіть ім'я з'єднання Form1.Adoconnection з головної форми, у властивості Tablename виберіть таблицю Dolg.
Для того, щоб програма коректно підключала таблицю в події форми Oncreate додайте код:
 
//підключаємо таблицю до програми
adotable1.Active:=true;
 
Для того, щоб програма коректно відключала таблицю в події форми Ondestroy додайте код:
 
//відключаємо таблицю від програми
adotable1.Active:=false;
 
Нанесіть на форму компонент Datasource (Dataaccess). У його властивості Dataset укажіть ім'я компонента Adotable1.
Для компонента Dblookupcombobox задайте властивості: Datasource - ім'я компонента Form1.Datasource; Datafield - поле, яке буде заповнюватися за допомогою списку (Посада); Listsource - ім'я компонента Datasource1; Keyfield - ім'я поля, значеннями якого буде заповнений список (Посада).
 
Створення кнопок
 
Нанесіть на форму компонент Button (Standard). У властивості Caption укажіть текст Зберегти. Дана кнопка повинна зберігати внесені зміни й закривати сторінкову форму. При цьому, якщо ключове поле Табельний номер не заповнене, то збереження запису неможливо. Для кнопки напишемо код:
 
procedure Tform2.Button1Click(Sender: Tobject);
begin
//якщо поле Табельний номер не порожнє
if dbedit1.text<>'' then
begin
//зберігаємо запис
form1.adotable1.post;
//закриваємо сторінкову форму
close;
end
//якщо поле Табельний номер порожнє
else
begin
//видаємо повідомлення про помилку
application.messagebox('Табельний номер не може бути порожнім','Помилка введення!',mb_ok+mb_iconstop);
//ставимо курсор у поле Табельний номер
dbedit1.Setfocus;
end;
end;
 
Нанесіть на форму компонент Button (Standard). У властивості Caption укажіть текст Скасувати. Дана кнопка повинна скасовувати внесені зміни й закривати сторінкову форму. Для кнопки напишемо код:
 
procedure Tform2.Button2Click(Sender: Tobject);
begin
//скасовуємо зміни
form1.adotable1.cancel;
//закриваємо сторінкову форму
close;
end;
Практическое занятие № 9
Тема: "Сортировка и фильтрация данных в таблицах (на примере СУБД MySQL)"
Цель работы: получить практические навыки по выполнению сортировки и фильтрации данных в разных СУБД
 
Ход работы
 
На сервере MySQL разместите базу данных (скачать), которая содержит таблицу sotr со следующей структурой:
 
Имя поля Тип Размер
tabnom счетчик ключевое
fam varchar 20
imya varchar 15
otch varchar 20
datar date  
oklad float 2 знака после запятой
 
Указания: разархивируйте содержимое архива и скопируйте папку baza в общую папку для хранения БД на сервере MySQL (в Windows XP по умолчанию эта папка имеет имя "C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data", в Windows 7 эта папка имеет имя "C:\Program Data").
Для проверки доступа к БД запустите утилиту "SQL Manager for MySQL", щелкните на кнопке "Зарагестрировать базу данныз". В окне регистрации введите параметри подключения: Хост=localhost, Порт=3306, Пользователь=root, Пароль=111 и щелкните на кнопке Далее.
В следующем окне в списке "Имя базы данных" выберите вашу скопированную БД "baza", в поле Кодировка выберите кодировку "utf8".
В левой части окна программы отобразится подключенная БД, которую можно открыть двойным щелчком мыши. В папке "Таблицы" двойным щелчком можно открыть таблицу "sotr" и в правой части на закладке "Данные" просмотреть ее содержимое.
 
В среде Delphi создайте программу для работы с данными таблицы. При этом форма должна иметь вид:
 

 
Указания: для форми задайте свойства: Caption=Список сотрудников, Position=DesktopCenter, Borderstyle=bsSingle, Height=340.
Для подключения БД MySQL нужно использовать специальный ODBC драйвер (скачать).
Нанесите на форму компонент ADOConnection (ADO) и задайте свойство ConnectionString с помощью мастера:
 
На первом шаге укажите драйвер Microsoft OLE DB Provider for ODBC Driver
 

 
На втором шаге выберите переключатель "Использовать строку подключения" и щелкнгите на кнопке "Сборка".
 

 
В следующем окне выберите файл подключения, который вы могли создать ранее или щелкните на кнопке Создать для создания такого файла.
На следующем шаге выберите драйвер БД "MySQL ODBC 5.1 Driver".
 

 
На следующем шаге введите имя для файла подключения.
 

 
В новом окне укажите параметры подключения как показано на рисунке (пароль 111).
 

 
На форму нанесите компонент ADOTable (Data Access). Для компонента задайте свойства: Connection = ADOConnection1, TableName = sotr. Двойным щелчком на компоненте откройте редактор полей. Поля переименуйте и задайте нужную ширину.
 
Для подключения к таблице в событии OnCreate формы введите код:
 
procedure Tform1.Formcreate(Sender: Tobject);
begin
    adotable1.Active:=true;
end;  
 
Для отключения от БД при закрытии программы в событии OnDestroy формы введите код:
 
procedure Tform1.FormDestroy(Sender: Tobject);
begin
    adoconnection1,connected:=false;
end;
 
Нанесите на форму компонент DataSource (DataAccess). Установите для него свойство DataSet =ADOTable1.
Нанесите на форму компонент  DbGrid (DataControls).  Установите для него свойство DataSource=DataSource1.
 
Данные в сетке можно сортировать с помощью щелчков на заголовках колонок сетки.
 
Указания: для организации сортировки в сетке в событии OnTitleClick сетки введите код:
 
procedure Tform1.Dbgrid1Titleclick(Column: Tcolumn);
begin
    //если сетка отсортирована по убыванию
    if adotable1.Indexfieldnames=column.Fieldname+' DESC' then
        //сортируем по возрастанию       
        adotable1.Indexfieldnames:=column.Fieldname
    else
        //иначе сортируем по убыванию      
        adotable1.Indexfieldnames:=column.Fieldname+' DESC';
end;
 
На форме разместите кнопку, которая увеличивает форму по высоте и отображает поля для ввода параметров поиска. Такая форма будет иметь вид:
 
 
 
Указания: на форму добавьте кнопку Button (Standard) и задайте свойство Caption=Знайти. Кнопка должна увеличить высоту формы и отобразить поля для ввода ключей поиска данных. Для этого в событии OnClick кнопки введите код:
 
procedure Tform1.Button1Click(Sender: Tobject);
begin
    //постепенно увеличиваем высоту формы до 480 толчек 
    while height<480 do
    begin   
        //увеличиваем высоту с шагом в 5 точек  
        height:=height+5;
        //центрируем форму по вертикали    
        top:=(screen.height-height) div 2;
    end;
    //ставим курсор в первое поле для ввода критериев поиска
    edit1.Setfocus;
end;
 
Пользователь может произвольно заполнять нужные поля для поиска. Поля "Дата от" и "Дата до" заполняются с помощью календаря (DateTimePicker).Поиск по дате рождения и окладу выполняется по диапазону значений.
 
Указания: увеличьте высоту формы, задав для нее свойство Height=480. На форму нанесите 8 компонентов Edit (Standard). Разместите и подпишите их так, как показано на рисунке в задании.
Для полей задания диапазона дат нужно использовать компоненты DateTimePicker. Добавьте на форму два компонента DateTimePicker (Win32), задайте им такой же размер, который имеют соответствующие компоненты Edit, задайте им свойство Visible=false, разместите их поверх соответссующих текстовых полей.
Для комбинации календаря с полем для текстового поля "Дата от" событии OnEnter введите код:
 
procedure Tform1.Edit5Enter(Sender: Tobject);
begin
    //делаем календарь видимым   
    datetimepicker1.Visible:=true;
    //ставим курсор в поле с календарем
    datetimepicker1.setfocus;
end;
 
Для календаря, размещенного над полем "Дата от", в событии  OnExit введите код:
 
procedure Tform1.Datetimepicker1Exit(Sender: Tobject);
begin
      //делаем календарь невидимым
    datetimepicker1.Visible:=false;
    //в поле записываем выбранную дату
    edit5.Text:=datetostr(datetimepicker1.date);
end;
 
Аналогично для поля "Дата до" в событии OnEnter введите код:
 
procedure Tform1.Edit6Enter(Sender: Tobject);
begin
    //делаем календарь видимым   
    datetimepicker2.Visible:=true;
    //ставим курсор в поле с календарем
    datetimepicker2.setfocus;
end;  
 
Аналогично для календаря, размещенного над полем "Дата до", в событии OnExit введите код:
 
procedure Tform1.Datetimepicker2Exit(Sender: Tobject);
begin
    //делаем календарь невидимым   
    datetimepicker2.Visible:=false;
    //в поле записываем выбранную дату
    edit6.Text:=datetostr(datetimepicker2.date);
end;
 
Кнопка "Отобрать" фильтрует данные в таблице.
 
Указания: для фильтрации будем использовать компонент ADOQuery (ADO), который нужно разместить на форме. Задайте для него свойства: Connection=ADOConnection1, в свойстве SQL введите текст запроса:
 
select * from baza.sort
 
Запрос нужен для того, чтобы двойным щелчком на компоненте вы могли добавить и настроить параметры полей в отобранном наборе данных.
 
Нанесите на форму кнопку Button (Standard) и задайте свойство Caption=Отобрать. Кнопка отбирает в сетке записи в соответствии с заданными условиями поиска. Для кнопки введите код:
 
procedure Tform1.Button2Click(Sender: Tobject);
//переменная для формирования условия поиска
var s:string;
begin
    //сначала условие поиска не задано
    s:='';
 
    //задаем условие поиска для поля "tabnom" (числовое)
    if edit1.text<>'' then
        s:=s+'tabnom ='+edit1.Text;
 
    //задаем условие поиска для поля "fam" (текстовое)
    if edit2.text<>'' then
        if s<>'' then
            s:=s+' and fam like '''+edit2.Text+'%'''
        else
            s:=s+'fam like '''+edit2.Text+'%''';
 
    //задаем условие поиска для поля "imya" (текстовое)
    if edit3.text<>'' then
        if s<>'' then
            s:=s+' and imya like '''+edit3.Text+'%'''
        else
            s:=s+'imya like '''+edit3.Text+'%''';
 
    //задаем условие поиска для поля "otch" (текстовое)
    if edit4.text<>'' then
        if s<>'' then
            s:=s+' and otch like '''+edit4.Text+'%'''
        else
            s:=s+'otch like '''+edit4.Text+'%''';
 
    //задаем условие поиска для поля "datar" (дата от) (дата/время)
    //обратите внимание на то, что содержимое поля Edit5 конвертируется
    //в формат представления дат в MySQL: 'yyyy-mm-dd'
    if edit5.text<>'' then
        if s<>'' then
            s:=s+' and datar >= '''+formatdatetime('yyyy-mm-dd',strtodate(edit5.text))+''''
        else
            s:=s+'datar >= '''+formatdatetime('yyyy-mm-dd',strtodate(edit5.text))+'''';
 
   
    //задаем условие поиска для поля "datar" (дата до) (дата/время)
    //обратите внимание на то, что содержимое поля Edit6 конвертируется
    //в формат представления дат в MySQL: 'yyyy-mm-dd'
    if edit6.text<>'' then
        if s<>'' then
            s:=s+' and datar <= '''+formatdatetime('yyyy-mm-dd',strtodate(edit6.text))+''''
        else
            s:=s+'datar <= '''+formatdatetime('yyyy-mm-dd',strtodate(edit6.text))+'''';
 
    //задаем условие поиска для поля "oklad" (оклад от) (числовое)
    if edit7.text<>'' then
        if s<>'' then
            s:=s+' and oklad >= '+edit7.Text
        else
            s:=s+'oklad >= '+edit7.Text;
 
    //задаем условие поиска для поля "oklad" (оклад до) (числовое)
    if edit8.text<>'' then
        if s<>'' then
            s:=s+' and oklad <= '+edit8.Text
        else
            s:=s+'oklad <= '+edit8.Text;
 
    //если условие поиска не задано завершаем работу процедурі
    if s='' then exit;
 
    //формируем текст запроса текст запиту   
    adoquery1.Active:=false;
    adoquery1.sql.text:='select * from sotr where '+s;
    //активируем запрос (отбираем данные)   
    adoquery1.Active:=true;
    //подключаем запрос к сетке (для отображения найденных данных)   
    datasource1.Dataset:=adoquery1;
end;
 
Кнопка "Очистить" очищает все поля критериев поиска и в сетке отображает все записи.
 
Указания: добавьте на форму кнопку Button (Standard). Для кнопки напишем код:
 
procedure Tform1.Button3Click(Sender: Tobject);
begin
    //очищаем все поля
    edit1.Clear;
    edit2.Clear;
    edit3.Clear;
    edit4.Clear;
    edit5.Clear;
    edit6.Clear;
    edit7.Clear;
    edit8.Clear;
    edit1.Setfocus;
    //подключаем таблицу к сетке (для отображения всех данных)
    datasource1.Dataset:=adotable1;
end;
 
Кнопка "Скрыть" проводит очистку всех полей, отображает все записи в сетке и возвращает форму в начальный размер по высоте.
 
Указания: нанесите на форму кнопку Button (Standard). Для кнопки напишіть код:
 
procedure Tform1.Button4Click(Sender: Tobject);
begin
    //вызываем процедуру для кнопки "Очистить" 
    Button3Click(Sender);
    //постепенно уменьшаем размер формы 
    while height>340 do
    begin   
        //уменьшаем размер формы на 5 пикселей  
        height:=height-5;
        //центрируем форму по вертикали по центру экрана   
        top:=(screen.height-height) div 2;
    end;
    //ставим курсор в сетку   
    dbgrid1.Setfocus;
end;
 
Скопируйте папку с созданным проектом и переделайте ее для работы с БД Access (скачать).
 
Указания: внесите изменения в свойство ADOConnection.ConnectionString, задав в качетве БД файл Access. Также для компонента ADOConnectionвыключите свойство LoginPrompt (регистрация не нужна).
Для кнопки "Найти" внесите изменения в формирование условий для полей "Дата от" и "Дата до" приведя содержимое эьтих полей к формату представления дат в Access.
 
 
//задаем условие поиска для поля "datar" (дата от) (дата/время)
//обратите внимание на то, что содержимое поля Edit5 конвертируется
//в формат представления дат в Access: #mm/dd/yyyy# (без кавычек)
if edit5.text<>'' then
        if s<>'' then
            s:=s+' and datar >= '+formatdatetime('#mm"/"dd"/"yyyy#',strtodate(edit5.text))
        else
            s:=s+'datar >= '+formatdatetime('#mm"/"dd"/"yyyy#',strtodate(edit5.text))
 
//задаем условие поиска для поля "datar" (дата до) (дата/время)
//обратите внимание на то, что содержимое поля Edit6 конвертируется
//в формат представления дат в Access: #mm/dd/yyyy# (без кавычек)
if edit6.text<>'' then
        if s<>'' then
            s:=s+' and datar <= '+formatdatetime('#mm"/"dd"/"yyyy#',strtodate(edit6.text))
        else
            s:=s+'datar <= '+formatdatetime('#mm"/"dd"/"yyyy#',strtodate(edit6.text))
 
Практичне заняття № 10
Тема: «Работа с сеткой Dbgrid в Delphi»
Цель работи: получить практические навыки для работы с сеткой Dbgrid
 
Ход работы
 
В среде Delphi создайте программу для работы с данными таблицы из БД "personal". При этом форма должна иметь вид:
 
 
 
В сетке отображаются все поля кроме поля "foto". Все поля должны иметь название по-русски и приемлемую ширину колонок.
 
Указания: для главной форме задайте свойства: Caption="Работа с сеткой DBGrid", Position="Desktopcenter", Borderstyle="bssingle". На форму нанесите компонент Adoconnection (ADO). В свойстве Connectionstring укажите параметры подключения к БД Access. В свойстве Loginprompt укажите false, чтобы программа не запрашивала логин и пароль при соединении с БД.
Нанесить на форму компонент Adotable (ADO). В свойстве Connection укажите соединение с БД Adoconnection1, в свойствеTablename укажите таблицу Sotr.
 
Для того, чтобы програма корректно подключала таблицу в событии форми Oncreate введите код:
 
procedure TForm1.FormCreate(Sender: TObject);
begin
    adotable1.Active:=true;
end;
 
Для того, чтобы программа корректно отключала таблицу в свойстве формы Ondestroy введите код:
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
    adoconnection1.connected:=false;
end;
 
Двойным щелчком на компоненте Adotable, в контекстном меню окна выберите команду Add All Fields. В результаьте в окне появится список полей таблицы. По очереди виделяйте каждое поле и в свойстве Displaylabel укажите название поля в сетке, а в поле Displaywidth укажите ширину поля в символах.
 
Проектирование сетки
Нанесите на форму компонент Datasource (Dataaccess). Задайте для него свойство Dataset =Adotable1.
Нанесите на форму компонент Dbgrid (Datacontrols). В свойстве Datasource укажите имя компонента Datasource1. Щелкните два раза на компоненте Dbgrid. В окне вызовите контекстное меню и выберите команду Add All Fields. В результате в окне отобразится список полей таблицы. Для поля "Foto" узадайте свойство Visible=true.
Нанесите на форму компонентов Dbnavigator (Datacontrols). Задайте свойство Datasource=Datasource1.
Для виравнивания компонентов на форме для компонента Dbnavigator задайте свойство Align = albottom, для компонента Dbgrid свойство Align = alclient.
 
Для поля "dolg" (Должность) создайте список с перечнем имеющихся в поле значений
 
Указания: нанесите на форму компонент Adoquery (ADO). Задайте свойство Connection=Adoconnection1. При щелчке на ячейке в колонке "Dolg" должен формироваться и открываться список уже имеющихся значений этого поля.
Для формирования перечня значений из поля будет использовать запрос.
Нанесите на форму компонент ADOQuery (ADO) и задайте свойства: Connection = ADOConnection1, SQL = 'select distinct dolg from sotr'
 
В событии Oncellclick сетки напишите код:
 
procedure TForm1.DBGrid1CellClick(Column: TColumn);
var i:integer;
begin
    //если пользователь щелкнул в ячейке поля "dolg"
    if dbgrid1.Columns[dbgrid1.Selectedindex].Fieldname='dolg' then
    begin
    //открываем запрос, отбирая перечень значений для списка
    adoquery1.Active:=true;
    //в поле очищаем старый список
    dbgrid1.Columns[dbgrid1.Selectedindex].Picklist.Clear;
    //в цикле проходим по всем значениям отобранного набора
    while not adoquery1.eof do
    begin
    //добавялем в список очередное значение
    dbgrid1.Columns[dbgrid1.Selectedindex].Picklist.Add(adoquery1.fieldbyname('dolg').asstring);
    //переходим на следующее значение
    adoquery1.Next;
    end;
//закриваем запрос
adoquery1.Active:=false;
end;
 
В ячейке колонки "Дата рождения" отображается кнопка с троеточием, с помощью которой открывается вспомагательная форма с календарем:
 
 
 
Указания: для отображения кнопки с троеточием двойным щелчком на сетке откройте список колонок, выделите колонку Datar и задайте свойства:ReadOnly=true; ButtonStyle=cbsEllipsis.
Для редактирования поля "Datar" создадим новую форму. Чтобы форма не создавалась автоматически при запуске програмы виполните команду Project - Options и перенесите форму  в список Available Forms. Для новой формы задайте свойства: Borderstyle=bsNone,   Position = poOwnerFormCenter.
Нанесите на форму компонент MonthCalendar (Win32)  и две кнопки. Для календаря задайте властивість Align = alTop.
При открытии этой форми в календаре должна отображаться дата из поля "Datar" сетки. Для этого в событии Oncreate форми введите код:
 
procedure TForm2.FormCreate(Sender: TObject);
begin
//если поле "Datar" не пустое
if form1.Adotable1.fieldbyname('datar').asstring<>'' then
//в календаре отображаем значение этого поля   
monthcalendar1.Date:=form1.Adotable1.fieldbyname('datar').value
//если поле "Datar" пустое
else
//в календаре отображаєм текущую дату
monthcalendar1.Date:=date;
end;
 
Кнопка "ОК" закривает форму, а в поле "Datar" сетки отображается выбранная дата. Для этого для кнопки напишем код:
 
procedure TForm2.Button1Click(Sender: TObject);
begin
    //в поле сетки отображаем выбранную дату
    form1.Adotable1.fieldbyname('datar').Value:=monthcalendar1.Date;
    //переходим в поле "datar"
    form1.adotable1.Fieldbyname('datar').Focuscontrol;
    //закриваем форму
    close;
end;
 
Кнопка "Отменить" закрывает форму не внося изменений в поле сетки. Для кнопки напишем код:
 
procedure TForm2.Button2Click(Sender: TObject);
begin
    //переходим на поле "datar"
    form1.adotable1.Fieldbyname('datar').Focuscontrol;
    //закриваем форму
    close;
end;
 
При закритии формы с календарем форма должна удаляться из памяти. У событии формы Onclose введите код:
 
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    action:=cafree;
 end;
 
При щелчке на кнопке с тремя точками должна открываться созданная вами форма с календарем. Для этого в событие OnEditButtonClick сетки введите код:
 
procedure TForm1.DBGrid1EditButtonClick(Sender: TObject);
begin
    //если пользователь щелкнул в ячейке поля "datar"
    if dbgrid1.Columns[dbgrid1.Selectedindex].Fieldname='datar' then
    begin
    //переводим таблицу в режим редактирования
    adotable1.Edit;
    //создаем и открываем форму Form2
    form2:=tform2.create(self);
    form2.showmodal;
    end;
end;
 
В сетке создайте специальную колонку для отображения состояния поля "Foto". Если поле заполнено (имеется поле), то в колонке отображается одна картинка, иначе - другая.
 
Указания: для добавления пустой колонки щелкните на сетке два раза. В контекстном меню окна выберите команду Add. Для созданной колонки задайте свойства: FieldName=pict, TitleCaption = Пробел.
Для хранения иконок нанесите на форму компонент Imagelist (Win32). Двойным щелчком откройте этот компонент и с помощью кнопки Add добавьте в него нужные рисунки.
Для оборажения рисунков в ячейках созданной колонки в событии OnDrawColumnCell опишите переменную:
 
 var p:tbitmap;
 
и добавьте код:
 
//если заголовок колонки равен пробелу (наша новая ячейка)
if column.Title.Click =' ' then
begin
//создаем в памяти переменную для считывания картинки
p:=tbitmap.create;
//если поле "foto" не пустое
if not adotable1.FieldByName('foto').isnull then
    //считываем первую картинку (нумерация с 0)
    imagelist1.Getbitmap(0,p)
//иначе, если поле "foto" не пустое
else
    //считываем вторую картинку
    imagelist1.Getbitmap(1,p);
//отображаем считанную картинку в ячейке колонки
dbgrid1.canvas.draw(rect.Left,rect.Top,p);
end;
 
В сетке выполните условной форматирование строк по правилу: строки с окладом до 1500 обозначаются одним цветом, а более 1500 - другим.
 
Указания: в событии DrawColumnCell сетки введите код:
 
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;DataCol: Integer; Column: TColumn; State:TGridDrawState);
begin
    //если поле "oklad" менее 1500
    if adotable1.Fieldbyname('oklad').value<1500 then
        //для сетки задаем один цвет фона
        dbgrid1.canvas.brush.color:=$00FFAFC8
    else
        //иначе задаем другой цвет фона
        dbgrid1.canvas.brush.color:=$00A5FFB6;
    //заливаем строку указанным цветом фона
    dbgrid1.canvas.fillrect(rect);
 
    //после заливки весь текст становится невидимым (залитым фоном)
    //нужно заново вывести весь текст в колонках
    //при этом колонка с рисунком не имеет текста и ее нужно пропустить
 
    //если заголовок текущей колонки = ' ' (не колонка с рисунком)
    if column.Title.Click <> ' ' then
        //выводим в ней текст  
        dbgrid1.canvas.textout(rect.left+2,rect.top+2,column.field.text);
end;
 
При щелчке на иконке нужно отображать окно для просмотра и редактирования поля "Foto".
 

 
Указания: добавьте новую форму. Чтобы форма не создавалась автоматически при запуске программы выполните команду Project - Options и перенесите форму в списокAvailable Forms. Для новой формы задайте свойства: Caption=Фото, Position = poOwnerFormCenter. С помощью команды File - Use Unit подключите модуль главной формы Unit1.
Нанесите на форму компонент Dbimage(DataControls) и две кнопки.
Для Dbimage задайте свойства: DataSource=Form1.Datasource, DataField=foto, Align=alTop, Stretch=true.
 Кнопка "Изменить"  открыввет диалог выбора файла и записывает указанный фавйл в поле "foto". Для этого навнесите на форму компонент OpenPictureDalog (Dialogs). В свойстве Filter оставьте токо формат *.bmp. Для кнопки напишите код:
 
procedure TForm3.Button1Click(Sender: TObject);
begin
if openpicturedialog1.Execute then        
//загружаем в поле "foto" выбранный файл    
tblobfield(form1.Adotable1.fieldbyname('foto')).Loadfromfile(openpicturedialog1.filename);
end;
 
Для роботи функции  TBlobFeld подключите модуль DB.
 
Кнопка "Очистить" очищает содержимое поля. Для кнопки напишите код:
 
procedure TForm3.Button2Click(Sender: TObject);
begin
    tblobfield(form1.Adotable1.fieldbyname('foto')).Clear;
end;
 
При закритии форми нужно форму удалить из памяти. Для этого в событии Onclose формы введите код:
 
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    action:=cafree;
end; 
 
Созданная форма должна появляться после щелчка пользователем в ячейке с картинкой. Для этого в событии OnCellClick сетки добавьте код: 
 
//если щелкнули в ячейке с картинкой (заголовок колоник = ' ')
if column.Title.Click = ' ' then
begin
//переводим таблицe в ht;bv редактирования
adotable1.Edit;
//создаем и открываем форму Form3
form3:=tform3.create(self);
form3.showmodal;
end;
 
В программе реализовать сохранение и восстановление таких параметров сетки как: порядок, ширина и заголовок колонок.
 
Указания: для работы с реестром подключите модуль Registry.
 
Для сохранения параметров колонок сетки в событии Onclose формы введите код:
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
//вначале опишите переменную для работы с реестром и счетчик цикла
var reg:tregistry; i:integer;
begin
//создаем объект для работы с реестром 
reg:=tregistry.create;
//задаем текущий раздел реестра   
reg.rootkey:=hkey_local_machine;
//в цикле проходим по всем колонкам сетки 
for i:=0 to dbgrid1.Columns.Count-1 do
begin
//создаем или открываем в реестре раздел для i-й колонки
reg.Openkey('\software\myprogram\dbgrid\col'+inttostr(i),true);
//записуем в реестр параметры сетки   
reg.writestring('field',dbgrid1.columns.items[i].fieldname);
reg.writeinteger('width',dbgrid1.columns[i].width);
reg.writestring('caption',dbgrid1.columns[i].title.caption);
end;
//удаляем из памяти объект для работы с реестром
reg.free;  
end;
 
При запуске программы из реестра нужно считывать сохраненные данные. Для этого в событие Oncreate главной формы добавьте код:
 
 
//вначале опишите переменную для работы с реестром и счетчик цикла
var reg:tregistry; i:integer;
 
//в код события добавьте команды
 
//создаем объект для работы с реестром
reg:=tregistry.create;
//задаем текущий раздел реестра
reg.rootkey:=hkey_local_machine;
//если в реестре существует указанная ветка
if reg.keyexists('software\myprogram\dbgrid') then
    begin
    //в цикле проходим по всем колонкам сетки
    for i:=0 to dbgrid1.Columns.Count-1 do
    begin
        //открываем в реестре раздел для i-й колонки
        reg.Openkey('\software\myprogram\dbgrid\col'+inttostr(i),true);
        //применяем к колнке сетки считанные параметры
        dbgrid1.columns[i].fieldname:=reg.readstring('field');
        dbgrid1.columns[i].width:=reg.readinteger('Width');
        dbgrid1.columns[i].title.caption:=reg.readstring('caption');
    end;
end;
//удаляем из памяти объект для работы с реестром
reg.Free;
end;
 
Запустите программу измените порядок и ширину колонок в сетке. Перезапустите программу и убедитесь, что параметры восстанавливаются корректно.
Практическое занятие № 11
Тема: "Обработка таблиц с помощью запросов"
Цель работи: получить практические навыки по использованию запросов разных типов при работе с БД
 
Ход работы
 
1. На сервере MySQL разместите базу даних "baza", которая содержит таблицы grupy и students, связанные по полю id_grup.
 
Таблица grupy иммет структуру:
Имя поля Тип Размер
id_grup integer ключевое, счетчик
grup_sokr varchar 3
grup varchar 20
klruk varchar 50
kurs integer  
Таблица students имеет структуру:
 
Имя поля Тип Размер
inn integer ключевое
fam varchar 15
imya varchar 15
otch varchar 15
datar date  
srbal decimal 2 знака после запятой
id_grup integer для связывания
 
Указания: распакуйте архив и скопируйте его содержимое в общую папку для хранения БД MySQL (по умолчанию эта папка имеет имя "C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data").
Для проверки доступа к БД зхапустите утилиту "SQL Manager for MySQL", щелкнитое на кнопке "Зарегестрировать БД". В окне регистрации введите параметры подключения к серверу: Хост=localhost, Порт=3306, Пользователь=root, Пароль=111 и щелкните на кнопке Далее.
В следующем окне с списке "Имя базы данных" выберите БД "baza", в списке "Кодировка клиента" выберите кодировку "utf8". После задания всех параметров щелкните на кнопке Готово.
В левой части окна отобразится подключенная БД, которую двойным щелчком можно открыть для работы. После открытия БД двойным щелчком можно открыть входящие в нее таблицы и в правой части просмотреть их содержимое.
Если все операции выполнены успешно и БД находиьтся на сервере, то можно приступать к созданию приложения.
 
2. В среде Delphi создайте программу для работы с данными таблиц. При этом форма должна иметь вид:
 

 
 
Указания: для формы задайте свойства: Caption=Работа с запросами, Position=DesktopCenter, Borderstyle=bsSingle, BorderIcons-biMaximized=false (скрывает кнопку разворачивания на весь экран).
Для подключения БД MySQL нужно использовать специальный ODBC драйвер (скачать).
Нанесите на форму компонент ADOConnection (ADO) и задайте свойство ConnectionString с помощью мастера:
 
На первом шаге укажите драйвер Microsoft OLE DB Provider for ODBC Driver
 

 
На втором шаге выберите переключатель "Использовать строку подключения" и щелкнгите на кнопке "Сборка".
 

 
В следующем окне выберите файл подключения, который вы могли создать ранее или щелкните на кнопке Создать для создания такого файла.
На следующем шаге выберите драйвер БД "MySQL ODBC 5.1 Driver".
 

 
На следующем шаге введите имя для файла подключения.
 

 
В новом окне укажите параметры подключения как показано на рисунке (пароль 111).
 

 
Подключение главной таблицы
 
По умолчанию главная таблица будет просматриваться с помощью запросов порциями по 10 записей.
На форму нанесите компонент ADOQuery (ADO). Для компонента задайте свойства : Connection=ADOConnection1, sql = select * from grupy
Добавьте в компонент все поля. Для полей задайте понятные названия и нужную ширину. Поле id_grup является счетчиком (заполняется автоматически), поэтому его можно не заполнять (Visible=false).
Нанесите на форму компонент DataSource (DataAccess). Установите его свойство DataSet =ADOQuery1.
Нанесите на форму компонент DBGrid (DataControls). В свойстве DataSource укажите имя компонента DataSource1.
 
Для отображения данных с помощью запроса, в событии формы OnCreate введите код:
 
procedure Tform1.Formcreate(Sender: Tobject);
begin
    //формируем запрос на выборку записей, количество которых за умолчанием
    //равно 10, и сортируем записи по полю grup  
    adoquery1.Active:=false;        adoquery1.SQL.Clear;
    //параметр limit указывает, что начинаем отбор с нулевой записи и всего 10 записей        adoquery1.SQL.Add('select * from grupy order by grup limit 0,10');        //активируем запрос на выборку данных
    adoquery1.Active:=true;
end;  
 
Для того, чтобы  програма корректно отключалась от БД , в событии формы OnDestroy введите код:
 
procedure Tform1.FormDestroy(Sender: Tobject);
begin
    adoconnection1.connected:=false;
end;
 
Подключение подчиненной таблицы
 
По умолчанию подчиненная таблица отображает только те записи, которые соответствую группе, выбранной в главной таблице. Здесь будем показывать все подчиненные записи, поэтому будем пользоваться не запросом, а таблицей.
На форму нанесите компонент ADOQuery (ADO). Для компонента задайте свойства: Connection=ADOConnection1, TableName=students
Добавьте в таблицу все поля, переименуйте и задайте нужную ширину. Поле id_grup связано с полем главной таблицы головної таблиці (заповнюється автоматично), тому його можна не відображати (Visible=false).
Нанесите на форму компонент DataSource (DataAccess). Установите его свойство DataSet =ADOTable1.
Нанесите на форму компонент DBGrid (DataControls). В свойстве DataSource укажите имя компонента DataSource2.
 
В событие OnCreate формы добавьте команду:
     
adotable1.Active:=true;
 
Для корректного отображения связанных данных в подчиненной таблице видылите колмпонент ADOTable1 (соответсвует связанной таблице) и задайте свойства: MasterSource=DataSource1 (главная таблица на основе запроса), MasterFields= id_grup=id_grup.
 
Каждая сетка DBGrid по умолчанию поддерживает специальные клавиши: Insert - додавить новую запись над текущей, Ctrl+Delete - удалить текущую запись(можете проверить эти возможности). Нужно заблокировать эти клавиши:
 
Указания: для того, чтобы форма могла реагировать и обрабатывать нажатия клавиш установите для формы свойство KeyPreview=true.
Для форми в событии OnKeyDown напишем код:
 
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);    begin        //если в момент нажатия на клавиши одна из сеток активна
    if (dbgrid1.focused=true) or (dbgrid2.focused=true) then            //если нажата клавиша insert
        //или клавиши ctrl+insert
        if (key=vk_insert) or (key=vk_delete) and (ssctrl in shift) then                //то это нажатие игнироруется         
            abort;    end;
 
По умолчанию сетка DBGrid не поддерживает просмотр записей с помощью колеса мыши  (можете проверить это утверждение). Нужно исправить этот недостаток.
 
Указания: нанесите на форму компонент ApplicationEvents (Additional)  и в его событии OnMessage введите код:
 
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;var Handled: Boolean);    var    i: SmallInt;    begin        //если одна из сеток активна
    if (dbgrid1.Focused = true) or (dbgrid2.Focused = true) then            //если наступает событие прокрутки колеса мыши
        if Msg.message = WM_MOUSEWHEEL then            begin                //то это событие подменяется событием прокрутки
            //с помощью клавиш "вверх" или "вниз"
            Msg.message := WM_KEYDOWN;                Msg.lParam := 0;                i := HiWord(Msg.wParam) ;                if i > 0 then                    Msg.wParam := VK_UP                else                    Msg.wParam := VK_DOWN;                Handled := False;            end;    end;
 
Под каждой из сеток добавим кнопки для добавления и удаления данных.
 
Указания: под главной сеткой разместите два компонента Button (Standard) и в свойствеCaption введите текст надписей на кнопках.
Для кнопки "Добавить" введить код:
 
procedure TForm1.Button1Click(Sender: TObject);
begin
    //добавляем новую запись
    adoquery1.Append;
    //ставим курсор в поле grup_sokr (первое поле в сетке)   
    adoquery1.FieldByName('grup_sokr').FocusControl;
end;
 
Для кнопки "Удалить" напишем код:
 
procedure TForm1.Button2Click(Sender: TObject);
begin
    //если поле id_grup не пустое (то есть есть записи для удаления)
    if adoquery1.FieldByName('id_grup').asstring<>'' then
        //показываем запрос на удаление
        if application.MessageBox(pchar('Удалить группу '''+adoquery1.FieldByName('grup').AsString+'''?'),
                                        'Подтвердите',mb_yesno+mb_iconquestion)=idyes then
        //если ответ положительный, то удаляем запись
        adoquery1.Delete;
end;
 
Под подчиненной сеткой разместите два компонента Button (Standard) и в свойстве Caption введите текст надписей на кнопках.
Для кнопки "Добавить" введить код:
 
procedure TForm1.Button3Click(Sender: TObject);    begin        //добавляем новую запись
    adotable1.Append;
    //ставим курсор в поле inn (первое поле в сетке)   
    adotable1.FieldByName('inn').FocusControl;
    end;
 
Для кнопки "Удалить" напишем код:
 
procedure TForm1.Button4Click(Sender: TObject);    begin
    //если поле inn не пустое (то есть есть записи для удаления)
    if adotable1.FieldByName('inn').asstring<>'' then
        //показываем запрос на удаление            if application.MessageBox(pchar('Видалити студента '''+            adotable1.FieldByName('fam').AsString+' '+            adotable1.FieldByName('imya').AsString+' '+            adotable1.FieldByName('otch').AsString+            '''?'),'Підтвердьте',mb_yesno+mb_iconquestion)=idyes then
            //если ответ положительный, то удаляем запись                adotable1.Delete;    end;
 
Реализуем просмотр данных по группам или целым списком. На форме создайте группу переключателей.
 

 
Если выбран первый переключатель (выбран по умолчанию), то в подчиненной сетке отображаются связанные данные. Если выбран второй переключатель, то в подчиненной сетке отображаются све записи одним списком без привязки к главной таблице.
 
Указания: добавьте на форму компонент RadioGroup (Standard) і задайте свойства Caption=Режим просмотра, Columns=2 (количество колонок), Items -названия переключателей, ItemIndex=0 (первый переключатель включен по умолчанию).
В событии OnClick компонента напишем код:
 
procedure TForm1.RadioGroup1Click(Sender: TObject);    begin               
    case radiogroup1.ItemIndex of            //если выбран первый переключатель
        //для  подчиненной таблицы задаем связывание с главной
        0: adotable1.mastersource:=datasource1;            //если выбран второй переключатель
        //для подчиненной таблицы удаляем связь с главной таблицей
        1: adotable1.mastersource:=nil;        end;    end;
 
Реализуем просмотр данных из главной таблицы порциями, размер которых введен в поле Edit1.
Для этого на форме создайте набор компонентов вида
 

 
В поле можно указать размер порции. Кнопки переходят по порциям. Предусмолтрать блокировку кнопок при отображении первой или последней порции.
 
Указания: нанесите на форму необходимые компоненты. Так как при старте отображается перавая порция, то идти назад некуда и кнопка "Назад" заблокирована (Enabled=false).
 
Для выполнения поставленной задачи опишем две глобальные переменные
//переменная для хранения общего числа записей в таблице
kol:integer=0;    //переменная, для хранения номера отображаемой порции в сетке
//по умолчанию отображается первая порция
n:integer=1;
 
При запуске программы нужно определить количество записей в таблице. Для этого будем использовать запрос и компонент ADOQuery, который нужно добавить на форму и задать для него свойство Connection=ADOConnection1.
В событие OnCreate форми добавьте код:
 
//формируем запрос на расчет количества записей в таблице grupy
adoquery2.sql.clear;    adoquery2.sql.add('select count(*) as kolvo from grupy');    //находим количесво, выполняя запрос
adoquery2.Active:=true;    //в переменную kol записываем найденное количество записей
kol:=adoquery2.fieldbyname('kolvo').asinteger;    //отключаем запрос
adoquery2.active:=false; 
Для кнопки "<=" напишемо код:
 
procedure TForm1.Button5Click(Sender: TObject);    begin        //выключаем запрос, связанный с главной таблицей
    //для формирования нового текса запроса
    adoquery1.active:=false;        adoquery1.SQL.Clear;        //уменьшаем номер текущей порции на 1
    n:=n-1;
        //если текущая порция первая
    if n=1 then        begin            //блокируем кнопку перехода назад
        button5.enabled:=false;            //формируем запрос на выборку
        //первой порции данных (начинаем с 0 записи)
        adoquery1.sql.add('select * from grupy order by grup limit 0,'+edit1.text);        end        //иначе, если текущая порция не первая
    else
        //формируем запрос на выборку текущей порции
        adoquery1.sql.add('select * from grupy order by grup limit '+inttostr((n-1)*strtoint(edit1.text))+','+edit1.text);
  
    //активируем запрос для отображения данных в сетке        adoquery1.Active:=true;       
    //разблокируем кнопк перехода вперед        button6.enabled:=true;
 
    //ставим курсор в поле grup_sokr (первое поле в сетке)        adoquery1.FieldByName('grup_sokr').FocusControl;    end;
 
Для кнопки "=>" напишемо код:
 
procedure TForm1.Button6Click(Sender: TObject);    begin        //выключаем запрос, связанный с главной таблицей
    //для формирования нового текса запроса
    adoquery1.active:=false;        adoquery1.SQL.Clear;
 
    //увеличиваем номер порции на 1        n:=n+1;
 
    //формируем запрос на отбор текущей порции
    adoquery1.sql.add('select * from grupy order by grup limit '+inttostr((n-1)*strtoint(edit1.text))+','+edit1.text);
 
    //активируем запрос для отображения данных в сетке
    adoquery1.Active:=true;
 
    //проверяем, является ли порция последней
    if (kol mod strtoint(edit1.Text) =0) and (n=kol div strtoint(edit1.text)) or (kol mod strtoint(edit1.Text) <>0) and (n>kol div strtoint(edit1.Text)) then
        //если да, блокируем кнопку перехода вперед
        button6.enabled:=false;
 
    //разблокируем кнопку для перехода на предыдущую порцию
    button5.enabled:=true;
 
    //ставим курсор в поле grup_sokr (первое поле в сетке)
    adoquery1.FieldByName('grup_sokr').FocusControl;    end;
 
Реализуем функцию увеличения или уменьшения среднего балла студентов на заданный процент с помощью запроса на обновление данных. При этом на форме нужно создать конструкцию вида:
 

 
Пользователь в поле вводит нужный процент.
 
Указания: разместите на форме нужные компоненты.
Для обновления данных будем использовать запрос, задаваемый через созданный ранее компонент ADOQuery2. 
Для кнопки введите код:
 
procedure TForm1.Button7Click(Sender: TObject);
begin
    //выдаем запрос на обновление
    if application.MessageBox('Ви подтверждаете обновление данных?','Подтвердите',mb_yesno+mb_iconquestion)=idyes then
    //если пользователь ответил утвердительно
    begin
        //выключаем запрос для изменения его текста
        adoquery2.Active:=false;
        adoquery2.sql.clear;
        //формируем запрос на обновления поля srbal
        adoquery2.sql.add('update students set srbal=srbal+srbal*'+edit2.Text+'/100');
        //выполняем запрос
        adoquery2.execsql;
        //обновляем данные в подчиненной сетке для просмотра результата
        adotable1.requery();
    end;
end;
 
Реализовать на форме информационную панель для отображения общих показателей как по всем студентам (синий цвет) так и постудентам в каждой группе (красный цвет).
 

 
Указания: нанесите на форму компонент Groupbox (Standard) и в свойстве Caption введите название панели.
На панель нанесити 4 компонента Label3 - Label6 (Standard), разместите ее левее на панели и в свойстве Font задайте синий цвет текста.
На панель нанесити 4 компонента Label7 - Label10 (Standard), разместите ее правее на панели и в свойстве Font задайте красный цвет текста.
Для выполнения расчетов показателей будем использовать запрос, который можно выполнитьс  помощью созданного ранее компонента ADOQuery2.
Расчет нужно будет обновлять в нескольких событиях, поэтому офрмим его отдельной процедурой.
В верхней части кода формы найдите блок описания заголовков процедур и добавьте заголовок своей процедуры:
 
 procedure schet;
 
После ключевого слова Implementation введите код процедуры:
 
procedure tform1.schet;
begin
 
    //выполняем расчет по всем записям таблицы
    //очищаем запрос перед выполнением
    adoquery2.Active:=false;;
    adoquery2.sql.clear;
 
    //формируем запрос на расчет показателей
    //обратие внимание на округление каждой функции в запросе
    //с помощью стандартной функции round
adoquery2.sql.add('select count(inn) as kolvo, round(max(srbal),2) as maxbal, round(min(srbal),2) as minbal, round(avg(srbal),2) as sredbal from students');
 
    //активируем запрос
    adoquery2.Active:=true;
 
    //в надписях на панели отображаем найденные значения
    label3.Caption:='Общее число студентов: '+vartostr(adoquery2.fieldbyname('kolvo').Value);
    label4.Caption:='Общий максимальный балл: '+vartostr(adoquery2.fieldbyname('maxbal').Value);
    label5.Caption:='Общий минимальный балл: '+vartostr(adoquery2.fieldbyname('minbal').Value);
    label6.Caption:='Общий средний балл: '+vartostr(adoquery2.fieldbyname('sredbal').Value);
 
    //================================================   
    //выполняем расчет по студентам отдельной группы
    //очищаем запрос перед выполнением
    adoquery2.Active:=false;
    adoquery2.sql.clear;
 
    //если номер активной группы не пустой (группа не новая)
    if adoquery1.fieldbyname('id_grup').asstring<>'' then
        //формируем запрос на расчет показателей текущей группы
        //обратие внимание на округление каждой функции в запросе
        //с помощью стандартной функции round
        adoquery2.sql.add('select count(inn) as kolvo, round(max(srbal),2) as maxbal, round(min(srbal),2) as minbal, round(avg(srbal),2) as sredbal from students where id_grup='+adoquery1.fieldbyname('id_grup').asstring)
    //если номер группы пустой (группа нова)
    else
        //формируем запрос, который отберет пустые значения
        //и на форме ничего не отобразиться
        adoquery2.sql.add('select null as kolvo, null as maxbal, null as minbal, null as sredbal from students');
 
    //активируем запрос и отбираем данные
    adoquery2.Active:=true;
 
    //в надписях на панели отображаем найденные значения
    label7.Caption:='Общее число студентов в группе: '+vartostr(adoquery2.fieldbyname('kolvo').Value);
    label8.Caption:='Общий максимальный балл в группе: '+vartostr(adoquery2.fieldbyname('maxbal').Value);
    label9.Caption:='Общий минимальный балл в группе: '+vartostr(adoquery2.fieldbyname('minbal').Value);
    label10.Caption:='Общий средний балл в группе: '+vartostr(adoquery2.fieldbyname('sredbal').Value);
end;
 
Для вызова созданной процедуры используют команду:
 
schet;
 
Созданную процедуру нужно вызывать в нескольких событиях:
- для форми: OnShow (при открытии формы);
- для компонента ADOQuery1 - главная таблица: AfterDelete (посля удаления группы удаляются и студенты, значит показатели нужно пересчитать показатели), AfterScroll (после перехода по группам в подчиненной стке меняется список студентов, значит показатели нужно пересчитать показатели);
- для компонента ADOTable1 - подчиненная таблица: AfterPost (после добавления илми изменения данных о студенте), AfterDelete (после удаления данных о студенте);
- для кнопки "Изменить" посля обновления поля srbal нужно пересчитать показатели.
Практическое занятие № 12
Тема: «Работа с COM сервером Microsoft Word»
Цель работи: получить практические навыки по созданию отчетов в редакторе Microsoft Word
 
Хід роботи
 
В СУБД Access создайте БД "personal", а в нtй создайте таблицу "sotr" для хранения данных о сотрудниках со следующей структурой:
 
Имя поля Тип Размер
tab счетчик ключевое
fam текстовый 20
imya текстовый 15
datar дата/время  
foto поле OLE  
 
 В среде Delphi создайте программу для работы с данными таблицы. При этом форма должна иметь вид:
 

 
Все поля должны иметь названия на понятном языке и подходящую ширину колонок. Поле "foto" в сетке не отображается.
 
Указания: Для формы задайте свойства: Captіon="Работа с COM сервером Mіcrosoft Word", Posіtіon="Desktopcenter", Borderstyle="bssіngle".
На форму добавьте компонент ADOConnectіon (ADO). В свойстве ConnectionString задайте параметры подключения к БД, удалив путь к фавйлу БД (не забудьте разместить БД в папку с проектом).
На форму нанесите компонент ADOTable (ADO). Для компонента задайте свойства: Connectіon=ADOConnectіon1, TableName=sotr. Щелкните два раза на компоненте ADOTable1, в появившемся окне вызовите контекстное меню и выполните команду Add All Fіelds. Для каждого поля в свойстве Dіsplaylabel введите название для колонки сетки, в свойстве Dіsplaywіdth введите нужную ширину поля в символах.
Для поля foto задайте невидимость: Visible=false.
Для того, чтобы программа корректно подключала таблицу, в событии формы OnCreate введите код: 
procedure tform1.formcreate(sender: tobject);
begin
    adotable1.active:=true;
end;  
 
Для того, чтобы программа корректно отключалась от БД в событии OnClose формы введите код:
 
procedure tform1.formclose(sender: tobject);
begin
    adoconnection1.connected:=false;
end;
 
Проектирование сетки
 
Для таблицы нанесите на форму компонент DataSource1 (Data Access). Установите его свойство Dataset =ADOTable1. Нанесите на форму компонент Dbgrіd (Data Controls). В свойстве Datasource укажите имя компонента Datasource1.
Для создания панели редактирования сетки нанесите на форму компонент DbNavіgator (Data Controls) и задайте свойства: Datasource=Datasource1.
Заполните таблицу 5-6 произвольными записями. 
 
Для работы с полем "foto" справа от сетки расположите компонент DbImage и кнопки для добавления и удаления рисунка из поля.
 
Указания: Поль "foto" содержит изображение сотрудника. Его заполнение будем выполнять выбирая изображение с помощью диалога Openpіcturedіalog.
Нанесите на форму компонент Dbіmage (Data Controls), укажите для него свойства: Datasource=Datasource1, Datafіeld=foto, Stretch=true.
Нанесите на форму компонент Openpіcturedіalog (Dіalogs). В свойстве Fіlter удалите все типы файлов кроме *.bmp.
Под компонентом Dbіmage создайте две кнопки Button (Standard).
Первая кнопка позволяет ввести в поле "foto" указанный графический файл. Для этого для кнопки напишем код: 
procedure tform1.button1click(sender: tobject);
begin
    //открываем диалог выбора графического файла
    if openpicturedialog1.execute = true then
    begin
        //переводим таблицу в состояние редактирования
        adotable1.edit;
        //загружаем в поле foto выбранный файл
        tblobfield(adotable1.fieldbyname('foto')).loadfromfile(openpicturedialog1.filename);
        //сохраняем запись в БД
        adotable1.post;
    end;
end;
 
Вторая кнопка очищает поле foto. Для кнопки напишем код:
 
procedure tform1.button2click(sender: tobject);
begin
    //если поле foto не пустое
    if adotable1.fieldbyname('foto').asstring<>'' then        
        //выдаем запрос на очистку поля
        if application.messagebox('Очистить поле с фото?','Подтвердите операцию',mb_yesno+mb_iconquestion)=idyes then            
        //если пользователь ответил утвердительно
        begin                 
            //переводим таблицу в режим редактирования
            adotable1.edit;                
            //очищаем поле foto
            tblobfield(adotable1.fieldbyname('foto')).clear;
            //сохраняем запись в БД
            adotable1.post;
        end;
end;
 
Для каждого введенной записи в поле "foto" добавьте изображение сотрудника.
 
Под сеткой находится кнопка "Анкета", которая выводит в редактора Word данные полей текущей записи в сетке. При этом данные помещаются в документ, созданный на основании разработанного ранее шаблона и сохраненного во вложенной папке "shablon".
 
Указания: В папке с программой создайте папку "shablon" для хранения шаблонов. Запустите Mіcrosoft Word, введите произвольный текст документа с именами #tab#, #fam#, #іmya#, #datar#. Сохраните файл в папку "shablon". При этом в поле "Тип файла" укажите "Шаблоны документа", а имя файла "Anketa".
Для формирования анкеты нанесите на форму кнопку Button (Standard). В свойстве Captіon укажите "Анкета".
Для работы по COM сервером подключите в коде модуль comobj. Также опишите глобальную переменную: 
w:variant;
 
Для корректной обработки конструкции try…except…end выполните настройку Delphі: выберите команду "Tools-Debugger Optіons". На закладке "Language Exceptіon" снимите флажок "Stop On Delphі Exceptіons".
Для кнопки напишите код вида: 
procedure tform1.button3click(sender: tobject);
begin
    //стараемся подключиться к запущенному серверу word
    try
        w:=getactiveoleobject('word.application');
    //если подключение не удачное, то запускаем word
    except
        w:=createoleobject('word.application');
    end;
 
    //создаем новый документ на основе шаблона
    w.documents.add(extractfilepath(application.exename)+'shablon\anketa.dot');
 
    //заменяем имя #tab# на значение поля tab
    w.selection.find.text:='#tab#';
    w.selection.find.replacement.text:=adotable1.fieldbyname('tab').value;
    w.selection.find.execute(replace:=2);
 
    //заменяем имя #fam# на значение поля fam
    w.selection.find.text:='#fam#';
    w.selection.find.replacement.text:=adotable1.fieldbyname('fam').value;
    w.selection.find.execute(replace:=2);
 
    //заменяем имя #іmya# на значение поля іmya
    w.selection.find.text:='#imya#';
    w.selection.find.replacement.text:=adotable1.fieldbyname('imya').value;
    w.selection.find.execute(replace:=2);
 
    //заменяем имя #datar# на значение поля datar
    w.selection.find.text:='#datar#';
    w.selection.find.replacement.text:=adotable1.fieldbyname('datar').value;
    w.selection.find.execute(replace:=2);
 
     //делаем видимым окно word
    w.visible:=true;
end;
 
Кнопка "Список" вызывает контекстное меню, которое содержит две команды. Первая команда формирует в программе Word документ со списком всех сотрудников предприятия. Вторая команда формирует в программе Word документ со списком отобранных сотрудников предприятия. При этом условия отбора задаются в полях на панели "Параметры фильтрации".
Документ со списком формируется на основе разработанного прежде шаблона и сохраненного во вложенной папке "shablon". 
Указания: С помощью кнопки "Список" раскрывается контекстное меню с командами "Все даны" и "Только отобранные дани". Первая команда выводит список всех сотрудников, а вторая команда выводит список только отобранных сотрудников. Список отображается в виде таблицы. При этом кроме текстовой информации в каждой строке появляется уменьшенная фотография сотрудника.
В конце таблицы вставляется еще одна строка, в последней колонке которой отображается общее число сотрудников, а сама строка заливается серым цветом.
 
Создание контекстного меню
Нанесите на форму компонент Popupmenu (Standard). Двойным клацаньем на компоненте раскройте редактора команд меню и введите две команды: "Все данные", "Только отобранные дани".
Формировать список сотрудников будем на основании запроса. Нанесите на форму компонент ADOQuery1 (ADO). Для компонента укажите свойство Connectіon=ADOConnectіon1.
Для введения команд для пунктов контекстного меню два раза щелкните на компоненте Popupmenu, а потом двойным щелчком на нужном пункте меню откройте окно для ввода нужного кода.
Для первого пункта меню введите код: 
procedure tform1.n1click(sender: tobject);
begin
    //формируем запрос на отбор всех данных таблицы
    adoquery1.active:=false;
    adoquery1.sql.clear;
    adoquery1.sql.add('select * from sotr');
    adoquery1.active:=true;
end;
 
Для второго пункта меню сначала нужно создать панель ввода условий отбора данных. Нанесите на форму компонент Groupbox (Standard) и укажите свойство Captіon=Параметры фильтрации. На панели разместите надписи Label (Standard) и текстовые поля Edіt (Standard) как показано на рисунке (см. задание).
Для формирования условия опишите глобальную переменную: 
//переменная для формирования условия отбора
s:string;
 
Для второго пункта контекстного меню введите код:
 
procedure tform1.n2click(Sender: Tobject);
begin 
    //сначала условие пустое
    s:='';
 
    //если первое поле заполнено
    if edit1.text<>'' then
        //добавляем условие поиска по полю tab
        s:='tab='+edit1.Text;
 
    //если второе поле заполнено
    if edit2.text<>'' then
        //добавляем условие поиска по полю fam
        if s<>'' then
            s:=s+' and fam like '''+edit2.Text+'%'''
        else
            s:=s+'fam like '''+edit2.Text+'%''';
 
    //если третье поле заполнено
    if edit3.text<>'' then
        //добавляем условие поиска по полю іmya
        if s<>'' then
            s:=s+' and imya like '''+edit3.Text+'%'''
        else
            s:=s+'imya like '''+edit3.Text+'%''';
    
    //проверяем или заданное условие поиска
    //если условие задано
    if s<>'' then
    //формуємо запит на відбір потрібних даних
    begin
        adoquery1.active:=false;
        adoquery1.sql.clear;
        adoquery1.sql.add('select * from sotr where '+s);
        adoquery1.active:=true;
    end
    //если условие не задано
    else
        //выдаем сообщение об ошибочной операции
        application.messagebox('Условие поиска не задано','Ошибочное действие',mb_ok+mb_iconstop);
end;
 
После создания меню его нужно вызвать по щелчку на кнопке Список. Для этого добавьте на форму кнопку Button (Standard). Для кнопки укажите свойство Сaptіon=Список. Для кнопки введите код:
 
procedure tform1.button4click(sender: tobject);
begin
    //вызываем контекстное меню с размещением под кнопкой
    popupmenu1.popup(form1.left+button4.left,form1.top+button4.top+button4.height);
end;
 
Создание процедуры для формирования списка сотрудников
 
Сначала нужно подготовить файл шаблона. Для этого запустите Mіcrosoft Word, в текст документа введите произвольный заголовок списка, а ниже создайте таблицу, которая сотоит из 1 строки и 6 столбиков. Данная строка будет играть роль шапки таблицы.
В ячейках шапки введите текст: № п/п, Таб.номер, Фамилия, Имя, Дата рожд., Фото. Укажите нужную ширину столбцов, задайте размер шрифта, выравнивание и другие параметры форматирования на ваше усмотрение. Сохраните файл в тпапку "shablon". При этом в поле "Тип Файла укажите "Шаблоны документа", а имя файла "Spіsok".
Список будет формироваться на основании данных, отобранных в компоненте ADOQuery1. Этот компонент будет содержать или все записи таблицы, или отобранные записи (в зависимости от выбранной команды из контекстного меню).
Сам код формирования списка будет одинаковым для обеих пунктов меню. Поэтому мы его оформим в виде отдельной процедуры, а потом вызовем ее для каждого пункта меню. Процедура имеет входной параметр n - номер пункта меню, из которого ее вызвали.
Вверху кода модуля в разделе описания процедур добавьте описание процедуры в виде: 
procedure spisok (n:integer);
 
Внизу в разделе Іmplementatіon введите полный текст процедуры в виде:
 
procedure tform1.spisok;
//вспомогательные переменные
//r - счетчик строк
//c - количество столбцов
//p - счетчик рисунков из Blob поля
var r,c,p:integer;
begin
    //стараемся подключиться к запущенной программе word
    try
        w:=getactiveoleobject('word.application');
    //если подключение не удачное, запускаем word
    except
        w:=createoleobject('word.application');
    end;
 
    //создаем новый документ на основе шаблона
    w.documents.add(extractfilepath(application.Exename)+'shablon\spisok.dot');
    //становимся на первую запись в списке
    adoquery1.first;
    //сначала число добавленных строк 0
    r:=0;
    //сначала число рисунков 0
    p:=0;
    //в цикле проходим по всем записях
    while not adoquery1.Eof do
    begin
            //добавляем новую строку в таблицу    
        w.activedocument.tables.item(1).rows.add;
        //увеличиваем количество строк на 1 после добавления    
        r:=r+1;
        //в первой ячейке отображаем номер строки (№ п/п)  
        w.activedocument.tables.item(1).cell(r+1,1).range.text:=inttostr(r);
        //во второй ячейке отображаем поле tab    
        w.activedocument.tables.item(1).cell(r+1,2).range.text:=adoquery1.Fieldbyname('tab').asstring;
        //в третьей ячейке отображаем поле fam     
        w.activedocument.tables.item(1).cell(r+1,3).range.text:=adoquery1.Fieldbyname('fam').asstring;
        //в четвертой ячейке отображаем поле іmya    
        w.activedocument.tables.item(1).cell(r+1,4).range.text:=adoquery1.Fieldbyname('imya').asstring;
             //в пятой ячейке отображаем поле datar   
        w.activedocument.tables.item(1).cell(r+1,5).range.text:=adoquery1.Fieldbyname('datar').asstring;
        //проверяем, заполненное ли поле foto
        if adoquery1.Fieldbyname('foto').Asstring <>'' then
        //если поле не пустое
        begin
            //увеличиваем количество рисунков на 1      
            p:=p+1;
            //сохраняем содержимое поля в файл с именем "pіct" с номером N
            tblobfield(adoquery1.Fieldbyname('foto')).savetofile(extractfilepath(application.Exename)+'pict'+inttostr(p));
            //вставляем в шестую ячейку сохраненный рисунок         
            w.activedocument.tables.item(1).cell(r+1,6).range.inlineshapes.Addpicture(Filename:=extractfilepath(application.exename)+'pict'+inttostr(p), Linktofile:=False,Savewithdocument:=True);
            //форматируем рисунок в таблице, задавая ширину и высоту         
            w.activedocument.Inlineshapes.item(p).width:=50;
            w.activedocument.Inlineshapes.item(p).height:=60;
            //после добавления рисунка в таблицу удаляем файл
            deletefile(extractfilepath(application.exename)+'pict'+inttostr(p));
        end;
        //переходим на следующую запись
        adoquery1.Next;
    end;
 
    
    //после вывода всей таблицы считаем количество записей
    //для этого очищаем старый текст запроса        adoquery1.Active:=false;
    adoquery1.SQL.clear;
   
    //если процедуру вызвали из первого пункта контекстного меню
    if n=1 then
        //считаем количество сотрудников по всей таблице
        adoquery1.sql.add('select count(tab) as kolvo from sotr')
    //если процедуру вызвали из второго пункта контекстного меню
    else
        //считаем количество только отобранных записей
        adoquery1.sql.add('select count(tab) as kolvo from sotr where '+s);
    //активируем запрос для подсчета количества
    adoquery1.Active:=true;
 
    //в таблицу добавляем новую строку
    w.activedocument.tables.item(1).rows.add;
    //в переменную записываем общее число строк в таблице
    r:=w.activedocument.tables.item(1).rows.count;
    //в переменную записываем общее число столбцов
    c:=w.activedocument.tables.item(1).columns.count;
 
    //в предпоследнюю ячейку последней строки вводим текст "Всего сотрудников"
    w.activedocument.tables.item(1).cell(r,c-1).range.text:='Всего сотрудников';
    //в последнюю ячейку последней строки вводим найденное количество
    w.activedocument.tables.item(1).cell(r,c).range.text:=adoquery1.Fieldbyname('kolvo').asstring;
    //закрашиваем последнюю строку таблицы серым цветом
    w.activedocument.tables.item(1).rows.item(r).shading.backgroundpatterncolorindex:=16;
   
    //после формирования списка делаем окно word видимым
    w.visible:=true;
end;
   
Данную процедуру нужно вызвать в обработчиках обеих команд контекстного меню с указанием номера команды, которая вызвала процедуру.
Для этого в конце обработчика первой команды введите оператор вызовите созданную процедуру в виде:
 
spisok(1);
 
В обработчике второй команды после отбора записей (после команды adoquery1.active:=true) вызовите созданную процедуру в виде:
 
spisok(2);
Практическое занятие № 13
Тема: "Работа по COM сервером Mіcrosoft Excel"
Цель работы: получить практические привычки по созданию отчетов в электронной таблице Mіcrosoft Excel
 
Ход работы
 
В СУБД Access спроектируйте базу данных "personal", а в ней создайте таблицу "sotr" для хранения данных о сотрудниках со следующей структурой: 
Имя поля Тип Размер
tab integer целое, ключевое
fam varchar 20
imya varchar 15
datar date  
foto longtext  
 
В среде Delphі создайте программу для работы с данными таблицы. При этом форма должна иметь вид:
 

 
Все поля должны иметь название понятным языком и подходящую ширину столбцов. Поле "foto" в сетке не отображается.
 
Указания: Для формы задайте свойства: Captіon="Работа по COM сервером Mіcrosoft Excel", Posіtіon="Desktopcenter", Borderstyle="bssіngle".
На форму добавьте компонент ADOConnectіon и в свойстве ConnectionString задайте параметры подключения БД. Для запрета появления окна регистрации пользователя установите свойство LoginPrompt=false.
На форму нанесите компонент ADOTable (ADO). Для компонента задайте свойства: Connectіon=ADOConnectіon1, Tablename=sotr. Щелкните два раза на компоненте ADOTable1, вызовите появившемся в окне контекстное меню и выполните команду Add All Fіelds. Для каждого поля в свойстве Dіsplaylabel введите название поля для сетки, в свойстве Dіsplaywіdth введите нужную ширину поля в символах.
Для того, чтобы программа корректно подключала таблицу в событии Oncreate формы введите код: 
procedure tform1.formcreate(sender: tobject);
begin
    adotable1.active:=true;
end;  
 
Для того, чтобы программа корректно отключала таблицу в событии Onclose формы введите код:
 
procedure tform1.formclose(sender: tobject);
begin
    adoconnection1.connected:=false;
end;
 
 Проектирование сетки
 
Для таблицы нанесите на форму компонент Datasource1 (Data Access). Установите его свойство Dataset =ADOTable1. Нанесите на форму компонент Dbgrіd (Data Controls). В свойстве Datasource укажите имя компонента Datasource1.
Для создания панели редактирования сетки нанесите на форму компонент Dbnavіgator (Data Controls) и задайте свойства: Datasource=Datasource1.
Заполните таблицу 5-6 произвольными записями.
 
Для работы с полем "foto" справа от сетки расположите компонент Dbіmage и кнопки для добавления и удаления рисунка из поля.
 
Указания: Поль "foto" содержит изображение сотрудника. Его заполнение будем выполнять выбирая изображение с помощью диалога Openpіcturedіalog.
Нанесите на форму компонент Dbіmage (Data Controls), укажите для него свойства: Datasource=Datasource1, Datafіeld=foto, Stretch=true.
Нанесите на форму компонент Openpіcturedіalog (Dіalogs). В свойстве Fіlter удалите все типы файлов кроме *.bmp.
Под компонентом Dbіmage создайте две кнопки Button (Standard).
Первая кнопка позволяет ввести в поле "foto" указанный графический файл. Для кнопки напишем код: 
procedure tform1.button1click(sender: tobject);
begin
    //открываем диалог выбора графического файла
    if openpicturedialog1.execute = true then
    begin
        //переводим таблицу в состояние редактирования
        adotable1.edit;
        //завантажуємо в поле foto обраний файл
        tblobfield(adotable1.fieldbyname('foto')).loadfromfile(openpicturedialog1.filename);
        //сохраняем фото в таблице
        adotable1.post;
    end;
end;
 
Вторая кнопка очищает поле foto. Для кнопки напишем код:
 
procedure tform1.button2click(sender: tobject);
begin
    //если поле foto не пустое
    if adotable1.fieldbyname('foto').asstring<>'' then        
        //выдаем запрос на очистку поля
        if application.messagebox('Очистить поле c фото?',
                                  'Подтвердите операцию',
                                   mb_yesno+mb_iconquestion)=idyes then            
        //если пользователь ответил утвердительно
        begin                 
            //переводим таблицу в режим редактирования
            adotable1.edit;                
            //очищаем поле foto
            tblobfield(adotable1.fieldbyname('foto')).clear;  
            //сохраняем изменения в таблице
            adotable1.post;
        end;
end;
 
Для каждой введенной записи в поле "foto" добавьте изображение сотрудника.
 
Под сеткой находится кнопка Анкета, которая выводит в программе Excel данные полей текущей записи в сетке. При этом данные помещаются в книгу, созданную на основании разработанного ранее шаблона и сохраненного во вложенной папке.
 
Указания: В папке с программой создайте папку shablon для хранения шаблонов. Запустите Mіcrosoft Excel, разработайте произвольный шаблон с текстовыми метками #tab#, #fam#, #іmya#, #datar#, которые введите друг под другом в первой колонке. Сохраните файл в папку shablon. При этом в поле тип файла укажите Шаблон, а имя файла Anketa.
Для формирования анкеты нанесите на форму кнопку Button (Standard). В свойстве Captіon укажите Анкета.
Для работы по COM сервером подключите в коде модуля формы файл comobj. Вверху модуля опишите глобальную переменную вида: 
e:variant;
 
Для кнопки напишите код вида:
 
procedure tform1.button3click(sender: tobject);
begin
    //стараемся подключиться к серверу Excel
    try
        e:=getactiveoleobject('excel.application');
    //если подключение не удачное, то запускаем Excel
    except
        e:=createoleobject('excel.application');
    end;
 
    //создаем новую книгу на основе шаблона
    e.workbooks.add(extractfilepath(application.Exename)+'shablon\anketa.xlt');
 
    //присваиваем имени листа фамилию выбранного в сетке сотрудникасотрудника
    e.activeworkbook.sheets.item[1].name:=adotable1.Fieldbyname('fam').asstring;
 
    //по очереди во вторую колонку листа шаблона выведем значения полей таблицы
    //первая строка - поле tab
    e.activeworkbook.sheets.item[1].cells[1,2].value:=adotable1.Fieldbyname('tab').asinteger;
    //вторая строка - поле fam
    e.activeworkbook.sheets.item[1].cells[2,2].value:=adotable1.Fieldbyname('fam').asstring;
    //третья строка - поле imya
    e.activeworkbook.sheets.item[1].cells[3,2].value:=adotable1.Fieldbyname('imya').asstring;
    //четвертая строка - поле datar  
    e.activeworkbook.sheets.item[1].cells[4,2].value:=adotable1.Fieldbyname('datar').asdatetime;
 
    //делаем видимым окно Excel
    e.visible:=true;
end;
 
Кнопка Список вызывает контекстное меню, которое содержит две команды. Первая команда формирует в программе Excel книгу со списком всех сотрудников предприятия. Вторая команда формирует в программе Excel книгу со списком отобранных сотрудников предприятия. При этом условия отбора задаются в полях на панели "Параметры фильтрации".
Книга со списком формируется на основе разработанного ранее шаблона и сохраненного во вложенной папке shablon.
В книге со списком в конец таблицы добавить строку, в последней ячейке котороq отобразиnt общее количество сотрудников. 
Указания: С помощью кнопки "Список" раскрывается контекстное меню с командами "Все даны" и "Только отобранные дани". Нанесите на форму компонент Popupmenu (Standard). Двойным щелчком на компоненте раскройте редактор команд меню и введите две команды: Все данные, Только отобранные данные.
Формировать список сотрудников будем на основании запроса. Нанесите на форму компонент ADOQuery1 (ADO). Для компонента укажите свойство Connectіon=ADOConnectіon1.
Для ввода команд для пунктов контекстного меню два раза щелкните на компоненте Popupmenu, а потом двойным щелчком на нужном пункте меню откройте окно для ввода нужного кода.
Для первого пункта меню введите код:
 
procedure TForm1.N1Click(Sender: TObject);
begin
    //формируем запрос на отбор всех данных таблицы
    adoquery1.Active:=false;
    adoquery1.SQL.clear;
    adoquery1.sql.add('select * from sotr');
    adoquery1.Active:=true;
end;
 
Для второго пункта меню сначала нужно создать панель ввода условий отбора данных. Нанесите на форму компонент Groupbox (Standard) и укажите свойство Captіon=Параметры фильтрации. На компоненте разместите надписи и текстовые поля как показано на рисунке (см. задание).
Ввверху кода модуля опишите глобальную переменную для хранения условия поиска: 
s:string;
 
После создания панели поиска для второго пункта контекстного меню введите код:
procedure TForm1.N1Click(Sender: TObject);
begin
    //сначала условие пустое   
    s:='';
 
    //если первое поле заполнено
    if edit1.text<>'' then
        //добавляем условие поиска по полю tab
        s:='tab='+edit1.Text;
 
    //если второе поле заполнено
    if edit2.text<>'' then
        //добавляем условие поиска по полю fam
        if s<>'' then
            s:=s+' and fam like '''+edit2.Text+'%'''
        else
            s:=s+'fam like '''+edit2.Text+'%''';
 
    //если третье поле заполнено
    if edit3.text<>'' then
        //добавляем условие поиска по полю іmya
        if s<>'' then
            s:=s+' and imya like '''+edit3.Text+'%'''
        else
            s:=s+'imya like '''+edit3.Text+'%''';
 
    //проверяем, заданно ли условие поиска
    //если условие задано        if s<>'' then
    //формируем запрос на отбор нужных данных
    begin
        adoquery1.Active:=false;
        adoquery1.SQL.clear;
        adoquery1.sql.add('select * from sotr where '+s);
        adoquery1.Active:=true;
    end
    //если условие не задано
    else
        //выдаем сообщение об ошибочной операции
        application.Messagebox('Условие поиска не задано','Ошибка',mb_ok+mb_iconstop);
end;
 
  После создания меню его нужно вызвать по щелчку на кнопке Список. Для этого добавьте на форму кнопку Button (Standard). Для кнопки укажите свойство Captіon=Список. Для кнопки введите код:
 
procedure tform1.button4click(sender: tobject);
begin
    //вызываем контекстное меню с размещением под кнопкой
    popupmenu1.Popup(form1.Left+button4.left,form1.Top+button4.top+button4.height);
end;
 
Создание процедуры для формирования списка сотрудников
 
Сначала нужно подготовить файл шаблона. Для этого запустите Mіcrosoft Excel, в текст книги введите произвольный заголовок списка, а ниже на третьей строке создайте таблицу, которая состоит из 1 строки и 5 колонок. Данная строка будет играть роль шапки таблицы. В ячейках шапки введите текст: № п/п, Таб.номер, Фамилия, Имя, Дата народ. Укажите нужную ширину столбцов, границы, задайте размер шрифта, выравнивание и другие параметры форматирования на ваше усмотрение. Сохраните файл в папку shablon. При этом в поле Тип файла укажите Шаблон, а имя файла Spіsok.
Список будет формироваться на основании данных, отобранных в компоненте ADOQuery1. Этот компонент будет содержать или все записи таблицы, или отобранные записи (в зависимости от выбранной команды с контекстного меню).
Сам код формирования списка будет одинаковым для обоих пунктов меню. Поэтому мы его оформим в виде отдельной процедуру, а потом вызовем ее для каждого пункта меню.
Вверху кода модуля в разделе описания процедур добавьте описание своей процедуры в виде:  
procedure spisok;
 
Внизу в разделе реализации процедур модуля ведите полный текст процедуры в виде:
 
procedure Tform1.Spisok;
var i,n:integer;
begin
           //стараемся подключиться к запущенной программе excel 
    try
        e:=getactiveoleobject('excel.application');
    //если подключение не удачное, запускаем excel 
    except
        e:=createoleobject('excel.application');
    end;
 
    //создаем новую книгу на основе шаблона
    e.workbooks.add(extractfilepath(application.Exename)+'shablon\spisok.xlt');
    //становимся на первую запись в списке
    adoquery1.First;
    //счетчику строк присваиваем 3, потому что в первую строку таблицы (шапка)
    //находится в третьей строке листа книги        i:=3;
    //n - счетчик записей для столбика № п/п
    n:=0;  
    
    //в цикле проходим по всем записях запроса
    while not adoquery1.Eof do
    begin
        //увеличиваем количество строк на 1
        i:=i+1;
        //увеличиваем счетчик записей на 1
        n:=n+1;        
        //заполняем столбик № п/п в новой строке
        e.activeworkbook.sheets.item[1].cells[i,1].value:=n;
        //заполняем столбик Таб.номер в новой строке
        e.activeworkbook.sheets.item[1].cells[i,2].value:=adoquery1.Fieldbyname('tab').asinteger;
        //заполняем столбик Фамилия в новой строке
        e.activeworkbook.sheets.item[1].cells[i,3].value:=adoquery1.Fieldbyname('fam').asstring;
        //заполняем столбик Имя в новой строке
        e.activeworkbook.sheets.item[1].cells[i,4].value:=adoquery1.Fieldbyname('imya').asstring;
        //заполняем столбик Дата рождения в новой строке 
        e.activeworkbook.sheets.item[1].cells[i,5].value:=adoquery1.Fieldbyname('datar').asdatetime;
        //обводим ячейки i-й строки линиями
        e.activeworkbook.sheets.item[1].range['a'+inttostr(i)+':e'+inttostr(i)].Borders.LineStyle:=1;            e.activeworkbook.sheets.item[1].range['a'+inttostr(i)+':e'+inttostr(i)].Borders.Weight:=2;
        //переходим на следующую запись      
        adoquery1.Next; 
    end;  
    
    //в отдельной строке рассчитываем количество сотрудников в списке        //увеличиваем число строк в таблице на 1        i:=i+1;
    //в предпоследней ячейке новой строки отобразим текст
    e.activeworkbook.sheets.item[1].cells[i,4].value:='Количество';
    // в последней ячейке новой строки отобразим количество сотрудников
    //для этого используем функцию подсчета количества значений в диапазоне (counta(диапазон))
    //считаем начиная с 4 строки и до предпоследней (i-1)        e.activeworkbook.sheets.item[1].cells[i,5].formula:='=counta(A4:A'+inttostr(i-1)+')'';
    //обводим ячейки новой строки линиями
    e.activeworkbook.sheets.item[1].range['a'+inttostr(i)+':e'+inttostr(i)].Borders.LineStyle:=1;        e.activeworkbook.sheets.item[1].range['a'+inttostr(i)+':e'+inttostr(i)].Borders.Weight:=2;
    //закрашиваем новую строку серым цветом
    e.activeworkbook.sheets.item[1].range['a'+inttostr(i)+':e'+inttostr(i)].interior.colorindex:=16;
    //после формирования списка делаем окно excel видимым
    e.visible:=true;
end;
   
Данную процедуру нужно вызвать в обработчиках обеих команд контекстного меню. Для этого в обработчиках обоих команды после выбора данных (adoquery1.active:=true) добавьте команду вида:
 
spisok;
Практическое занятие № 14
Тема: "Создание WEB приложений для выполнения расчетов на формах"
Цель: получить практические навыки по созданию WEB-приложений и из размещению на WEB сервере
 
Ход работы
 
Создать форму для выполнения расчетов вида:
 

 
Указания: в редакторе FrontPage с помощью команды Вставка - Форма вставьте новую форму и удалите на ней все кнопки.
На форму добавьте таблицу с параметрами: размер - 6х2; выравнивание - по центру; ширина - 600 точек; ширина границы - 0.
В соответствующих ячейках введите текстовые надписи и поля.
Для выпадающего списка выполните команду Вставка - Форма - Раскрывающийся список. Двойным щелчком раскройте список, с помощью кнопки Добавить создайте новый элемент, введите текст элемента (сумма, разность, произведение, частное) и установите флажок Значение (убедитесь, что значение совпадает с текстом элемента флажка). Повторите эту операцию для всех элементов списка.
На форме с помощью команды Вставка - Форма - Кнопка создайте кнопку Рассчитать. Двойным щелчком на кнопке раскройте окно свойств и выберите тип кнопки Отправить. Аналогично рядом создайте кнопку с надписью Очистить.
 
Для обработки формы в будущей программе пометьте нужные элементы страницы текстовыми метками в формате:
 
<#имя>
 
Указания: перейдите на закладку С разделением.
В нижней части выделите первое текстовое поле. В верхней части в тег этого поля введите текстовую метку:
 
<input type="text" name="T1" size="20" value="<#t1>">
 
В нижней части выделите второе текстовое поле. В верхней части в тег этого поля введите текстовую метку:
 
<input type="text" name="T1" size="20" value="<#t2>">
 
В нижней части выделите третье текстовое поле. В верхней части в тег этого поля введите текстовую метку:
 
<input type="text" name="T1" size="20" value="<#t3>">
 
Для каждого элемента списка также нужно присвоить тпекстовую метку. В нижней части окна выделите список. В верхней части окна для каждого тегoption (тег элемента списка) введите текстовую метку:
 
<select size="1" name="D1">
<option <#sel1> value="Сумма">Сумма</option>
<option <#sel2> value="Разность">Разность</option>
<option <#sel3> value="Произведение">Произведение</option>
<option <#sel4> value="Частное">Частное</option>
</select></td> 
 
Каждая кнопка должна выполнять какую-то программу с передачей в нее содержимого всех элементов на форме.
 
Указания: предположим, что наша будущая программа будет называться raschet.exe.
Расчет будем выполнять с помощью запуска программы с ключом /calc. В коде страницы найдите тег form первой формы и в параметре action укажите имя вызываемой программы:
 
<form method="POST" action="/cgi/raschet.exe/calc">
 
Не забудьте удалить текст комментария после тега form.
 
Сохраните созданную страницу под именем form.htm с отдельную папку.
 
В Delphi создайте программу для обработки данных формы.
 
Указания: в среде Delphi выполните команду File - New - Other. В окне выберите тип приложения "WEB Server Applacation" и щелкните ОК. В результате откроется окно, в котором выберите тип проекта "CGI Stand-alone executable". Будет создан новый проект и откроется окно WebModule.
 
Сохраните проект в ту же папку, в которой находится созданная ранее страница с формой. Обязательно задайте имя проекта raschet. Если пролект сохранен под другим именем, то выполните команду File - Save Project As... и введите нужное имя.
 
Для подключения к проекту вашей страницы в окно WebModule добавьте компонент PageProducer (Internet) и для него задайте свойство: HTMLFile - ваш файл с формой (обязательно удалите путь к файлу).
 
Для модуля создадим два действия.
Первое действие
 
Данное действие выполняется по умолчанию при загрузке страницы и оно же выполняется при щелчке на кнопке Очистить на форме.
Для добавления действия щелкните два раза на пустом месте окна WebModule ив открывшемся окне редактора действий щелкните на первой кнопке (Add New). В результате будет добавлено первое действие. Чтобы это действие выполнялось по умолчанию, задайте для него свойство Default=true.
Данное действие сбрасывает все элементы формы в начальные значения и посылает их в браузер. Выделите действие и в его событии OnAction введите код:
 
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
    //первое поле по умолчанию сбрасывается в 0
    t1:='0';
    //второе поле по умолчанию сбрасывается в 0
    t2:='0';
    //третье поле по умолчанию сбрасывается в 0
    t3:='0';
    //в списке выбирается первый элемент
    list:=1;
    //посылаем команду браузеру на загрузку содержимого HTML файла
    response.content:=pageproducer1.content;
end;
 
Используемые переменные будут использоваться в нескольких подпрограммах, поэтому их нужно описать как глобальные:
 
//переменные для хранения значений текстовых полей
t1,t2,t3:string;
//переменная для хранения номера выбранного элемента списка
list:integer;
 
Второе действие
 
Данное действие выполняется при щелчке на кнопке формы Рассчитать. Чтобы программа различала, какое действие из имеющихся нужно выполнять, каждому действию нужно присвоить уникальный параметр. В нашем случае ранее на форме мы указывали, что кнопка Рассчитать запускает нашу программу с параметром /calc. Это означает, что запустится наша программа и выполнит действие с параметром /calc.
 
Для добавления второго действия щелкните два раза на пустом месте окна WebModule ив открывшемся окне редактора действий щелкните на первой кнопке(Add New). В результате будет добавлено новое действие. Для действия зададим имя параметра для вызова. Для этого укажите свойство: PathInfo=/calc
Данное действие получает значения элементов с формы, выполняет  расчет и посылает все данные в браузер.. Выделите действие и в его событии OnActionвведите код:
 
procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
    //проверим какая кнопка была нажата
    //если нажата кнопка "Очистить"
    if request.ContentFields.values['B2']='Очистить' then
    begin   
        //загружаем наше приложение с действием по умолчанию
        response.SendRedirect('/cgi/raschet.exe');
        //завершаем работу процедуры
        exit;
    end;
 
    //в противном случае (если нажата кнопка "Рассчитать")   
    //считываем в переменные значения полей T1 и Т2
    t1:=request.ContentFields.values['t1'];
    t2:=request.ContentFields.values['t2'];
 
    //если в списке (его имя на форме D1) выбрана строка "сумма"
    if request.ContentFields.values['D1']='Сумма' then
    begin
        //считаем сумму и запоминаем номер элемента списка
        t3:=floattostr(strtofloat(t1)+strtofloat(t2));
        list:=1;
    end
    //если в списке выбрана строка "разность"
    else if request.ContentFields.values['D1']='Разность' then
    begin
        //считаем разность и запоминаем номер элемента списка
        t3:=floattostr(strtofloat(t1)-strtofloat(t2));
        list:=2;
    end
    //если в списке выбрана строка "прозведение"
    else if request.ContentFields.values['D1']='Произведение' then
    begin
        //считаем произведение и запоминаем номер элемента списка
        t3:=floattostr(strtofloat(t1)*strtofloat(t2));
        list:=3;
    end
    else
    //если в списке выбрана строка "частное"
    begin
        //считаем частное и запоминаем номер элемента списка
        if strtofloat(t2)<>0 then
            t3:=floattostr(strtofloat(t1)/strtofloat(t2))
        else
            t3:='деление на 0';
        list:=4;
    end;
    //посылаем команду браузеру на загрузку содержимого HTML файла
    response.Content:=pageproducer1.Content;
end;
 
Отображение значений переменных на форме страницы
 
После задания значения всех переменных их нужно отобразить на странице в браузере. Для этого мы воспользуемся теми текстовыми метками, которыми мы ранее пометили нужные элементы на странице.
 
Для выполнения такой замены выделите компонент PageProducer и в его событии OnHTMLTag введите код:
 
procedure TWebModule1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag; const TagString: String; TagParams: TStrings; var ReplaceText: String);
begin
 
    //находим метку <#t1>
    //и на ее место ставим значение переменной t1
    if tagstring='t1' then
        replacetext:=t1;
 
    //находим метку <#t2>
    //и на ее место ставим значение переменной t2
    if tagstring='t2' then
        replacetext:=t2;
 
    //находим метку <#t3>
    //и на ее место ставим значение переменной t3
    if tagstring='t3' then
        replacetext:=t3;
 
    //проверяем номер выбранного элемента списка
    case list of
        //если выбран первый элемент
        //находим метку <#sel1> (соответствует первому элементу на форме)
        //и на ее место ставим значение переменной selected (выбран по умолчанию)
        1: if tagstring='sel1' then
            replacetext:='selected';
       
        //если выбран второй элемент
        //находим метку <#sel2> (соответствует второму элементу на форме)
        //и на ее место ставим значение переменной selected
        2: if tagstring='sel2' then
            replacetext:='selected';
 
        //если выбран третий элемент
        //находим метку <#sel3> (соответствует третьему элементу на форме)
        //и на ее место ставим значение переменной selected
        3: if tagstring='sel3' then
            replacetext:='selected';
 
        //если выбран четвертый элемент
        //находим метку <#sel4> (соответствует четвертому элементу на форме)
        //и на ее место ставим значение переменной selected
        4: if tagstring='sel4' then
            replacetext:='selected';
    end;
end;
 
Разместите созданную программу на WEB сервер и проверьте ее работу.
 
Указания: распакуйте архив сервера Denwer. Для запуска сервера запустите файл denwer/run.exe.
В папку home/localhost/cgi скопируйте файлы raschet.exe и form.htm.
Запустите браузер и введите адрес:
 
localhost/cgi/raschet.exe
 
Проверьте работу вашей программы.
Індивідуальне завдання № 1
 
1. Спроектуйте форму, яка відображається по центру екрана. Для форми задайте фіксовану границю й приберіть кнопку розкриття на весь екран. У якості заголовка форми введіть прізвище й номер варіанта.
 
 
 
2. На формі виконати розрахунки функції за умовою згідно свого варіанта. При цьому керуючі елементи розмістити відповідно до гілок виконання програми
 
3. Вихідні дані заповнювати шляхом вибору значення зі списку й клацання на відповідній кнопці для запису обраного значення в поле. За замовчуванням усі поля на формі заблоковані для редагування
 
4. Передбачити можливість додавання нових елемента в список і видалення їх зі списку (обробляти ситуацію, коли додавати або видаляти нема чого). При додаванні й видаленні даних запитувати дозвіл на виконання операції
 
5. Результати розрахунків кожного кроку вивести в поле, яке відповідає певній гілці роботи алгоритму
 
6. Унизу форми передбачити настроювання параметрів вводу й виводу . У групі «Редактирование и очистка» за допомогою перемикачів можна дозволити або заборонити введення вихідних даних із клавіатури. Прапорець «Проводить очистку» вказує, що поля з вихідними даними можна очистити відповідною кнопкою «Очистить»
 
7. У групі «Расчет и вывод» за допомогою перемикачів можна вказати вид виводу результатів (повідомленням або в новій формі) по кнопці «Вывести»
 
8. Усі операції: розрахунки, очищення, висновок, закриття програми виконувати тільки з дозволу користувача, шляхом видачі відповідного питання
 
9. Звернути увагу на порядок переходу по елементах за допомогою клавіші TAB: елементи, які служать для відображення результатів розрахунків не повинні бути доступні по клавіші TAB
 
 
Варіанти завдань
 
№ за списком Функція 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Індивідуальне завдання № 2
 
1. Створіть форму, яка буде з'являтися по центру екрана з фіксованими границями й без кнопок згортання й розгортання вікна. Задайте значок іконки для вікна. У заголовку форми відображається кількість спроб, що залишилися в користувача для введення пароля.
 
 
 
Вікно призначене для реєстрації користувача в програмі. Користувачеві необхідно ввести ім'я й прізвище, а також пароль, розбитий на п'ять частин по шість символів у кожній. Усі поля у формі повинні підтримувати вавтоматичний перехід до наступного поля при введенні шести символів. Сам пароль користувач не повинен бачити (відображати символ *).
По кнопці ОК спочатку перевіряється, чи заповнив користувач поля Прізвище й Ім'я. Якщо ні, то видається повідомлення й курсор переходить у незаповнене поле.
Потім перевіряється введений пароль згідно варіанта. У випадку невірного введення пароля повинне видаватися повідомлення про помилку й користувач повинен знову ввести його (при цьому курсор автоматично стає на перше поле вводу). У випадку невірного введення пароля N раз ( N-число спроб уведення, див. свій варіант) додаток блокується (вид блокування див. у своєму варіанті) і продовження роботи із програмою стає неможливим.
2. У випадку вірного введення пароля відбувається вхід у систему й користувач отримує доступ до форми по роботі з текстом. Форма повинна відображатися по центру екрана і підтримувати масштабування елементів на ній. Задайте значок іконки для форми. У заголовку вікна необхідно відобразити текст, що інформує про користувача системи (див. свій варіант). На формі розмістіть багаторядкове текстове поле й додатковий компонент згідно варіанта.
 
Варіанти завдань 
№ за списком Алгоритм формування пароля Кількість спроб уведення Вид блокування Заголовок вікна Компонент на формі
1 сума кодів непарних символів рівна заданій 2 заблокувати кнопку "ОК" і на ній вивести текст "Помилка" Працює: Прізвище Ім'я Кнопка для виклику діалогу форматування тексту в полі
2 кожний непарний символ - цифра 3 сховати два перші текстові поля й на їхньому місці вивести текст "Помилка" Привіт користувачеві: Ім'я Кнопка для виклику діалогу вибору кольору фона в полі
3 кожний перший символ у кожному полі - рядкова латинська буква 4 сховати поля "Прізвище" і "Ім'я", на їхньому місці видати повідомлення "Помилка" і заблокувати кнопку "ОК" Ласкаво просимо: Прізвище перша буква імені Список для вибору кольору фона в полі
4 кожний останній символ у кожному полі - прописна латинська буква 1 видати повідомлення про останню спробу, заблокувати кнопку "ОК" і на ній написати "Помилка" Відкритий сеанс для: Прізвище Ім'я Кнопка для виклику діалогу форматування всього тексту на формі
5 сума кодів символів у непарних полях збігається 3 сховати останні два текстові поля й на їхньому місці вивести текст "Помилка" Добрий день: Ім'я Прізвище Кнопка для виклику діалогу вибору кольору фона всієї форми
6 кожний непарний символ у парних полях - прописна латинська буква 4 видати повідомлення про останню спробу, на місці поля "Ім'я" вивести текст "Помилка" Поточний користувач: Прізвище Список для вибору кольору фона всієї форми
7 кожний третій символ у паролі - цифра 3 сховати кнопку "ОК" і на її місці вивести текст "Помилка" Реєстрація для: Прізвище перша буква імені Кнопка для виклику діалогу форматування тексту в полі
8 сума кодів парних символів у паролі рівна заданій 4 видати повідомлення про останню спробу,  сховати кнопку "ОК" і на її місці вивести текст "Помилка" Роботу проводить: Прізвище Кнопка для виклику діалогу вибору кольору фона в полі
9 середній символ у кожному полі - рядкова латинська буква 2 сховати всі текстові поля й на їхньому місці вивести текст "Помилка" Поточний сеанс: Ім'я Список для вибору кольору фона в полі
10 кожний другий символ у полі цифра, а третій - заголовна латинська буква 2 заблокувати кнопку "ОК" і в заголовку вікна видати повідомлення про блокування Будемо знайомі: перша буква імені Прізвище Кнопка для виклику діалогу форматування всього тексту на формі
11 сума кодів парних символів дорівнює сумі кодів непарних 4 заблокувати всі текстові поля, у заголовку вікна вивести повідомлення про блокування Програма відкрита для: Прізвище Ім'я Кнопка для виклику діалогу вибору кольору фона всієї форми
12 кожне поле починається й закінчується цифрою 3 сховати всі елементи на формі ( крім кнопки "Скасування") вивести повідомлення "Помилка" Привіт: Ім'я Прізвище Список для вибору кольору фона всієї форми
13 сума кодів непарних символів рівна заданій 5 видати повідомлення про останню спробу, на місці поля "Ім'я" вивести текст "Помилка" Реєстрація для: Прізвище перша буква імені Кнопка для виклику діалогу форматування тексту в полі
14 кожний непарний символ - цифра 4 заблокувати кнопку "ОК" і в заголовку вікна видати повідомлення про блокування Роботу проводить: Прізвище Кнопка для виклику діалогу вибору кольору фона в полі
15 кожний перший символ у кожному полі - рядкова латинська буква 3 видати повідомлення про останню спробу, заблокувати кнопку "ОК" і на ній написати "Помилка" Поточний користувач: Прізвище Список для вибору кольору фона в полі
16 кожний останній символ у кожному полі - прописна латинська буква 2 сховати всі елементи на формі ( крім кнопки "Скасування") , вивести повідомлення "Помилка" Поточний сеанс: Ім'я Кнопка для виклику діалогу форматування всього тексту на формі
17 сума кодів символів у непарних полях збігається 3 сховати кнопку "ОК" і на її місці вивести текст "Помилка" Добрий день: Ім'я Прізвище Кнопка для виклику діалогу вибору кольору фона всієї форми
18 кожний непарний символ у парних полях - прописна латинська буква 5 заблокувати всі текстові поля, у заголовку вікна вивести повідомлення про блокування Будемо знайомі: перша буква імені Прізвище Список для вибору кольору фона всієї форми
19 кожний третій символ у паролі - цифра 4 заблокувати кнопку "ОК" і на ній вивести текст "Помилка" Відкритий сеанс для: Прізвище Ім'я Кнопка для виклику діалогу форматування тексту в полі
20 сума кодів парних символів у паролі рівна заданій 2 видати повідомлення про останню спробу,  сховати кнопку "ОК" і на її місці вивести текст "Помилка" Програма відкрита для: Прізвище Ім'я Кнопка для виклику діалогу вибору кольору фона в полі
21 середній символ у кожному полі - рядкова латинська буква 3 сховати всі елементи на формі ( крім кнопки "Скасування"), вивести повідомлення "Помилка" Ласкаво просимо: Прізвище перша буква імені Список для вибору кольору фона в полі
22 кожний другий символ у поле цифра, а третій - заголовна латинська буква 3 сховати поля "Прізвище" і "Ім'я", на їхньому місці видати повідомлення "Помилка" і заблокувати кнопку "ОК" Привіт: Ім'я Прізвище Кнопка для виклику діалогу форматування всього тексту на формі
23 сума кодів парних символів дорівнює сумі кодів непарних 4 сховати всі текстові поля й на їхньому місці вивести текст "Помилка" Привіт користувачеві: Ім'я Кнопка для виклику діалогу вибору кольору фона всієї форми
24 кожне поле починається й закінчується цифрою 5 сховати два перші текстові поля й на їхньому місці вивести текст "Помилка" Будемо знайомі: перша буква імені Прізвище Список для вибору кольору фона всієї форми
25 сума кодів непарних символів рівна заданій 3 сховати останні два текстові поля й на їхньому місці вивести текст "Помилка" Працює: Прізвище Ім’я Кнопка для виклику діалогу форматування тексту в полі

1. Яке із тверджень не відноситься до синтаксису мови Object Pascal?
 
1) усі використовувані змінні, функції й процедури повинні бути описані до їхнього використання
2) кожний оператор закінчується крапкою з комою
3) прописні й малі літери в іменах ідентичні
4) описати змінні можна в будь-якому місці програми, але до їхнього використання в коді
5) усі твердження вірні
 
2. Яка з назв не є цілим типом даних в Object Pascal?
 
1) Word
2) Cardinal
3) Integer
4) Shortint
5) Bit
6) усі назви відповідають іменам цілих типів
 
3. Який із зазначених цілих типів Object Pascal є родовим?
 
1) Word
2) Integer
3) Longword
4) Shortint
 
4. Яка з назв не є речовинним типом даних в Object Pascal?
 
1) Real
2) Single
3) Double
4) Extension
5) усі назви є назвами речовинних типів
 
5. Який з речовинних типів Object Pascal є родовим?
 
1) Single
2) Real
3) Double
4) Comp
 
6. Який із зазначених символьних типів Object Pascal дозволяє зберігати символи національних алфавітів?
 
1) Ansichar
2) Char
3) Widechar
4) у будь-якому типі можна зберігати таку інформацію
 
7. Який зі строкових типів Object Pascal дозволяє зберігати текст у національному кодуванні?
 
1) String
2) Shortstring
3) Ansistring
4) усі типи підходять для цього
 
8. Для того щоб описати глобальну для модуля змінну необхідно
 
1) описати змінну в розділі Var після ключового слова Interface
2) описати змінну в розділі Var усередині будь-якої процедури в розділі Implementation
3) описати змінну в розділі Var після ключового слова Implementation
4) немає правильної відповіді
 
9. Для того щоб описати глобальну для проекту змінну необхідно
 
1) описати змінну в розділі Var усередині будь-якої процедури в розділі Implementation
2) описати змінну в розділі Var після ключового слова Interface
3) описати змінну в розділі Var після ключового слова Implementation
4) немає правильної відповіді
 
10. Для того щоб описати локальну для конкретної процедури або функції модуля змінну необхідно
 
1) описати змінну в розділі Var усередині потрібної процедури в розділі Implementation
2) описати змінну в розділі Var після ключового слова Implementation
3) описати змінну в розділі Var після ключового слова Interface
4) усі змінні в модулі можуть бути або глобальними для модуля, або глобальними для проекту
 
1. Файл проекту в Delphi має розширення
 
1) *.prj
2) *.dpr
3) *.prg
4) *.drp
 
2. Файл форми в Delphi має розширення
 
1) *.frm
2) *.dfr
3) *.dfm
4) *.fdm
 
3. Відкомпільований файл модуля Delphi має розширення
 
1) *.pas
2) *.exe
3) *.dps
4) *.dcu
 
4. Що дозволяє створити в  проекті Delphi команда File-New-Other?
 
1) новий порожній проект
2) створити новий проект, форму, фрейм на основі наявних зразків
2) будь-який порожній об'єкт проекту: сам проект, форму, модуль і т.і.
3) створити будь-який об'єкт проекту на основі наявних зразків
4) створити тільки новий проект на основі наявних зразків
5) створити тільки нову форму або фрейм на основі наявних зразків
 
5. Для введення інформації про версію продукту необхідно
 
1) виконати команду Project-Options і перейти на вкладку About
2)  виконати команду Project-Options і перейти на вкладку Info Version
3) виконати команду Project-Options і перейти на вкладку Version About
4) виконати команду Project-Options і перейти на вкладку Version Info
5) немає правильної відповіді
1. З описаних тверджень виберіть те, яке не відноситься до головної форми проекту
 
1) при запуску проекту саме ця форма одержує керування
2) головна форма може бути спроектована невидимою
3) головною формою може бути тільки перша форма, створена при відкритті нового проекту
4) закриття головної форми в будь-якому місці коду веде до завершення роботи всієї програми
 
2. Для зміни головної форми проекту потрібно
 
1) Виконати команду Project-Options і перейти на вкладку Mainform
2) Виконати команду Project-Options і перейти на вкладку Projectforms
3) Виконати команду Project-Options і перейти на вкладку Forms
4) Виконати команду Project-Options і перейти на вкладку Formslist
 
3. Для відкриття форми як модальної потрібно викликати метод форми
 
1) Form.Show
2) Form.Open  Modal
3) Form.Openmodal
4) Form.Showmodal
5) Form.Modalshow
6) Form.Show  Modal
 
4. Як називається подія, яка виникає перед закриттям форми й слугує для видачі запиту на вихід із програми?
 
1) Onqueryclose
2) Onqueyunload
3) Onclose
4) Onclosequery
 
5. Для того щоб форма не закривалася, якщо користувач не підтвердив цю операцію, необхідно в оброблювач потрібної події вставити оператор
 
1) Canclose:=false
2) Closecan:=true;
3) Close:=true;
4) Canclose:=true;
5) Close:=false;
5) немає правильної відповіді
 
6. Для того щоб форма була прихована з екрана, але не віддалялася з пам'яті, потрібно викликати метод
 
1) Form.Hide; 
2) Form.Haid;
3) Form.Close;
4) Form.Destroy;
 
7. Для додавання форми в проект Delphi потрібно виконати команду (вибрати невідповідне)
1) File-newform
2) Project – Add to Project і вказати файл готової форми
3) File-New-Other і вибрати зразок потрібної форми
4) File-New-Form
 
8. Для видалення форми із проекту потрібно виконати команду
 
1) File-removeform
2) File-Remove-Form
3) Project-removeform
4) Project-Remove from Project
5) File – Deleteform
 
9. Серед наведених назв укажіть ту, яке не є типом запозичення форм із депозитарію
 
1) use
2) copy
3) browse
4) inherit
 
 
10. До якого з типів запозичення форми з депозитарію відноситься даної твердження: екземпляр форми успадковує оригінал із депозитарія?
 
1) copy
2) browse
3) inherit
4) use
 
11. До якого з типів запозичення форми з депозитарію відноситься даної твердження: у проект включається оригінал форми з депозитарію?
 
1) browse
2) use
3) copy
4) inherit
 
12. Яка властивість форми визначає ступінь прозорості вікна?
 
1) Alphacolorvalue
2) Alphablend
3) Alphablendvalue
4) Transparentvalue
 
13. Яка властивість форми відміняє автоматичне відображення смуг прокручування?
 
1) Autoscrollbars
2) Scrollbars
3) Autoscroll
4) немає правильної відповіді
 
14. Яка властивість форми визначає положення вікна форми при запуску?
 
1) Desktop
2) Positionform
3) Formposition
4) Position
 
15. Що задає властивість форми Transparent?
 
1) робить форму прозорою
2) задає колір, який стане прозорим на формі
3) якщо рівний True, то визначений колір (заданий  у властивості Transparet Color) буде прозорим на формі
4) такої властивості немає
 
16. Функція введення даних із клавіатури має вигляд
 
1) inputbox (‘ текст-підказка’, ‘значення за замовчуванням’, ‘заголовок’)
2) inputbox (‘ текст-підказка’, ‘заголовок’, ‘значення за замовчуванням’)
3) inputbox (‘заголовок’, ‘ текст-підказка’, ‘значення за замовчуванням’)
4) inputbox (‘значення за замовчуванням’, ‘ текст-підказка’, ‘заголовок’)
 
17. Для видачі вікна з текстом в Delphi використовується команда
 
1) Showmessage ‘текст’;
2) Showmessage (текст);
3) Showmessage (‘текст’);
4) Showmessage текст;
 
18. Для видачі діалогового вікна із запитом використовують процедуру виду
 
1) application.messagebox (‘заголовок’, ‘ текст-підказка’, прапори);
2) application.messagebox (‘текст_підказка’, прапори, ‘заголовок’);
3) application.messagebox (‘текст_підказка’, ‘заголовок’, прапори);
4) application.messagebox (‘заголовок’, прапори, ‘ текст-підказка’);
 
 1. До якоі із властивостей компонента Label відноситься твердження: якщо властивість рівна True, то розмір компонента визначається розміром тексту на ньому?
 
1) Autoscroll
2) Width
3) Autosize
4) Height
 
2. Якщо властивість Wordwrap компонента Label рівна true, то це означає
 
1) автоматичний підгін розміру компонента під розмір тексту
2) автоматичне перенесення тексту на новий рядок
3) автоматичне відображення смуг прокручування
4) немає правильної відповіді
 
3. Для присвоєння «гарячої» клавіші компоненту, пов'язаному з міткою (Label), необхідно (вибрати невірне)
 
1) перед «гарячим» символом у тексті мітки ввести символ «&»
2) у властивості форми Keypreview вибрати true
3) у властивості мітки Focuscontrol вибрати компонент, що зв'язується з «гарячим» символом
4) у властивості мітки Showaccelchar вибрати true
 
4. Якщо властивість Autosize у компоненті Edit установлена в true, то це означає
 
1) висота й ширина поля підганяється під розмір тексту
2) під розмір тексту підганяється тільки ширина компонента
3) під розмір тексту підганяється тільки висота компонента
4) такої властивості у компонента Edit немає
 
5. Для блокування текстового поля для введення даних (без заборони доступу до поля) використовують властивість
 
1) enabled
2) visible
3) locked
4) readonly
 
6. Для чого використовується властивість Seltext компонента Edit?
 
1) для доступу до тексту компонента
2) для доступу до виділеного тексту в полі
3) для доступу до тексту, який залишився не виділеним у полі
4) такої властивості у компонента немає
 
7. Яка властивість компонента Labelededit служить для форматування напису?
 
1) caption
2) edit
3) label
4) editlabel
 
8. Для того щоб кнопка на формі реагувала на натискання клавіші Enter, використовується властивість кнопки
 
1) click
2) cancel
3) default
4) keypreview
 
9. Для того щоб кнопка на формі реагувала на натискання клавіші Esc, використовується властивість кнопки
 
1) default
2) click
3) keypreview
4) cancel
 
10. Для задавання малюнка на кнопці Bitbtn використовують властивість
 
1) picture
2) icon
3) glyph
4) image
 
11. Для чого використовується властивість Margin компонента Bitbtn?
 
1) для вирівнювання малюнка на кнопці
2) для задавання відступів малюнка від країв кнопки
3) для задавання розміщення малюнка на кнопці щодо напису
4) такої властивості немає
 
12. Для задавання оформлення кнопки Bitbtn шляхом вибору однієї з наявних заготовок використовують властивість
 
1) maket
2) example
3) kind
4) style
1. Для зв'язування компонента Updown з текстовим полем використовується властивість
 
1) text
2) associate
3) link
4) value
 
2. Для розміщення кнопок Updown ліворуч або праворуч від текстового поля використовують властивість
 
1) orientation
2) alignment
3) alignbutton
4) немає правильної відповіді
 
3. Для зміни значення компонента Updown по кільцю потрібно встановити в true властивість
 
1) circle
2) round
3) wrap
4) textwrap
 
4. Для зчитування значення компонента Updown використовують властивість
 
1) text
2) value
3) number
4) position
 
5. Яке із тверджень не відноситься до компонента Spinedit?
 
1) значення компонента знаходиться у властивості value
2) компонент знаходиться на вкладці Samples
3) для зв'язування компонента з полем використовують властивість associate
4) для завдання мінімального значення зміни лічильника використовують властивість minvalue
 
6. Для введення списку значень у компонент Listbox використовують властивість
 
1) list
2) text
3) items
4) lines
 
7. Для швидкого переходу в списку Listbox на потрібний рядок по перших уведених символах використовують властивість
 
1) autoserch
2) autotext
3) autoselect
4) autocomplete
 
8. Для звертання до елемента списку Listbox по його номеру використовують властивість
 
1) rownumber
2) indexitem
3) itemindex
4) itemnumber
 
9. Для видалення рядка зі списку Listbox використовують команду
 
1) Listbox.items.remove (Listbox.itemindex)
2) Listbox.items.delete (Listbox.indexitem)
3) Listbox.delete (Listbox.itemindex)
4) Listbox.remove (Listbox.indexitem)
5) Listbox.items.delete (Listbox.itemindex)
 
10. Для додавання рядка в компонент Listbox використовують команду
 
1) Listbox.add ‘текст’
2) Listbox.add (текст)
3) Listbox.items.add ‘текст’
4) Listbox.items.add (текст)
 
11. Якщо поле в компоненті Combobox потрібно заблокувати для введення значень із клавіатури, то в його властивості style потрібно вибрати значення
 
1) dropdown
2) dropdownlist
3) simple
4) readonlylist
 
12. Яке із тверджень не відноситься до компонента Radiogroup?
 
1) перемикачі автоматично вирівнюються усередині компонента
2) для створення перемикачів досить увести їхні назви у властивості list
3) перемикачі можна розміщати в декілька колонок за допомогою властивості columns
4) для звертання до перемикача використовують властивість itemindex
5) усі твердження вірні
 
13. За допомогою якої властивості можна визначити, чи включений компонент Radiobutton?
 
1) value
2) check
3) itemindex
4) checked
5) немає правильної відповіді
 
14. Розміщення напису компонента Checkbox ліворуч або праворуч задається властивістю
 
1) alignment
2) align
3) orientation
4) position
 
15. Яке із тверджень не відноситься до компонента Imagelist?
 
1) містить колекцію картинок для їхнього використання в програмі
2) нумерація картинок у компоненті починається з 0
3) додавання нового зображення виконується командою Insert
4) видалення зображення зі списку виконується за допомогою кнопки Delete
5) усі твердження вірні
 
16. Яке із тверджень не відноситься до компонента Pagecontrol?
 
1) дозволяє розміщати множину компонентів в одній формі за рахунок їх поділу по окремих сторінках
2) для додавання нової сторінки в контекстному меню компонента потрібно вибрати команду New Page
3) вкладки компонента можуть розміщатися біля будь-якого краю компонента
4) на вкладках можна розміщати зображення
5) усі вкладки мають однакову ширину по найдовшому тексту
 
17. Що задає властивість Pageindex компонента Pagecontrol?
 
1) номер компонента, розміщеного на сторінці
2) номер сторінки в поточному рядку. Використовується, якщо вкладки розміщаються в кілька рядків
3) номер вкладки незалежно від розбивки на рядки
4) номер рядка вкладок
 
18. Для присвоєння компоненту Pagecontrol колекції малюнків використовують властивість
 
1) pictures
2) icons
3) images
4) imageindex
 
19. Для завдання положення вкладок компонента Pagecontrol використовують властивість
 
1) alignment
2) position
3) tabposition
4) orientation
1. Яке із тверджень не відноситься до компонента Memo?
 
1) дозволяє вводити текст у кілька рядків
2) автоматично підтримує роботу з буфером обміну через контекстне меню
3) перехід на новий рядок у компоненті відбувається автоматично
4) знаходиться на вкладці компонентів Additional
 
2. Яка властивість компонента Memo дозволяє відредагувати текст у ньому при проектуванні форми?
 
1) lines
2) text
3) items
4) wordwrap
 
3. Яка властивість компонента Memo задає автоматичний перехід тексту на новий рядок?
 
1) текст переходить на новий рядок сам без завдання властивостей
2) wrap
3) wordwrap
4) wordenter
 
4. Для очищення вмісту компонента Memo використовують метод
 
1) clear
2) cls
3) delete
4) clstext
 
5. Для виділення всього тексту в компоненті Memo використовують метод
 
1) select
2) allselect
3) selectall
4) selecttext
 
6. Для додавання рядка тексту в компоненті Memo використовую метод
 
1) memo1.add (текст);
2) memo1.text.add(текст);
3) memo1.add.lines(текст);
4) memo1.add.text(текст);
5) memo1.lines.add(текст);
 
7. Для копіювання виділеного фрагмента поля Memo у буфер обміну використовують команду
 
1)  memo1.copytoclipboard;
2) memo1.seltext.copy;
3) memo1.seltext.copytoclipboard;
4) memo1.copy.seltext;
5) memo1.copytoclipboard.seltext;
 
8. Для вставки вмісту буфера обміну в поле Memo використовують команду
 
1) memo1.paste;
2) memo1.paste.text;
3) memo1.pastefromclipboard;
4) memo1.text.pastefromclipboard;
 
9. Для збереження вмісту компонента Memo у файл використовують команду
 
1) memo1.savetofile(ім'я_файлу);
2) memo1.lines.savetofile(ім'я_файлу);
3) memo1.lines.save(ім'я_файлу);
4) memo1.lines.savefile(ім'я_файлу);
 
10. Для зчитування вмісту файлу в компонент Memo використовують команду
 
1) memo1.loadfile(ім'я_файлу);
2) memo1.lines.loadfile(ім'я_файлу);
3) memo1.lines.openfromfile(ім'я_файлу);
4) memo1.lines.loadfromfile (ім'я_файлу);
 
11. Яка із зазначених назв є властивістю компонента Fontdialog, що задає максимальний розмір шрифту?
 
1) maxfontsize
2) maxsize
3) maxsizefont
4) maxfont
 
12. Що задає властивість Device компонента Fontdialog?
 
1) ім'я диска, на якому зберігаються шрифти
2) ім'я принтера, на який планується виводити документи
3) список шрифтів, відображуваних у діалозі
4) немає правильної відповіді
 
13. Якщо в діалозі Fontdialog є кнопка Застосувати, то код для неї пишуть у події діалогу
 
1) Onclick
2) Onrun
3) Onapply
4) Onshow
 
14. У якій властивості компонента Colordialog зберігається обраний користувачем колір?
 
1) Color
2) Value
3) Colorvalue
4) Valuecolor
 
15. На якій вкладці знаходиться компонент Colorbox?
 
1) Standard
2) Additional
3) Win32
4) System
 
16. Для визначення кольору, обраного користувачем у компоненті Colorbox, використовується властивість
 
1) color
2) selected
3) select
4) value
1. Яка функція дозволяє визначити ім'я поточної папки?
 
1) getcurrentdir()
2) getdircurrent()
3) getdir()
4) currentdir()
 
2. За допомогою якої властивості можна визначити повний шлях до файлу програми?
 
1) application.path
2) application.exename
3) application.fullname
4) application.fullpath
 
3. Яка функція дозволяє виділити з повного шляху ім'я диска?
 
1) extractdrivename
2) extractdrivefile
3) extractfulldrive
4) extractfiledrive
 
4. Яка функція дозволяє виділити з повного шляху ім’я папки?
 
1) extractpath
2) extractfilepath
3) extractfullpath
4) extractpathfile
 
5. Яка функція дозволяє виділити з повного шляху ім'я файлу?
 
1) extractnamefile
2) extractname
3) extractfilename
4) extractfile
 
6. Яка функція дозволяє виділити з повного шляху розширення файлу?
 
1) extractextfile
2) extractfileext
3) extractext
4) extractfile
 
7. Яка функція дозволяє створити папку?
 
1) newdip()
2) createpath()
3) createdir()
4) createfolder()
 
8. Яка функція дозволяє перейти в зазначену папку?
 
1) opendir()
2) setcurrentfolder()
3) setcfolder()
4) setcurrentdir()
 
9. За допомогою якої функції можна перевірити існування папки на диску?
 
1) directoryexists()
2) folderexists()
3) pathexists()
3) existsfolder()
 
10. Яка функція дозволяє вилучити папку з диска?
 
1) erasedir()
2) deletedir()
3) deldir()
4) removedir()
 
11. Яке ім'я має клас для роботи з текстовими файлами?
 
1) tstring
2) tliststring
3) tlist
4) tstringlist
 
12. Який з методів не відноситься до класу роботи з текстовими файлами?
 
1) clear
2) savetofile
3) show
4) add
 
13. Який з методів не відноситься до класу роботи з текстовими файлами?
 
1) delete
2) close
3) loadfromfile
4) free
 
14. Як правильно описати змінну для роботи з екземпляром класу по роботі з текстовими файлами?
 
1) var t:string;
2) var t:tstringlist
3) var t:tlist
4) var t:tliststring
 
15. Який метод дозволяє створити новий екземпляр класу для роботи з текстовими файлами?
 
1) new
2) open
3) add
4) create
 
16. Який метод дозволяє видалити з пам'яті екземпляр класу для роботи з текстовими файлами?
 
1) free
2) close
3) erase
4) delete
 
17. Яка властивість класу по роботі з текстовими файлами зберігає кількість рядків тексту в класі?
 
1) lines
2) strings
3) count
4) items
 
18. Яка властивість класу по роботі з текстовими файлами зберігає текст рядка в класі?
 
1) lines[i]
2) strings(i)
3) strings[i]
4) lines(i)
 
19. Яка функція дозволяє скопіювати файл?
 
1) copy()
2) filecopy()
3) copy_file()
4) copyfile()
 
20. Як при записі функції копіювання файлів правильно конвертувати шлях до файлу, записаний у вигляді тексту?
 
1) str(’шлях’)
2) pchar(‘шлях’)
3) pstr(‘шлях’)
4) pansichar(‘шлях’)
 
21. Яка функція дозволяє перевірити існування файлу на диску?
 
1) fileopen()
2) existsfile()
3) fileexists()
4) openfile()
 
22. Яка функція дозволяє перейменувати файл?
 
1) rename()
2) renfile()
3) filerename()
4) renamefile(0
 
23. Для видалення файлу використовується функція:
 
1) delfile()
2) erasefile()
3) filedelete()
4) deletefile()
 
24. Ім'я файлу, зазначене в діалогах відкриття або збереження файлів зберігається у властивості
 
1) nameoffile
2) namefile
3) fileofname
4) filename
 
25. Для завдання каталогу за замовчуванням для діалогів відкриття й збереження файлів використовується властивість
 
1) defdir
2) initialdir
3) initdir
4) dirinitial
 
26. Якщо в діалогах відкриття або збереження файлів потрібно вказати розширення, що привласнюється файлам за замовчуванням, то використовують властивість
 
1) defaultext
2) extindex
3) defext
4) filterindex
 
27. Що задає властивість Filterindex
 
1) розширення, обране в діалозі
2) список типів файлів, доступних у діалозі
3) номер типу файлу, обраного в діалозі
4) немає правильної відповіді
1. Яка функція дозволяє визначити ім'я поточної папки?
 
1) getcurrentdir()
2) getdircurrent()
3) getdir()
4) currentdir()
 
2. За допомогою якої властивості можна визначити повний шлях до файлу програми?
 
1) application.path
2) application.exename
3) application.fullname
4) application.fullpath
 
3. Яка функція дозволяє виділити з повного шляху ім'я диска?
 
1) extractdrivename
2) extractdrivefile
3) extractfulldrive
4) extractfiledrive
 
4. Яка функція дозволяє виділити з повного шляху ім’я папки?
 
1) extractpath
2) extractfilepath
3) extractfullpath
4) extractpathfile
 
5. Яка функція дозволяє виділити з повного шляху ім'я файлу?
 
1) extractnamefile
2) extractname
3) extractfilename
4) extractfile
 
6. Яка функція дозволяє виділити з повного шляху розширення файлу?
 
1) extractextfile
2) extractfileext
3) extractext
4) extractfile
 
7. Яка функція дозволяє створити папку?
 
1) newdip()
2) createpath()
3) createdir()
4) createfolder()
 
8. Яка функція дозволяє перейти в зазначену папку?
 
1) opendir()
2) setcurrentfolder()
3) setcfolder()
4) setcurrentdir()
 
9. За допомогою якої функції можна перевірити існування папки на диску?
 
1) directoryexists()
2) folderexists()
3) pathexists()
3) existsfolder()
 
10. Яка функція дозволяє вилучити папку з диска?
 
1) erasedir()
2) deletedir()
3) deldir()
4) removedir()
 
11. Яке ім'я має клас для роботи з текстовими файлами?
 
1) tstring
2) tliststring
3) tlist
4) tstringlist
 
12. Який з методів не відноситься до класу роботи з текстовими файлами?
 
1) clear
2) savetofile
3) show
4) add
 
13. Який з методів не відноситься до класу роботи з текстовими файлами?
 
1) delete
2) close
3) loadfromfile
4) free
 
14. Як правильно описати змінну для роботи з екземпляром класу по роботі з текстовими файлами?
 
1) var t:string;
2) var t:tstringlist
3) var t:tlist
4) var t:tliststring
 
15. Який метод дозволяє створити новий екземпляр класу для роботи з текстовими файлами?
 
1) new
2) open
3) add
4) create
 
16. Який метод дозволяє видалити з пам'яті екземпляр класу для роботи з текстовими файлами?
 
1) free
2) close
3) erase
4) delete
 
17. Яка властивість класу по роботі з текстовими файлами зберігає кількість рядків тексту в класі?
 
1) lines
2) strings
3) count
4) items
 
18. Яка властивість класу по роботі з текстовими файлами зберігає текст рядка в класі?
 
1) lines[i]
2) strings(i)
3) strings[i]
4) lines(i)
 
19. Яка функція дозволяє скопіювати файл?
 
1) copy()
2) filecopy()
3) copy_file()
4) copyfile()
 
20. Як при записі функції копіювання файлів правильно конвертувати шлях до файлу, записаний у вигляді тексту?
 
1) str(’шлях’)
2) pchar(‘шлях’)
3) pstr(‘шлях’)
4) pansichar(‘шлях’)
 
21. Яка функція дозволяє перевірити існування файлу на диску?
 
1) fileopen()
2) existsfile()
3) fileexists()
4) openfile()
 
22. Яка функція дозволяє перейменувати файл?
 
1) rename()
2) renfile()
3) filerename()
4) renamefile(0
 
23. Для видалення файлу використовується функція:
 
1) delfile()
2) erasefile()
3) filedelete()
4) deletefile()
 
24. Ім'я файлу, зазначене в діалогах відкриття або збереження файлів зберігається у властивості
 
1) nameoffile
2) namefile
3) fileofname
4) filename
 
25. Для завдання каталогу за замовчуванням для діалогів відкриття й збереження файлів використовується властивість
 
1) defdir
2) initialdir
3) initdir
4) dirinitial
 
26. Якщо в діалогах відкриття або збереження файлів потрібно вказати розширення, що привласнюється файлам за замовчуванням, то використовують властивість
 
1) defaultext
2) extindex
3) defext
4) filterindex
 
27. Що задає властивість Filterindex
 
1) розширення, обране в діалозі
2) список типів файлів, доступних у діалозі
3) номер типу файлу, обраного в діалозі
4) немає правильної відповіді
1. У якій властивості форми можна вказати, що форма є головною MDI або дочірньою?
 
1) Formmdi
2) Formstyle
3) Formkind
4) немає правильної відповіді
 
2. Для опису змінної, потрібної для створення екземпляра дочірньої форми, використовують команду
 
1) var ім'я_пременной:ім'я_форми;
2) var ім'я_змінної:Tимя_форми;
3) var ім'я-форми:Tform;
4) немає правильної відповіді;
 
3. Яка властивість головної MDI форми служить для визначення кількості відкритих дочірніх форм?
 
1) Mdicount
2) Childcount
3) Mdichildcount
4) Mdichild
 
4. Для звертання до активної дочірньої форми в MDI додатках використовують властивість
 
1) activechild
2) activechildren
3) activemdichildren
4) activemdichild
5) activeform
 
5. Для впорядкування дочірніх форм каскадом використовується метод
 
1) kaskade
2) cascad
3) kascade
4) cascade
 
6. Для впорядкування дочірніх форм зверху вниз необхідно властивості Tile присвоїти значення
 
1) tbhorizontal
2) tbtoptobottom
3) tbvertical
4) tbtopbuttom
 
7. Якщо потрібно, щоб меню дочірньої форми поєднувалося з меню головної форми, то потрібно встановити в true наступну властивість дочірньої форми
 
1) automerge
2) autoadd
3) automenu
4) autochildmenu
 
8. Якщо значення властивості Groupindex пунктів меню головної й дочірньої форми збігається, то це означає що
 
1) ці пункти поєднуються
2) ці пункти заміняють один одного
3) однакових значень для цієї властивості бути не може
4) немає правильної відповіді
 
9. Для звертання до виділеного фрагмента в компоненті Richedit використовують властивість
 
1) seltext
2) selattributes
3) selecttext
4) sellines
 
10. Для завдання відступу першого рядка в компоненті Richedit  у властивості Paragraph є підвластивість
 
1) firstline
2) firsttext
3) firstindent
4) firstlines
 
11. Для створення маркірованого списку в компоненті Richedit у властивості Paragraph використовується підвластивість
 
1) markered
2) numbering
3) markerlist
4) markertext
 
12. Яка властивість компонента Richedit служить для завдання звичайного або форматованого формату тексту, що зберігається або відкривається
 
1) textformat
2) plaintext
3) textplain
4) formattext
1. Для завдання малюнка, відображуваного в компоненті Image, використовується властивість
 
1) icons
2) picture
3) image
4) pict
 
2. Для підгонки компонента Image під розмір завантаженого зображення використовується властивість
 
1) stretch
2) autosize
3) crop
4) center
 
3. Для підгонки розміру малюнка під розмір компонента Image використовується властивість
 
1) autosize
2) center
3) stretch
4) crop
 
4. Яке із тверджень не відноситься до компонента Image?
 
1) може відображати графічні файли на формах
2) може підганяти свій розмір під розмір малюнка
3) може містити кілька зображень одночасно
4) може відображати тільки центр малюнока, обрізаючи невидимі краї
 
5. Для очищення компонента Image використовують команду
 
1) image1.picture:='';
2) image1.picture:=null;
3) image1.picture:=nill;
4) image1.picture:=nil;
 
6. Для копіювання вмісту компонента Image у буфер обміну використовують команду
 
1) image1.picture.copytoclipboard;
2) image1.picture.copy(clipboard);
3) image1.picture.assign(clipboard);
4) clipboard.assign(image1.picture);
 
7. Для вставки вмісту буфера обміну в компонент Image використовується команда
 
1) image1.picture.pastefromclipboard;
2) clipboard.assign(image1.picture);
3) image1.picture.assign(clipboard);
4) image1.picture.assign:=clipboard;
 
8. Яка з наведених назв є методом читання зображення з компонента Imagelist?
 
1) getimagelist
2) getbitmap
3) readimage
4) getpicture
 
9. Якщо з компонента Imagelist потрібно прочитати зображення в змінну, то як правильно цю змінну описати?
 
1) пер: tgraphic;
2) пер: tpicture;
3) пер: timage;
4) пер: tbitmap;
 
10. На якій вкладці знаходиться компонент Timer?
 
1) standard
2) system
3) additional
4) win32
 
11. Яка властивість компонента Timer дозволяє задати інтервал часу для його спрацьовування?
 
1) time
2) period
3) value
4) interval
1. Який компонент служить для зазначення таблиці БД при підключенні за технологією ADO?
 
1) Adotable
2) Adoconnection
3) Adoquery
4) Datasource
 
2. Яка властивість таблиці-компонента дозволяє підключитися до БД, у якій ця таблиця перебуває?
 
1) Adoconnection
2) Connection
3) Datasource
4) Active:=true;
 
3. Яка властивість таблиці-компонента дозволяє вказати таблицю БД?
 
1) Table
2) Tabledb
3) Nametable
4) Tablename
 
4. Яка властивість таблиці-компонента дозволять активувати таблицю для роботи з даними?
 
1) Enabled
2) Active
3) Visible
4) Readonly
 
5. Яка команда відключає таблицю-компонентів від фізичної таблиці БД?
 
1) active:=true;
2) enabled:=false;
3) visible:=false;
4) active:=false;
 
6. Яка властивість поля таблиці дозволяє задати текст, відображуваний у заголовку поля на формі?
 
1) Displaylabel
2) Caption
3) Titlecaption
4) Titletext
 
7. Яка властивість поля таблиці дозволяє задати його ширину в символах?
 
1) Width
2) Displaywidh
3) Columnwidth
4) Fieldwidth
 
8. Яка властивість поля таблиці робить його невидимим?
 
1) Visible
2) Displayvisible
3) Fieldvisible
4) Visiblecolumn
 
9. Яка властивість поля таблиці задає формат відображення даних у полі?
 
1) Maskedit
2) Formatedit
3) Displaymask
4) Displayformat
 
10. Який запис дозволяє звернутися до поля fam таблиці?
 
1) adotable1.fam
2) adotable1.field.fam
3) adotable1.fieldbyname('fam')
4) adotable1.fieldbyname(fam)
 
11. Який запис дозволяє прочитати вміст поля fam таблиці як текст?
 
1) fam.asstring
2) fam.text
3) fam.string
4) fam.value
 
12. Який запис дозволяє прочитати вміст поля oklad таблиці як число?
 
1) oklad.value
2) oklad.float
3) oklad.asfloat
4) oklad.real
 
13. У якій події компонента-таблиці пишуть формули для розрахунків полів, що обчислюються?
 
1) Oncreate
2) Onfieldscalc
3) Oncalc
4) Oncalcfields
 
14. Якщо потрібно обмежити значення поля деякою умовою, то в якій події поля потрібно писати код?
 
1) Onchange
2) Onvalidate
3) Aftervalidate
4) Oncheck
 
15. Яка властивість дозволяє зв'язати компонент форми з полем таблиці?
 
1) datafield
2) dataset
3) datasource
4) fieldsdata
 
16. Яка команда правильно завантажує картинку в поле foto таблиці?
 
1) tblodfield(поле).loadfromfile(файл);
2) поле.loadfromfile:=файл;
3) tblodfield(поле).value:=файл;
4) tblobfield.поле.loadfromfile(поле);
 
17. Якщо в полі Edit перебуває дата, яка функція правильно конвертує текст у дату?
 
1) date(текст)
2) datestr(текст)
3) strtodate(текст)
4) datetostr(текст)
 
18. Якщо в компоненті Datetimepicker обрана дата, то як правильно привласнити це значення текстовому полю?
 
1) поле:=Datetimepicker1.value;
2) поле:=datetostr(Datetimepicker1.value);
3) поле:=datetostr(Datetimepicker1.date);
4) поле:=strtodate(Datetimepicker1.date);
 
19. Який компонент служить для створення списків-довідників, що випадають?
 
1) dblookupcombobox
2) dblookupbox
3) dblookupcombo
4) dbcombobox
 
20. Яка властивість списку-довідника дозволяє задати джерело даних, з якого будуть братися значення з довідника?
 
1) datasource
2) dataset
3) listset
4) listsource
 
21. Яка властивість списку-довідника дозволяє вказати поле джерела даних, з якого будуть братися значення для довідника?
 
1) keyfield
2) dataset
3) listfield
4) datafield
 
22. Яка властивість компонента dbnavigator дозволяє змінити набір кнопок на компоненті?
 
1) options
2) visiblebuttons
3) activebuttons
4) showbuttons
 
22. Яка властивість dbnavigator дозволяє змінити тексти спливаючих підказок?
1) showhint
2) hint
3) hints
4) butonhints
 
23. Для зв'язування сітки dbgrid з набором даних використовують властивість:
 
1) tablename
2) dataset
3) connection
4) datasource
 
24. Якщо сітка відображає підлеглу таблицю, то яка властивість сітки дозволяє задати ім'я головної таблиці?
 
1) keysource
2) parentsource
3) mastersource
4) mainsource
 
25. Якщо сітка відображає підлеглу таблицю, то яка властивість сітки дозволяє задати імена полів, по яких таблиці зв'язані?
 
1) linkfields
2) masterfields
3) parentfields
4) datafields
 
26. Який з методів таблиці виконує перехід на один запис назад?
 
1) next
2) prior
3) last
4) first
 
27. Який з методів таблиці виконує перехід на один запис уперед?
 
1) last
2) prior
3) next
4) first
 
28. Який з методів таблиці виконує перехід на перший запис?
 
1) begin
2) one
3) first
4) next
 
29. Який з методів таблиці додає новий запис?
 
1) insert
2) add
3) paste
4) new
 
30. Який з методів таблиці видаляє запис?
 
1) reset
2) clear
3) delete
4) destroy
 
31. Який з методів таблиці зберігає запис?
 
1) save
2) update
3) refresh
4) post
 
32. Який з методів таблиці скасовує зміни?
 
1) cancelupdate
2) cancel
3) undo
4) exit
 
33. Який з методів таблиці переводить запис у режим редагування?
 
1) edit
2) editrec
3) change
4) recedit
 
34. Якf властивість набору даних дозволяє визначити кількість записів у наборі?
 
1) record
2) numrecord
3) recordcounts
4) countrec
 
35. Якf властивість набору даних дозволяє визначити номер поточного запису в наборі?
 
1) numberrecord
2) recordnumber
3) recnumber
4) recno
 
36. Якf властивість набору даних дозволяє звернутися до унікальної мітки кожного запису?
 
1) bookmark
2) label
3) recmark
4) reclabel
 
37. Яка властивість набору даних дозволяє визначити досягнення кінця набору даних (кінця таблиці)?
 
1) efo
2) feo
3) eof
4) foe
1. Яка властивість компонента dbgrid служить для завдання джерела даних?
 
1) dataset
2) datasource
3) datacontrol
4) connection
 
2. Яка властивість компонента dbgrid дозволяє звернутися до списку стовпчиків сітки?
 
1) fields
2) grid
3) columns
4) dbcols
 
3. Яка властивість компонента dbgrid служить для завдання додаткових властивостей сітки?
 
1) options
2) settings
3) properties
4) tools
 
4. Яка властивість компонента dbgrid служить для завдання параметрів заголовків колонок сітки?
 
1) title
2) titlecaption
3) caption
4) titlefont
 
5. Яка властивість компонента dbgrid дозволяє визначити кількість стовпчиків у сітці?
 
1) colcount
2) columncount
3) fieldcount
4) count
 
6. Яка властивість компонента dbgrid дозволяє визначити поле стовпчика, обраного в сітці користувачем?
 
1) field
2) selectfieldname
3) selectedfield
4) selectedname
 
7. Яка властивість компонента dbgrid дозволяє визначити номер активного стовпчика сітки, обраного користувачем?
 
1) selectedno
2) selectednumber
3) selectedcolumn
4) selectedindex
 
8. Яку із властивостей не має стовпчик сітки dbgrid?
 
1) buttonstyle
2) dropdownrows
3) keyfield
4) picklist
 
9. Яка властивість стовпчика сітки dbgrid дозволяє задати ім'я відображуваного поля?
 
1) datafield
2) fieldindex
3) fieldname
4) dataset
 
10. Яка властивість стовпчика сітки dbgrid дозволяє задати значення для списку, що випадає?
 
1) picklist
2) listdata
3) pickfield
4) keypicklist
 
11. Яка властивість стовпчика сітки dbgrid дозволяє задати параметри заголовка стовпчика?
 
1) caption
2) titlecaption
3) title
4) titletext
 
12. Як правильно звернутися до потрібного стовпчика сітки dbgrid?
 
1) dbgrid.col[i]
2) dbgrid.columns[i]
3) dbgrid.fields[i]
4) dbgrid.column[i]
 
13. Яка подія сітки dbgrid виникає після клацання на мишею на будь-якій чарунці?
 
1) onclick
2) oncellenter
3) oncellclick
4) onclickcell
 
14. У якій події сітки dbgrid уводять код для фарбування рядків і чарунок?
 
1) ondrawcells
2) ondrawcolumn
3) ondrawrect
4) ondrawcolumncell
 
15. Яка команда правильно задає колір тла для заливання чарунок сітки dbgrid?
 
1) dbgrid1.canvas.brush.fon:=колір;
2) dbgrid1.canvas.brush.backcolor:=колір;
3) dbgrid.canvas.color:=колір;
4) dbgrid1.canvas.brush.color:=колір;
 
16. Яка команда правильно зафарбовує чарунки сітки dbgrid?
 
1) dbgrid1.canvas.fillrect (rect);
2) dbgrid1.canvas.fillcells (rect);
3) dbgrid1.canvas.rectfill (rect);
2) dbgrid1.canvas.colorrect (rect);
 
17. Яка команда правильно задає колір тексту в зафарбованих чарунках сітки dbgrid?
 
1) dbgrid1.canvas.color:=колір;
2) dbgrid1.canvas.font.color:=колір;
3) dbgrid1.canvas.fontcolor:=колір;
4) dbgrid1.canvas.colorfont:=колір;
 
18. Яка команда правильно виводить текст в зафарбованих чарунках сітки dbgrid?
 
1) dbgrid1.canvas.text(. . .);
2) dbgrid1.canvas.outtext(...);
3) dbgrid1.text.out(...);
4) dbgrid1.canvas.textout(...);

Питання для підготовки до обов'язкової контрольної роботи № 2
 
1. Як виконати підключення таблиці до програми за технологією ADO? Опишіть принципи роботи з полями таблиці.
2. Як можна звернутися до значення поля, як створити поле, що обчислюється й написати для нього формулу? Приклад.
3. Як програмно задати обмеження на значення потрібного поля? Приклад. За допомогою яких компонентів можна відобразити значення полів таблиці на формі, які властивості при цьому потрібно вказати?
4. Приведіть приклад коду, який поміщає в Blob-поле вміст обраного графічного файлу. Які обмеження має компонент Dbimage?
5. Яке компонент використовується для роботи з полями типу дата/час? Приведіть приклад.
6. Як створити список-довідник. Опишіть дії для створення такого довідника.
7. За допомогою якого компонента можна додати на форму набір кнопок для виконання над даними основних операцій? Які властивості має цей компонент?
8. Приведіть основні методи таблиці для виконання навігації по записах. Приведіть приклад циклу для переходу по всіх записах таблиці.
9. Приведіть методи таблиці для виконання редагування даних таблиці.
10. Опишіть основні властивості сітки Dbgrid.
11. Опишіть основні властивості окремого стовпчика в сітці Dbgrid.
12. Як можна в програмі звернутися до потрібного стовпчика в сітці Dbgrid? Як можна звернутися до поточного стовпчика?
13. Як у сітці Dbgrid створити порожній стовпчик? Як для стовпчика сітки створити список, що випадає?
14. У якій події сітки Dbgrid виконують розфарбовування рядків або комірок? Приведіть приклад розфарбовування всіх комірок рядка сітки.
15. Приведіть приклад розфарбовування окремої комірки в сітці Dbgrid. Як у комірці сітки відобразити іконку з Imagelist?
16. Який компонент дозволяє відображати із БД графічну інформацію у форматах JPEG і GIF. Як установити цей компонент?
17. Опишіть основні властивості таких компонентів як wwdbedit, wwspinedit, wwcheckbox з бібліотеки Infopower.
18. Опишіть основні властивості компонента Radiogroup з бібліотеки Infopower.
19. Опишіть основні властивості сітки wwdbedit з бібліотеки Infopower.
20. Опишіть основні властивості окремого стовпчика в сітці wwdbgrid з бібліотеки Infopower.
21. Як зберегти й відновити параметри сітки wwdbgrid з бібліотеки Infopower через реєстр. Приклад
22. Як працювати з підвалом сітки wwdbgrid з бібліотеки Infopower? Які властивості відображають рядок підвалу? Приведіть код відображення даних у рядку підвалу?
23. Які компоненти є в бібліотеці Infopower для роботи з датами, приведіть властивості цих компонентів. Який компонент служить для роботи з  Memo полями, приведіть властивості цього компонента
24. Опишіть основні властивості компонента wwdbnavigator з бібліотеки Infopower.
25. Опишіть принцип відображення стовпчика полів таблиці в сітці wwdbgrid з бібліотеки Infopower.
26. Як створити список полів, що розкривається, у сітці wwdbgrid з бібліотеки Infopower.
27. Як установити бібліотеку Quickreport? З якого компонента починається проектування звіту?
28. Як задати параметри сторінки для звіту Quickreport?
29. Які смуги може містити звіт Quickreport, як їх додати на звіт?
30. Які візуальні компоненти можна додавати на звіт Quickreport? Як компоненти зв'язуються з полями таблиці?,
31. Опишіть принцип малювання рамок у звітах Quickreport. За допомогою яких компонентів можна відобразити у звіті графічну інформацію?
32. Опишіть вставку у звіт Quickreport формул, системних змінних і шаблонів.
33. Опишіть процедуру групування даних у звіті Quickreport.
34. Опишіть процедуру створення звіту Quickreport по зв'язаних таблицях.
35. Опишіть принцип перегляду, друку й експорту звіту Quickreport.
36. Які можливості має Delphi для розробки WEB додатків? Як виконати такий додаток?
37. Опишіть принцип створення WEB додатка в Delphi. Як створити перелік дій? З яких частин складається URL?
38. Як написати оброблювач для дії в WEB додатку? Які параметри має цей оброблювач?
39. Як при описі HTML форми вказати, що вона обробляється дією з WEB додатка Delphi? Як звернутися до полів на HTML формі в коді WEB додатка Delphi?
40. Який компонент дозволяє використовувати в WEB додатках Delphi шаблони HTML файлів? Як за допомогою WEB додатка виконати підстановку в HTML шаблон потрібних значень?
41. За допомогою якого компонента можна відобразити в WEB додатку дані БД у вигляді таблиці? Опишіть властивості цього компонента.
42. Як у таблицю із даними БД додати новий стовпчик і заповнити його потрібними значеннями?

Приложенные файлы

  • docx 18184692
    Размер файла: 6 MB Загрузок: 0

Добавить комментарий