I. Вступ
Інтернет все більше і більше входить в наше життя. Ми часто сидимо і натискаємо кнопку "оновити", чекаючи нових даних на заповітної сторінці. Але ж треба і працювати колись, тому завдання моніторингу сторінки з новинами ми доручимо Delphi, а самі будемо працювати (чи займатися іншою корисною справою - життя адже прекрасна). Якщо що - все буде завантажено та представлено в зручному для нас вигляді.
Як "піддослідного кролика" я вибрав багатьом відомий цитатника рунета - bash.org.ru. Програма буде забирати з головної сторінки цитати, і складати їх в базу. А з цитатами в базі можна робити що завгодно.
II. загальні зауваження
Зовнішній інтерфейс програми не претендує на нагороду. Я над ним особливо не замислювався, так як основне завдання в іншому. Інтерфейс зробите самі, якщо він вам потрібен.
Ця програма побудована за модульно-об'єктної технології (мені більше подобається назва "Розділяй і володарюй"). Те-є, для кожної сутності є об'єкт, і ці об'єкти взаємодіють між собою. Так як зв'язки і залежності між ними мінімальні, то можна легко їх замінювати і модифікувати.
Щоб легше було шукати місце в коді, на яке я посилаюся, я використовую спеціальні маркери. У тексті статті вони виглядають так. Щоб знайти код, який відповідає йому, потрібно зробити наступне. Перейти в Delphi, вибрати в меню View »ToDo List. Знайти там відповідний текст і клікнути двічі. А по тексту програми ви побачите їх як
огляд класу
Почнемо розбір з класу, який обслуговує базу даних. Тільки об'єкти цього класу мають доступ до бази даних, тільки вони знають як з нею працювати. Решта класи не повинні нічого знати про базу даних.
У самому верху юніта BBasa оголошений абстрактний клас TBBasaCustom B1>. Цей клас має тільки один метод для додавання цитат в базу, та й той абстрактний. Робочий клас буде успадковуватися від нього. Це зроблено спеціально, щоб з того об'єкта, який буде додавати дані, не можна було б звернутися до інших методів, і йому було все одно, які ще методи є у класу. Вони йому не потрібні. Це виглядає дивно, але пізніше стане зрозуміло.
У цьому ж юніте оголошений клас TBBasa. Цей клас успадковується від нашого класу і реалізовує всю потрібну функціональність, а саме:
Відкриває БД при своєму створенні. Якщо файл бази відсутній - він його створить. B6>
Вміє додавати цитату, так як реалізовує абстрактний метод Add. B3>
Вміє знайти в базі цитату за номером - метод GetQuotes. B4>
Подивіться уважно на public методи. Жоден з них не розповість про те, як і де зберігаються дані. Тому, ніхто не заважає переписати методи і зберігати цитати в текстовому файлі або декількох файлах. Решта код цього ніяк не відчує. Чи відчуваєте силу такого підходу до програмування?
За базу даних я використовую SQLite.
Розглянемо деякі методи детальніше.
Цей метод B3> отримує два параметри - Number і Text - відповідно номер цитати і її текст. Перед додаванням спочатку перевіряє, а чи немає вже цитати в базі. Для цього він робить запит на вибірку цитат із заданим номером. Якщо цитата не знайдено (кількість знайдених рядків дорівнює нулю), то додаємо в базу. Звичайно, теоретично може бути, що в базі буде кілька записів з одним номером (програмна помилка, наприклад), але я не ускладнюю. В кінці методу є виклик SendCommand. Це сповіщення інтерфейсу про те, що є нові цитати. Як це працює - буде розказано нижче.
метод GetQuotes
Цей метод B4> по заданому номеру цитати знаходить її і повертає, попередньо видаливши спецсимволи. Якщо цитата не знайдено - повертає порожній рядок (воно логічно). Цікаво також те, що цей метод звертається до іншого, який запитує "сирий текст" з бази.
IV. клас потоку
Даний клас займається основною роботою - він викачує головну сторінку, парсит, і віддає поштучно цитати об'єкту БД. Вся реалізація знаходиться в юніте BTread.
Як видно з коду, у цього класу тільки три публічних методу - конструктор, деструктор і запит на оновлення. А більше йому й не треба.
Розглянемо як все це працює. Через конструктор T1> при створенні класу ми передаємо йому посилання на об'єкт БД, щоб потім мати можливість додавати цитати.
Після того, як потік буде запущений, починає виконуватися метод Execute T2>. Він гранично простий - поки нас не завершили, повторювати: скачати, розпарсити і почекати. Всі дії спеціально розділені, щоб бути незалежними.
Завантаження сторінки
Метод завантажити сторінку GetText просто повертає у вигляді рядка вміст сторінки. Якщо вам з якихось ідеологічних причин не подобаються компоненти Indy, просто замініть тут на свій код, і все. Сам метод гарний ще тим, що показує, як в RunTime створювати компонент і призначати методи.
Між скачуванням цитат треба робити паузу. Так як ми знаходимося в потоці, то вільно можемо писати Sleep. Ніякого "підвисання интерфеса" не буде. Але ця функція погана тим, що потік складно розбудити з такого сну. І якщо ми захочемо в цей момент закрити програму, то нам доведеться чекати, поки функція не відпрацьована.
Саме з цієї причини я використовую трохи інший метод T5>. Я використовую функцію WaitForSingleObject, яка, на відміну від Sleep, може також завершитися, якщо "спрацював об'єкт-подія", який їй передали. Спрацював - це перейшов з SetEvent.
Тому, якщо потрібно оновити завчасно або завершити роботу потоку, ми "включаємо подія" і метод Sleep завершується достроково.
V. Основне застосування
Тепер, коли ми розглянули всі допоміжні об'єкти, пора їх об'єднати і змусити працювати.
Так як основна функціональність у нас вже реалізована, то код гранично простий. Насамперед ми створюємо два об'єкти - один для БД, інший для потоку. Робимо це в OnCreate форми M2>. У OnDestroy відповідно знищуємо. Зверніть увагу на послідовність створення і видалення. Вона важлива.
Кнопка "оновити" теж не повинна викликати ускладнень. Вона просто викликає метод Update у об'єкта потоку.
Зворотній зв'язок
Пам'ятайте виклик SendCommand у об'єкта БД? Ця функція знаходиться в юніте BMessage. Сама вона дуже проста - вона просто викликає WinAPI функцію SendMessage для посилки повідомлення головною формою, а хендл головною форми береться з Application.MainForm.Handle. Головна форма приймає ці повідомлення, і вже самостійно звертається до потрібних об'єктів.
Розглянемо для прикладу передачу повідомлення про нову цитаті. Після того, як цитата була збережена, надсилається повідомлення MY_NEW_QUOTES і в якості параметра передається номер цитати. Другий параметр нам не потрібен, і ми пишемо туди 0.
В класу форми оголошений метод M7> для перехоплення цього повідомлення. Отримавши його, ми звертаємося до об'єкту БД, за номером отримуємо саме повідомлення і додаємо в Memo.
VI. висновки
Звичайно, це дуже сирий приклад, і на виставку він не годиться. Але він хороший тим, що є заготівлею для різних програм подібного типу - збирати новини, викачувати галереї картинок, збирати дані.
І пам'ятайте, у деяких випадках подібні програми можуть не дружити з законом! Будьте уважні, і не порушуйте.