Отправляет email-рассылки с помощью сервиса Sendsay

Программирование на Delphi

  Все выпуски  

Программирование на Delphi (выпуск 82)


Программирование на DELPHI
Выпуск #82 (05 июня 2008 г.)

Разделы сайта:

Delphi.int.ru

Новости сайта
Регистрация »
Файловый архив
Статьи
Компоненты
Plug-in's
Документация
Исходники
Изображения
Игры
Программы
Рассылки сайта
F.A.Q.

IRC-каналы сайта:

Сервер: irc.dalnet.ru
Порт: 6667
Канал: #delphiintru

Ждём Вас на нашем канале!

Доброго времени суток, уважаемые читатели!

Вот уже наступило лето, с чем всех и поздравляем. Лето - сезон отпусков, поэтому нужно не работать, а отдыхать :-)

На сайте появилась возможность поиска статей, поэтому найти нужную или ещё непрочитанную статью стало проще. В ближайшее время будут обновлены функции добавления комментариев к статьям и оценки статей.

Всем тем, кто только присоединился к нам, рекомендуется зарегистрироваться на сайте. Регистрация предоставит Вам полный доступ к возможностям сайта. К примеру, без регистрации Вы не сможете задавать на сайте вопросы, оставлять комментарии к файлам и участвовать в опросах. Перейти к регистрации »

В этом выпуске:

  • Обучение - урок 21: Подпрограммы (часть 3);
  • Статья: Читаем цитаты с bash.org.ru своей программой;
  • Файловый архив - новые компоненты и исходники;
  • Юмор - Переписка или "Как я завел себе почтовый ящик".

Статистика Delphi.int.ru Expert на 05.06.2008, 18:00 (предыдущий подсчёт - 01.05.2008, 09:00):

Количество экспертов: 51 (+2).
Участниками задано вопросов: 1660 (+122).
Экспертами отправлено ответов: 2271 (+105).
Количество сообщений на мини-форумах: 3190 (+357).
Максимальное число разосланных в день писем (за всю историю): 1960 (28.10.2007, +0).

До встречи в следующем выпуске!

Разделы рассылки:

» Авторское слово
» Обучение Delphi
» Delphi.int.ru Expert
» Статья по Delphi
» Файловый архив
» Юмор

Delphi.int.ru Expert
Сообщество программистов: общение, помощь, обмен опытом.

Количество читателей рассылки (05.06.2008, 18:00):
5540+1917+491= 7948 (+29)

Связь по e-mail:

admin@delphi.int.ru
support@delphi.int.ru


Если Вы хотите где-либо разместить материалы, представленные на www.delphi.int.ru или в данной рассылке, свяжитесь, пожалуйста, с их автором или ведущим рассылки.

Delphi.int.ru Expert
Сообщество программистов: общение, помощь, обмен опытом
(текущая версия системы: 2.36+; последнее обновление: 11.05.2008)

Последние новости

В начале каждого месяца проходит голосование за лучший ответ месяца и самый интересный вопрос. Победителям вручаются почётные медали.
За апрель медали получили: Матвеев Игорь Владимирович (лучший ответ) и Phoenix (лучший вопрос).

 

Архив: вопросы и ответы

В архив попадают вопросы, срок действия которых истёк. Каждый заданный вопрос действителен в течение одной недели, т.е. ответы на него принимаются именно в этот период. В сегодняшнем выпуске опубликованы вопросы # 371 - 385. Вопросы, на которые не было дано ни одного ответа, не публикуются.
Так как темп поступления вопросов от пользователей намного выше темпа их публикации, в рассылке публикуются вопросы, заданные довольно давно. Тем не менее, вопросы публикуются по порядку, без пропусков. Просмотреть любые вопросы и ответы Вы всегда можете на сайте.

Статистика по выпуску:

Кол-во вопросов: 18
Кол-ответов: 32
Баллы за ответы: 112
 

Вопрос # 386

Здравствуйте. Дорогих женщин поздравляю с 8 Марта,
а к экспертам у меня вопрос. Как мне в своём "exe" файле в Memo1,
заменить цвет шрифта или цвет фона, что бы при следующей загрузке,
он загружался с новыми параметрами. Заранее благодарен.

Вопрос задал: Толков Геннадий Викторович (статус: Посетитель)
Вопрос отправлен: 08 марта 2007, 03:54
Всего ответов: 2; сообщений в мини-форуме вопроса: 3

 

1. Отвечает эксперт: Роман

Здравствуйте, Толков Геннадий Викторович!К примеру так как в примере.Там сохраняется цвет и размер в ini-файле.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 8 марта 2007, 04:32
Оценка за ответ: 5

2. Отвечает эксперт: Виталий Лещенко

Здравствуйте, Толков Геннадий Викторович!

При выходе сохраняйте свои настройки в реестр или ini файл (imho вротое предпочтительнее), а при запуске загружайте из.

Ответ отправил: Виталий Лещенко (статус: 4-ый класс)
Ответ отправлен: 8 марта 2007, 14:00
Оценка за ответ: 4


Вопрос # 387

Уважаемые эксперты!
Ответьте, пожалуйста, новичку в Delphi на вопрос:
Каким образом в Delphi 2006 подключить компонент VCL, представленный, например, в виде модуля. Или компонент, созданный в другой версии Delphi, в состав которого входят модули.
С уважением.
Dick

Вопрос задал: Dick (статус: Посетитель)
Вопрос отправлен: 08 марта 2007, 13:12
Всего ответов: 2; сообщений в мини-форуме вопроса: 5

 

1. Отвечает эксперт: Виталий Лещенко

Здравствуйте, Dick!

Скомпилированные модули других версий никогда не поддерживались (Исключение Delphi2007 - совместим с Delphi2006).
Если есть исходники, то можно перекомпилировать...
Если нет - то никак!

Ответ отправил: Виталий Лещенко (статус: 4-ый класс)
Ответ отправлен: 8 марта 2007, 14:03
Оценка за ответ: 4

2. Отвечает эксперт: Alex Van Glukhman

Здравствуйте, Dick!

А можно просто создать новый проект компонента - подключить туда модуль описания компонента с расширением pas, откомпилировать, скомпоновать и установить. И в этом случае легко решается вопрос совместимости различных версий Delphi. Debugger подскажет что изменить надо или подключить.

Удачи!

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 11 марта 2007, 18:19
Оценка за ответ: 4


Вопрос # 388

Проведём ещё один эксперемент :)
Создадим пустой проэкт, положем таймер на форму. В обработчике таймера напишем width := width - 100. Запустим. Через равные промежутки времени форма уменьшается. Теперь запустим ещё раз, но нажмём и держим левую кнопку мыши на заголовке формы. Держим, пока форма не уменьшится пару раз. Пускаем - форма восстановилась до тех размеров, когда мы зажали кнопку мыши. Вопрос: Как избавиться?

Вопрос задал: mvp (статус: 4-ый класс)
Вопрос отправлен: 08 марта 2007, 15:08
Всего ответов: 2; сообщений в мини-форуме вопроса: 2

 

1. Отвечает эксперт: Федоров Роман Сергеевич

Здравствуйте, фокусник - mvp!
Проверял, форма не восстанавливает свой размер.
(Delphi 7, Windows Xp SP2)

Ответ отправил: Федоров Роман Сергеевич (статус: 2-ой класс)
Ответ отправлен: 8 марта 2007, 23:17
Оценка за ответ: 3
Комментарий: Хотя я проблема на delphi6 (xp64 prof), только что проверил на delphi7 (xp prof sp2) - всё точно также - восстанавливается - даже если форма ушла из под мышки. А вы точно по заголовку формы мышь зажимали?

2. Отвечает эксперт: Помфюк Владимир Степанович

Здравствуйте, mvp!
Взял и проверил на XP Home SP2 в Delphi 5 и Delphi 7 - размер не восстанавливается. Но была видна рамка того же размера. Она-то и натолкнула на мысль поставить настройку "Show window contents while dragging". Вот тут и начались те глюки, которые Вы описываете. Выход - засекать размер окна при создании формы и при каждом событии таймера, а в OnResize проверять: если размер больше положеного - уменьшить. Правда появляются некрасивые дергания при условиях Вашего эксперимента, но тут уже Вам решать что лучше - дергания или восстановление размера.

Ответ отправил: Помфюк Владимир Степанович (статус: Абитуриент)
Ответ отправлен: 9 марта 2007, 11:11
Оценка за ответ: 4
Комментарий: Это конечно же вариант, но немного сложноват в реализации... Но так и сделаю, если выход не найду. Мне кажется, что достаточно дать понять окну, что кнопку мыши отпустили - только не могу найти соответствующее API


Вопрос # 389

УВАЖАЕМЫЕ ЭКСПЕРТЫ, покажите, пожалуйста, как в перемножить две матрицы различных размеров с помощью циклов for.Заранее ОГРОМНЕЙШЕЕ ВАМ СПАСИБО!!!!!!!!!!:-))

Вопрос задала: Лабзенкова Елена Юрьевна (статус: Посетитель)
Вопрос отправлен: 09 марта 2007, 17:38
Всего ответов: 1

 

1. Отвечает эксперт: Вадим К

вы должны помнить, что не всякие матрицы можно множить. Если множим матрицу A на B, то необходимо чтобы число столбцов матрицы A было равно числу строк матрицы B.
А иначе никак.
Как реализовать. Открываем учебник и читаем
Элемент Cij, стоящий на пересечении i-й строки
и j-го столбца матрицы C = AB, равен сумме попарных произведений
соответствующих элементов i-й строки матрицы A и j-го столбца матрицы B.
также, заметим, что если A имеет размерность (m,n)
а B (n,p)
то результак будет C размерности (m,p)
Реализация в приложении. Её можно оптимизировать, но для понимания - самое оно

Приложение:

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 9 марта 2007, 17:59
Оценка за ответ: 5


Вопрос # 390

Здравствуйте. Скажите, пожалуйста, можно сделать так, что бы мои окна (если можно то все окна) сворачивались на мою форму. И ещё я уже задавал вопрос (как в Memo1 сохранить как...), а если я работаю с текстом в Memo1,
как мне просто сохранить, то есть нажал сохранить, работаю дальше, опять сохранил, как в Notepad, чтобы не указывать путь.

Вопрос задал: Толков Геннадий Викторович (статус: Посетитель)
Вопрос отправлен: 10 марта 2007, 02:21
Всего ответов: 2; сообщений в мини-форуме вопроса: 1

 

1. Отвечает эксперт: Роман

Здравствуйте, Толков Геннадий Викторович!Ну имя то так или иначе прийдётся указывать,другое дело что можно скажем условится,что если имя и путь сохранения не указан то будем сохранять всегда в некой папке по умолчанию в часности в примере (при нажатии save) это:C:\Documents and Settings\Rem_si\Рабочий стол,т\е по умолчанию сохраняем на рабочем столе с именем document.txt. А когда мы укажем путь в save as то вдальнейшем при нажатии кнопки save сохранение будет происходить по указанному пути.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 10 марта 2007, 04:13
Оценка за ответ: 5

2. Отвечает эксперт: Spawn

Здравствуйте, Толков Геннадий Викторович! Можно сделать так, при первом сохранении записываем в переменную имя файла, а при послеюдующих сохранениях проверяем, если переменная "не пуста", то сохраняем в тот файл, что указан в переменной, если же "пуста", то выводим диалог сохранения.
Пример в приложении.

Приложение:

Ответ отправил: Spawn (статус: 1-ый класс)
Ответ отправлен: 10 марта 2007, 09:03


Вопрос # 391

Как узнать есть ли internet соединение

Вопрос задал: San (статус: Посетитель)
Вопрос отправлен: 11 марта 2007, 03:00
Всего ответов: 3; сообщений в мини-форуме вопроса: 2

 

1. Отвечает эксперт: min@y™

Читай статью А. Лозовюка, вот она: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=401

Ответ отправил: min@y™ (статус: Студент)
Ответ отправлен: 11 марта 2007, 08:23

2. Отвечает эксперт: Роман

Здравствуйте, San!Посмотрите на delphiworld.narod.ru/_internet_.html там есть насколько вариантов как узнать есть-ли internet соединение и его активность.

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 11 марта 2007, 09:12

3. Отвечает эксперт: Вадим К

http://www.delphikingdom.com/asp/viewitem.asp?catalogid=401
Статья немного устарела. Запомните, нет функции, которая бы говорила, есть или нет сооединение с мировой сетью. Но есть один путь, который может только направить.
Первое. Попинговать известные сайты, которые наверняка работают. Только не пытайтесь пинговать майкрософт - они давно не пингуются:)
Но злосный админ мог прикрыть echo пакеты, и пинги не пойдут в любом случае. Более надёжный способ - попытаться открыть какую-нибудь страничку. Если она открывается - всё ок, соединение есть, нет, значит либо сервер временно в дауне, пробуем пару других, либо мы за прокси - тут вначале прийдётся узнать параметры прокси. Либо нас прирезал фаервол (пользователь в недоумении, почему наш текстовый редактор лезит по разным порносайтам:) - прибил ещё на подлёте) - тут уже очень сложно что то сделать(я не сказал невозможно, я сказал сложно) и лучше повиноваться.
как наиболее просто запростить содержимое странички
Бросаем компонент IdHHTP и в нажатии кнопки пишем
s:string;
begin
try
s:=IdHTTP1.Get('http://www.w3c.org');//Этот сайт обычно пропускают все фильтры - сайт интернет консорциума
//А тут надо проанализировать переменную d
except
//А сюда попали - значит у нас проблемы.
end;

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 11 марта 2007, 13:31
Оценка за ответ: 3
Комментарий: опробовал функцию
flags: DWORD;
InternetGetConnectedState(@flags, 0);
если соединение есть возвращает true
работает


Вопрос # 392

Доброе время суток! Уважаемые эксперты,кто-нибудь использовал Delphi совместно с FireBird?Помогите советом как к нему подключиться? Через ODBC не настраивается

Вопрос задал: Мережников Андрей (статус: Посетитель)
Вопрос отправлен: 11 марта 2007, 08:14
Всего ответов: 3; сообщений в мини-форуме вопроса: 2

 

1. Отвечает эксперт: Роман

Здравствуйте, Мережников Андрей!Поишите на http://www.interbase-world.com/ru/articles/index.php?BID=24&ID=47 "Технические статьи о программировании для InterBase и Firebird"?,плюс обратите внимание на FIBPlus - это библиотека компонентов, предназначенная для работы с InterBase и Firebird. Она предоставляет быстрый, прямой и удобный доступ к базам данных Borland InterBase и Firebird при работе с Delphi, C++ Builder и Kylix.
http://www.fibplus.com/
http://www.devrace.com/

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 11 марта 2007, 09:42
Оценка за ответ: 5

2. Отвечает эксперт: Вадим К

Да, соглашусь, FIBplus - одни с лучших компонентов для работы с FireBird. По сравнению с ODBC они предоставляют доступ к почти всем возможностям СУБД. Плюс ко всему там есть много особенностей - переподключение при потере связи, разумный запрос данных с сервера (тянуться не все, а только то, что видит пользователь в данный момент. Оставльные по мере надобности) и так дальше.
Также поищите в мировой сети или на прилавках книжку "Мир InterBase" - одна с лучших книг, которая вам несомненно поможет.

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 11 марта 2007, 13:35
Оценка за ответ: 3

3. Отвечает эксперт: Alex Van Glukhman

Здравствуйте, Мережников Андрей!

Interbase и Firebird совместимые БД. Для работы с ними во всез версиях Delphi существуют родные компоненты на вкладке Interbase и dbExpress

Удачи!

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 11 марта 2007, 18:25
Оценка за ответ: 4


Вопрос # 393

1)TV тюнер по нажатию горячей клавиши (например 'S')фотографирует кадр и записывает в файл на диске. Я хочу эмулировать нажатие клавиши в Delphi, что бы записывать эти кадры с заданным интервалом времени. Как этого добиться?
2) Как через Delphi отключить звук?

Вопрос задал: Калинин А.Ю. (статус: Посетитель)
Вопрос отправлен: 11 марта 2007, 14:03
Всего ответов: 1; сообщений в мини-форуме вопроса: 1

 

1. Отвечает эксперт: Вадим К

только недавно обсуждали http://expert.delphi.int.ru/question_379

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 11 марта 2007, 14:20


Вопрос # 394

Подскажите как подсчитать входящий и исходящий трафик ?

Вопрос задал: San (статус: Посетитель)
Вопрос отправлен: 11 марта 2007, 14:11
Всего ответов: 1

 

1. Отвечает эксперт: Роман

Здравствуйте, San!Скачайте пример с http://www.delphi.int.ru/?name=sources - NetTrafMonitor
программа, подсчитывающая время использования соединения, объём трафика (50Кб).

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 11 марта 2007, 15:24


Вопрос # 397

Здравствуйте ув. эксперты. Есть линия заданаая точками pt1 и pt2. Как определить входит, ли точка pt в окрестность линии заданной переменной Magnet (в пикселях)? Т.е. если провести перпендикуляр к линии, то окрестность слева и справа от линии равна Magnet.

Вопрос задал: SMaks (статус: 1-ый класс)
Вопрос отправлен: 11 марта 2007, 22:52
Всего ответов: 2

 

1. Отвечает эксперт: mvp

Немного математики: Пусть есть две точки (x1, y1) и (x2, y2). Тогда ур-ие прямой, проходящих через эти точки:
(y - y1) / (y2 - y1) = (x - x1) / (x2 - x1);

Нужно получить ур-ие в виде:
Ax + By + C = 0;
Тогда расстояние от точки (x3, y3) до прямой будет:
r = |Ax3 + By3 + C| / (A^2 + B^2)^0.5

Если r < Magnet, то входит. Естественно, это всё работает, только если Ваша система координат имеет размерность экрана(т. е. 1 пиксель соответствует 1 системы координат), иначе придётся нормировать, но это уже другой вопрос.

Попробуйте вывести ур-ие в общем виде сами. У меня получилось (могу ошибиться, поэтому и прошу проделать данную процедуру самостоятельно):

(y1 - y2)x + (x2 - x1)y + x1y2 - y1x2 = 0;
т. е. А = y1 - y2; B = x2 - x1; C = x1y2 - y1x2.
Ну, а код уже совсем приметивен.

Ответ отправил: mvp (статус: 4-ый класс)
Ответ отправлен: 11 марта 2007, 23:49
Оценка за ответ: 5
Комментарий: То что нужно! Спасибо. Я уже думал, что нужно воспозоваться формулой для нахождения растояния от точки до прямой, но незнал как его применить.

2. Отвечает эксперт: Вадим К

Вы сами ответили на свой вопрос. Нужно провести перпендикуляр от точки к прямой и узнать его длину. А дальше сравнить.
Но можно поступить и по другому. У нас ведь есть три точки. Значит есть треугольник. Проведём высоту (она и будет перпендикуляром) а дальше - банальная геометрия.
пусть (a1,a2) и (b1,b2) - координаты твоей линии.
(c1,c2) - координаты точки. тогда
вначеле длины
a=sqrt(sqr(a1-a2)+sqr(b1-b2));
b и c аналогично
cosa = (b*b+c*c-a*a)/(2*b*c);
sina=sqrt(1-cosa*cosa);
n = b*sina;
вот и всё. Если я геометрию за многие годы не забыл, должно работать

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 12 марта 2007, 00:08
Оценка за ответ: 5
Комментарий: Сначала хотел тоже делать через треугольники, но боялся, что все очень усложниться. Оказывается все просто, однако первый метод удобнее, но все равно спасибо!


Вопрос # 398

Парни, скачал у вас компонент RAG. Как установить его в delphi? Нужен просто позорез!

Вопрос задал: Scayn (статус: Посетитель)
Вопрос отправлен: 12 марта 2007, 07:21
Всего ответов: 1; сообщений в мини-форуме вопроса: 1

 

1. Отвечает эксперт: Dron

Здравствуйте, Scayn!
Как я понимаю, "у нас" - значит на delphi.int.ru? ;-)
Этот компонент - не совсем компонент. Он отличается тем, что в Delphi IDE не устанавливается и на Палитре компонент не появляется, т.е. устанавливать его не нужно. Нужно просто добавить в uses своей программы 3 модуля этого компонента: RAG, RAGGraph и LinkedInt64List, а также добавить путь, где эти модуль лежат в путь поиска (Tools - Environment Options - Library - Library path), либо просто скопировать эти модули в Delphi/Lib. После этого работать с компонентом нужно программно - создавать его, использовать и уничтожать. Как это делается - смотрите демо-приложение (RAGProject.dpr), а также справочное руководство (RAG-en.pdf). Желаю удачи!

Ответ отправил: Dron (статус: Студент)
Ответ отправлен: 12 марта 2007, 16:06
Оценка за ответ: 5


Вопрос # 400

Добрый день! Я пытаюсь подключить счетчик гейгера к компу. Он дает импульсы довольно короткие, которые я направляю на game port.
Далее процедурка
m:=joySetCapture (form1.Handle,0 , 1, True);
m:=joyGetPos(0,@myjoy);
опрашивает порт. а таймет(T=1ms) считывает значения параметров:
if (myjoy.wbuttons and joy_button1)>1 then...
Данная конструкция работает очень медленно, пропускает импульсы. Возможно ли оптимизировать код? И если есть статьи по работе с паралельным портом скиньте ссылку, буду очень благодарен! (Горю, дипломная...)

Вопрос задал: Scayn (статус: Посетитель)
Вопрос отправлен: 12 марта 2007, 13:39
Всего ответов: 2; сообщений в мини-форуме вопроса: 6

 

1. Отвечает эксперт: Вадим К

1) виндовс не система реального времени. Она имеет полное право "задержать" тик таймера, а то и пропустить (всё это задокументировано).
2) если таймер не мультимедийный, то чаше чем раз в 50 мс он работать не может (опять документировано, даже кажеться 55 мс)

Что же делать?
Попробывать мультимедийний таймер. Он вроде в библиотеке JVCL есть. Но лучше сделать маленькую схему с контролером - надёжность возрастёт в разы, простота работы также

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 12 марта 2007, 13:48
Оценка за ответ: 5

2. Отвечает эксперт: Роман

Здравствуйте, Scayn!Здравствуйте, Scayn!Вопервых я бы поставил на выходе счётчика расширитель импульсов Т.к у СГ они очень короткие,во вторых не использовал бы gameport т.к он изначально не расчитан на какую либо точность,а использовал бы com или lpt порт,для работы с lpt используйте LPTWDMIO - драйвер lpt пля делфи под XP,для com используйте компонент TBComPort предназначенный для обмена данными с внешними устройствами
через интерфейс RS-232 в асинхронном или синхронном режиме.
Разработан на основе библиотеки ComPort Library от
Dejan Crnila.
Обеспечивает прием и передачу данных по линиям TXD и RXD,
управление линиями RTS и DTR, мониторинг состояния линий CTS, DSR, RI (Ring Indicator)
и RLSD (Carrier Detect). Управление потоком приема-передачи (Flow Control) не предусмотрено.
Состояние порта отслеживается в отдельном потоке с генерацией соответствующих событий.
Работает с Delphi 2..7 под Windows 9X/ME/NT4/2K/XP. Можно конечно попробовать ещё на выходе СГ поставить защёлку которая будет изменять своё состояние по каждому импульсу СГ т.е 0-импульс-1-импульс-0,то тогда я думаю хватит и точности TTimer,и ненадо там никаких МК тулить. Итак работаем с com или lpt(кстати у меня на celeron 1.2ГГц мфксимальная скорость обращения ч.з LPTWDMIO период min по LPTout1-LPTout0 (меандр) = 10mkS;(F=100KГц);min длительность импульса = 5mkS;) а контроль состояния линий порта - в отдельный поток.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 12 марта 2007, 15:09
Оценка за ответ: 5


Вопрос # 401

Доброго времени суток, у меня вопрос, как в делфи управлять атрибутивами фйлов, тоесть програмно зделать файл например только для чтения или скрытым??? Заоание спасибо!

Вопрос задал: Шарайчук Сергій Олександрович (статус: 1-ый класс)
Вопрос отправлен: 12 марта 2007, 22:41
Всего ответов: 4

 

1. Отвечает эксперт: Роман

Здравствуйте, Шарайчук Сергій Олександрович!Надо воспользоваться функцией FileSetAttr(const:FileName:string;Attr:Integer):integer. Задаём ей два параметра: сначала имя файла, затем задаваемые атрибуты. Например, так можем файл сделать "только для чтения":FileSetAttr('C:\file.txt', faReadOnly);Можно задавать следующие значения:
faReadOnly-только для чтения
faHidden-скрытый
faSysFile-системный
faVolumeID-метка диска
faDirectory-каталог
faArchive-архивный
faAnyFile-произвольный

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 12 марта 2007, 23:12
Оценка за ответ: 5

2. Отвечает эксперт: Николай Рубан

Единственное что хотелось бы добавить к предыдущему ответу так это то, что если Вам необходимо установить сразу несколько атрибутов к данному файлу то просто перечислите их через логическую связку or.

Вот пример, в котором файлу присваиваются сразу четыре атрибута (только для чтения; скрытый; системный; архивный):

FileSetAttr('attrib.xxx',faReadOnly or faHidden or faSysFile or faArchive);

Good Luck!!!

Ответ отправил: Николай Рубан (статус: 9-ый класс)
Ответ отправлен: 12 марта 2007, 23:38
Оценка за ответ: 5

3. Отвечает эксперт: Spawn

Здравствуйте, Шарайчук Сергй Олександрович!
Для этого есть SetFileAttributes.

Boolean SetFileAttributes(
PChar lpFileName, // имя файла или папки
DWord dwFileAttributes // атрибут или комбинация атрибутов
);

FILE_ATTRIBUTE_ARCHIVE - архивный
FILE_ATTRIBUTE_HIDDEN - скрытый
FILE_ATTRIBUTE_NORMAL - обычный
FILE_ATTRIBUTE_OFFLINE - временно недоступный
FILE_ATTRIBUTE_READONLY - для чтения
FILE_ATTRIBUTE_SYSTEM - системный
FILE_ATTRIBUTE_TEMPORARY - временный

Также есть функция для получения текущих атрибутов файла GetFileAttributes.

DWord GetFileAttributes(
PChar lpFileName // имя файла или папки
);

Приложение:

Ответ отправил: Spawn (статус: 1-ый класс)
Ответ отправлен: 13 марта 2007, 13:24
Оценка за ответ: 5

4. Отвечает эксперт: Дима Гусаков

Здравствуйте, Шарайчук Сергій Олександрович!
функция FileGetAttr(const FileName: String): Integer определяет атрибуты файла
функция FileSetAttr(const FileName: String; Attr: Integer): Integer устанавливает атрибуты файла

атрибуты
faReadOnly - только для чтения
faHidden - скрытый файл
faSysFile - системный файл
faVolumeID - идентификатор тома
faDirectory - имя каталога
faArchive - архивный файл
faAnyFile - любой файл

Ответ отправил: Дима Гусаков (статус: 2-ой класс)
Ответ отправлен: 14 марта 2007, 11:56
Оценка за ответ: 5


Вопрос # 402

Приветствую!!!Как в TreeView нажать на SubItem?

Вопрос задал: KilkaMS (статус: Посетитель)
Вопрос отправлен: 13 марта 2007, 00:31
Всего ответов: 2; сообщений в мини-форуме вопроса: 1

 

1. Отвечает эксперт: Роман

Здравствуйте, KilkaMS!Я не совсем понял что значит "нажать на SubItem" но если вам нужно выполнить какое либо действие по нажатию на определённый узел то посмотрите функцию в примере она позволяет получить строковый путь в TTreeView,немного изменив её можно выполнять действия связанные с выбранным узлом.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 13 марта 2007, 02:20

2. Отвечает эксперт: Вадим К

А может вы просто хотите выделить елемент? там есть свойство Select у каждой ноды. Или просто развернуть ноду хочеться? есть метод Expand()
С другой стороны у TreeView нет SubItem. Они есть у ListView. Мож путаете?

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 13 марта 2007, 11:36


Вопрос # 403

Здравствуйте. Для выделения точек на канве, я выделяю их с помощью процедурки: DrawFocusRect. Однако при движении прямоугольника проходиться перерисовывать полностью все, поэтому изображение мелькает. Если при движении сохранять предыдущую точку и потом переривывать с помощью: FrameRect и DrawFocusRect, то рисунок частично стирается. Думаю нужно сохранять как-то прямоугольник "полностью" (по массиву линий), но обращение к отдельному пикселю слишком медленное. Что лучше применить в данном случае?

Вопрос задал: SMaks (статус: 1-ый класс)
Вопрос отправлен: 13 марта 2007, 04:01
Всего ответов: 3; сообщений в мини-форуме вопроса: 3

 

1. Отвечает эксперт: Роман

Здравствуйте, SMaks!Я в таких случаях использыю вспомогательные слои т.е кпримеру есть расунок фона и нужно перемещять по нему какойлибо об'ект:создаём bg_fon:TImage;грузим в него фоновую картинку,ещё один bg_work:TImage,далее в цикле анимации c помощью copyrect переношу bg_fon на bg_work,рисую на bg_work что надо и copyrect на видимый canvas,и никаких мерцаний нет.И если есть желание посмотрите на delphiworld.narod.ru/_graphic_.html(Графика и Игры).Кстати можно воспользоватся графической библиотекой SpriteUtils с http://www.delphikingdom.com.

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 13 марта 2007, 04:52
Оценка за ответ: 5
Комментарий: В моем случае полностью прямоугольник копировать не нужно, только 4 линии, а как это сделать максимально быстро?

2. Отвечает эксперт: Вадим К

Если вам нужен только прямоугольник выделения, то советую воспользоваться режимим карандаша xor. В результате никаких дополнительных манипуляций.
как сделать.
Image1.Canvas.pen.mode:=pmXOR;//Кажеться так
//рисуем прямоугольник.
//он рисуется поверх старого!
//благодаря режиму ксор он сотрётся
//терерь сдвигаем координаты и снова рисуем прямоугольник.

То есть, хотя мы рисуем два прямоугольника, скорость приличная.Испытано много раз. Здесьмы используем то, что A xor B xor B = A

Предупрежу вопрос о быстром доступе к пикселям. Погуглите на тему ScanLine

Ответ отправил: Вадим К (статус: Кандидат наук)
Ответ отправлен: 13 марта 2007, 11:30
Оценка за ответ: 4
Комментарий: Пробовал, мелькает сильно.

3. Отвечает эксперт: Новаковский Юрий Аврамович

Здравствуйте, SMaks!

Создайте переменную
var BitMap:TBitMap;

Инициализируйте ее
BitMap := TBitMap.Create;

Копируйте канву с Вашего имиджа
BitMap.Canvas.Assing(Image1.Canvas);

Чевото делаете с изображением
BitMap.Canvas.Pixels[100,44]:=clRed;
.....
.....
При этом никаких перерисовок не происходит т.к.
BitMap не виден и все операции с ним не затрагивают графическую подсистему.
Для этого он и существует.

Возвращаете канву на место
Image1.Canvas.Assing(BitMap.Canvas);
Вот тут и будет перерисовка ОДНА.
BitMap.Free;

Все! Удачи!

Ответ отправил: Новаковский Юрий Аврамович (статус: 4-ый класс)
Ответ отправлен: 13 марта 2007, 12:22
Оценка за ответ: 4


Вопрос # 404

Здравствуйте! Давно уже хотел спросить, для чего предназначены и что делают методы Lock и соотвественно UnLock канвы?

Вопрос задал: SMaks (статус: 1-ый класс)
Вопрос отправлен: 13 марта 2007, 05:58
Всего ответов: 1

 

1. Отвечает эксперт: Лукьяненко Алексей Валериевич

Метод Lock блокирует канву для вызвавшего этот метод потока (Thread) в многопоточном приложении. До последующего вызова Unlock никакой другой поток не сможет заблокировать канву для себя и проводить операции с ней.

Ответ отправил: Лукьяненко Алексей Валериевич (статус: 1-ый класс)
Ответ отправлен: 13 марта 2007, 10:39
Оценка за ответ: 5


Обучение Delphi

» Найти все предыдущие уроки можно на www.delphi.int.ru в разделе "Статьи". Последние 3 урока:

18. Работа со строками и символами
19. Подпрограммы (часть 1)
19. Подпрограммы (часть 2)

Подпрограммы (часть 3)

Автор:
© Ерёмин А.А., 2008
Для любого программного пакета справедливо: как только пользователь полностью изучит все возможности пакета, появится новая версия с новыми функциями.
Номер урока:
21

Решение домашнего задания из урока №20

Домашнее задание, предложенное в прошлом уроке было следующим:

Составить подпрограммы:

  1. Для вычисления факториала указанного числа.
  2. Для преобразования текста, содержащего русские буквы, в верхний регистр.
  3. Для вычисления результата импликации двух логических выражений (A -> B).

Задача 1. Факториалом числа n называется произведение 1*2*3*...*n и обозначается факториал "n!". Факториал числа 0 равен 1. Вычислить факториал можно последовательным умножением чисел 1, 2, 3, ... в цикле. В данном случае вполне подойдёт цикл FOR.

function Factorial(n: Integer): Int64;
var i: Integer;
begin
  Result:=1;
  for i:=2 to n do
    Result:=Result*i;
end;

Обратите внимание, что для выходного значения функции объявлен тип данных Int64. Это сделано по той причине, что факториалы - достаточно большие числа. Проверьте, к примеру, чему равен факториал числа 20... "Обычными" типами данных здесь не обойтись.

Задача 2. В одном из предыдущих уроков вы уже научились работать со строками. Здесь и пригодятся эти умения. Вообще, функции для преобразования регистра текста уже существуют, и работают они гораздо быстрее, чем те же функции, написанные самим программистом (они специальным образом оптимизированы). Но в качестве упражнения решение этой задачи вполне подойдёт. Существуют разные способы выполнения требуемой операции. Например, один из них такой. Мы заранее перечисляем все буквы русского алфавита, причём отдельно указываем буквы в нижнем регистре, и отдельно - в верхнем, но делаем это таким образом, чтобы соответствующие буквы находились на одних и тех же местах. А далее мы просматриваем каждый символ текста и ищем его в списке букв нижнего регистра. Если нашли (т.е. текущий символ - русская буква нижнего регистра), то заменяем её на соответствующую букву верхнего регистра. Как определяем букву для замены? А по позиции - в какой позиции находится "нижняя" буква, в такой же находится и "верхняя ". Реализация:

function RusToUpper(Str: String): String;
const
  LetL = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя';
  LetU = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';
var i: Integer;
begin
  Result:=Str;
  for i:=1 to Length(Str) do
    if Pos(Str[i],LetL) > 0 then
      Result[i]:=LetU[Pos(Str[i],LetL)];
end;

Задача 3. Импликация (лат. implico - тесно связываю) - логическая операция, образующая сложное высказывание из двух высказываний посредством логической связки, соответствующей союзу "если ..., то ...". Импликация ложна лишь в случае истинности первого выражения и ложности второго и истинна во всех остальных случаях. Обозначается импликация стрелкой вправо (A -> B).
Как следует из определения, импликация A -> B будет ложна только в том случае, если A = True и B = False. Так и запишем:

function Implication(A,B: Boolean): Boolean;
begin
  Result:=not(A and not(B))
end;

Введение

Третий и завершающий урок по теме "подпрограммы". В предыдущих двух мы разобрались, что такое подпрограммы, зачем они нужны, а также научились создавать свои собственные подпрограммы и пользоваться ими. В этом уроке будет скорее не новый материал, а дополнение к уже имеющемуся.

Способы передачи параметров в подпрограммы

Существует два способа передачи параметров. До текущего момента мы использовали только один способ - передача по значению (англ. by value). Смысл этого способа в том, что мы передаём подпрограмме конкретное значение - число, текст, логическое значение и т.д. Подпрограмма каким-либо образом использует это значение. При этом, из внешней программы передавать эти параметры можно было как явным указанием значения (например, указав число прямо в коде программы), так и передавая переменную или константу - использовалось соответствующее значение переменной / константы.

Но такой способ не всегда удобен. Более того, в случае, если подпрограмма должна вычислить сразу несколько значений, этот способ не принесёт успеха. Именно поэтому существует другой способ передачи параметров - передача по ссылке (англ. by reference). Смысл этого способа в том, что мы передаём не конкретное значение, а ячейку памяти, т.е. переменную. В чём же отличие? А отличие в том, что подпрограмма уже может работать с этой переменной, т.е. не только получать её значение, но и это значение менять! Получается, что мы берём переменную из основной программы, "отдаём" её подпрограмме, та, в свою очередь, производит какие-то манипуляции с ней, и в результате наша переменная получает новое значение и мы можем далее её использовать. Несложно догадаться, что такой подход позволит подпрограмме отдавать сразу несколько значений (причём не обязательно одного типа).

Для передачи по значению никаких изменений в подпрограмму вносить не нужно - это способ передачи по умолчанию. А вот для передачи по ссылке нужно всего лишь в описании подпрограммы добавить слово var перед нужными параметрами.

procedure Proc(a: Integer); //Передача по значению
 ...
procedure Proc(var a: Integer); //Передача по ссылке

Как нетрудно догадаться, если в процедуре требуется передача по ссылке, соответствующий параметр непременно должен быть переменной. Фиксированного значения там быть не должно. Ошибиться здесь трудно - программа просто не скомпилируется, если вместо переменной будет конкретное значение.

Примерами функций с передачей по ссылке являются широкоизвестные Inc() и Dec(). Вспомните - ведь не нужно писать a:=Inc(a); - достаточно просто Inc(a).

Пример. Любое целое положительное число можно представить в виде n = x2 + y, где x, y - тоже целые положительные числа. Написать подпрограмму, которая для заданного числа находит наибольшее возможное значение x и соответствующее значение y. Например, для 29: x = 5, y = 4.

Определим, что от нас требуется. А требуется от нас подпрограмма, которая принимает на вход число и в результате выдаёт другие два числа. Функцией это сделать не получится, ведь функция может вернуть только одно значение. Выход - процедура с передачей по ссылке. У нас будет 3 параметра: исходное число и две "ячейки" для переменных, куда будут записаны полученные значения. Заголовок процедуры будет таким:

procedure GetXY(n: Word; var x, y: Word);

Тип данных Word выбран специально для того, чтобы отрицательные значения не могли быть переданы процедуре.

Теперь реализация самой функции. Нам нужно найти максимальное значение x. Самый простой способ сделать это - извлечь квадратный корень из числа и округлить его в меньшую сторону. Далее полученный x нужно возвести в квадрат и найти разницу между этим квадратом и исходным числом - вот и число y. Единственное, что нужно учесть - y должен быть положительным числом, а значит не может быть нулём. А нулём он будет в том случае, если квадратный корень из n извлечётся нацело. В этом случае просто уменьшаем x на единицу и пересчитываем y. Окончательный код процедуры:

procedure GetXY(n: Word; var x, y: Word);
begin
  x:=Trunc(Sqrt(n));
  y:=n-Sqr(x);
  if y = 0 then
  begin
    Dec(x);
    y:=n-Sqr(x);
  end;
end;

Проверка работы подпрограммы при нажатии на кнопку:

procedure TForm1.Button1Click(Sender: TObject);
var N,A,B: Word;
begin
  N:=StrToInt(Edit1.Text);
  GetXY(N,A,B);
  Caption:=IntToStr(N)+' = '+IntToStr(a)+'^2 + '+IntToStr(b);
end;

Как видите, передача по ссылке является достаточно удобным механизмом взаимодействия программы и её подпрограмм. Если бы мы захотели решить эту задачу с использованием функций, пришлось бы писать две отдельные функции - одна вычисляла бы x, а другая - y. Что уж говорить о том, что одни и те же вычисления делались бы 2 раза...

На один параметр больше...

Недавно на одном форуме заметил интересное сообщение. Совершенно случайно была обнаружена занятная вещь: если в коде вызова подпрограммы в скобках после указания все параметров добавить запятую, т.е. "намекнуть", что дальше должен быть ещё один параметр, компилятор безо всяких ошибок такую строку кода скушает. Если же сам параметр указать, при компиляции возникнет ошибка. Если добавить больше одной запятой - тоже будет ошибка. Т.е. в нашем примере можно написать:

GetXY(N,A,B,);

Это просто отступление от темы - забавная вещь.

Параметры-константы

Есть ещё одна модификация параметров подпрограммы. Можно любой из них сделать константой. Нужно это в случае, если вы хотите контроллировать свой код на предмет отсутствия команд для изменения значения входного параметра. Делается это добавлением слова const перед переменной в заголовке.

Например, мы хотим для нашей предыдущей задачи находить x и y не для числа n, а для n+1. Для этого добавим в тело подпрограммы соответствующую строку:

procedure GetXY(n: Word; var x, y: Word);
begin
  Inc(n);
  ...

Но теперь, если мы сделаем параметр n константой, компилятор выдаст ошибку на только что добавленной строке:

procedure GetXY(const n: Word; var x, y: Word);
begin
  Inc(n);
  ...
[DCC Error] E2064 Left side cannot be assigned to

Понятно, что при передаче по значению даже если значение параметра и будет изменено, во внешнюю программу оно не попадёт... Но для корректировки работы функций объявление параметров константами может быть полезным.

Необязательные параметры

Часто подпрограммы имеют большое количество параметров, что подчёркивает их универсальность и обширность выполняемых действий. Однако во многих случаях одни и те же параметры имеют одинаковое значение, т.е. среди вариантов значений одного параметра есть наиболее популярный. В этом случае для упрощения вызова подпрограмм часть параметров делают необязательными. Необязательный параметр может быть передан подпрограмме, а может и быть опущен. Для того случая, когда он опущен, имеется его исходное значение, которое подпрограмма и будет использовать.

Например, процедура Inc() может увеличивать значение переменной не только на единицу, но и на произвольное число - у неё есть второй параметр, отвечающий за эту величину, но параметр этот необязательный. Таким образом, если второй параметр указан - функция прибавляет указанное число единиц, а если параметр отсутствует - прибавляет единицу, которая задана как значение этого параметра по умолчанию. Понять, какие параметры обязательные, а какие - нет, можно по всплывающей подсказке с параметрами функции, которая появляется после набора открывающей скобки в редакторе кода:

Список параметров процедуры Inc()

Необязательные параметры указываются в квадратных скобках.

Удобно, согласитесь? Сейчас мы научимся делать необязательные параметры и в своих подпрограммах.

Для начала стоит отметить, что необязательные параметры должны находиться среди всех параметров в конце. Понятно почему - ведь если необязательный параметр будет в середине, откуда компилятор узнает, присутствует здесь этот параметр или нет? Если бы были разные типы данных - понять это было бы возможно, но если одинаковые (например, все параметры - числа), то ошибка неизбежна и поэтому самым разумным выходом является расположение необязательных параметров в конце.
Теперь о том, как сделать параметры необязательными. А здесь всё крайне просто - если указать значение по умолчанию, то параметр и станет необязательным. Указывается значение самым обычным образом - после имени аргумента и типа данных ставится знак равенства "=" и далее значение.

Пример. Создадим функцию, вычисляющую десятичный логарифм заданного числа или логарифм по указанному основанию.

function Logarithm(Num: Real; Base: Real = 10): Real;
begin
  Result:=Ln(Num)/Ln(Base)
end;

В описанной функции параметр, отвечающий за основание логарифма, необязательный. Его исходное значение - 10. Если при вызове функции этот параметр будет опущен, основание будет 10, а если будет задан - будет вычислен логарифм по указанному основанию. Откуда появилась в формула в теле функции не спрашивайте, а лучше загляните в учебник математики :-)

Посмотрите количество параметров функции CreateProcess():

Параметры функции CreateProcess()

Согласитесь - каждый раз писать такое количество параметров просто невыносимо. В данном случае необязательные параметры вполне могут решить проблему. Но на самом деле, для этой функции написаны несколько "обёрток", т.е. функций, принимающий только самые необходимые параметры, а все остальные остаются одинаковыми.

Привязка подпрограмм к форме

Если подпрограммы простые и занимаются, к примеру, арифметическими вычислениями, они могут просто располагаться в коде и прекрасно себя чувствовать. Однако, если вы попытаетесь из подпрограммы обратиться, скажем, к форме, или к её компонентам, ничего не выйдет - подпрограмма ничего не знает о вашей форме. Для того, чтобы из подпрограммы работать с компонентами формы, нужно выполнить кое-какие действия - сделать подпрограмму методом формы. Подробнее о том, что такое метод и как создаются методы для объектов, мы рассмотрим позже, когда будем знакомиться с объектно-ориентированным программированием. Сейчас же моей целью является просто показать, как это делается, чтобы вы могли делать точно так же в своих программах.

Рассмотрим конкретный пример. Пусть у нас на форме есть 3 кнопки - Button1, Button2 и Button3. Нам требуется из разных мест программы то включать эти кнопки, то выключать (через свойство Enabled). Чтобы не копировать один и тот же код, лучше написать подпрограмму, которая будет делать всё необходимое. Итак, вот наша процедура:

procedure EnableButtons(Enabled: Boolean);
begin
  Button1.Enabled:=Enabled;
  Button2.Enabled:=Enabled;
  Button3.Enabled:=Enabled
end;

Всё бы ничего, но при компиляции получаем ошибку: [DCC Error] Unit1.pas(29): E2003 Undeclared identifier: 'Button1'. Процедура "не видит" кнопку Button1. А точнее, не видит она и остальные две - это первое из сообщений об ошибке.

Итак, чтобы "привязать" процедуру к форме, мы должны сделать следующее:

1) В заголовке процедуры перед названием должны добавить имя класса формы. Имя класса формы в Delphi автоматически формируется из буквы "T" и имени самой формы. Т.е. для формы Form1 имя класса TForm1. Имя вы можете увидеть в модуле в разделе var - там описана сама форма:

Класс формы Form1 - TForm1 (редактор кода)

Между именем класса формы и именем подпрограммы должна стоять точка. В результате заголовок процедуры станет таким:

procedure TForm1.EnableButtons(Enabled: Boolean);

2) Теперь нужно добавить заголовок метода в описание самой формы. Для этого нужно скопировать заголовок нашей процедуры в секцию private или public в раздел type, где описана наша форма. Единственное, что ещё нужно сделать - удалить название класса формы в скопированной строке. В результате получим:

Подпрограмма в описании класса формы

Выбор раздела - private или public в каждом случае следует определять отдельно. Всё, что описано в private, доступно только в рамках данной формы. А всё, что описано в public, доступно из других форм и модулей. К примеру, если в вашей программе две формы и из второй нужно запускать процедуру, заголовок следует скопировать в public.

На этом "привязка" процедуры к форме завершена. Теперь программа скомпилируется без ошибок. Осталось только выяснить, как запускать созданную подпрограмму. А здесь никаких сложностей нет - подпрограмма доступна как имя_формы.имя_подпрограммы. В нашем случае это Form1.EnableButtons. Однако, такая запись необходима только если вы вызываете подпрограмму откуда-то извне, например из другой формы. Если вызов происходит откуда-то из самой Form1, можно обращаться к процедуре просто по имени. Например, поместим на форму TCheckBox и в обработчике его события OnClick напишем:

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  EnableButtons(CheckBox1.Checked)
end;

Теперь, если флажок установлен, кнопки активны, а если снят - неактивны.

А если, например, есть Form2 и CheckBox2 на ней, то обработчик будет такой:

procedure TForm2.CheckBox2Click(Sender: TObject);
begin
  Form1.EnableButtons(CheckBox2.Checked)
end;

Заключение

В сегодняшнем уроке мы рассмотрели способы передачи параметров в подпрограммы, необязательные параметры, а также научились осуществлять взаимодействие между подпрограммами и компонентами формы. Теперь вам известно всё, чтобы правильно создавать свои подпрограммы. Домашнего задания в этот раз нет - экспериментируйте самостоятельно. В следующий раз мы перейдём к новой теме. Успехов!


Оцените данный урок (1 - плохо, ..., 5 - отлично): -1- -2- -3- -4- -5-. Комментарии в тексте письма приветствуются.
 

Статьи

Самые популярные статьи на сайте:

Работа с приложениями Microsoft Office. Excel
Конвертирование графических форматов
Работа с приложениями Microsoft Office. Word
Как можно из Delphi отслеживать все события Windows?
Написание инсталлятора на Delphi
Работа с реестром и INI-файлами в Delphi
Работа со строковыми типами данных
Создание непрямоугольных форм в Delphi
Как прочитать ID3-Tag'и из MP3-файла?
Работа с HTML-справкой в программах

Читаем цитаты с bash.org.ru своей программой

Автор: Вадим К

I. Вступление

Интернет всё больше и больше входит в нашу жизнь. Мы часто сидим и нажимаем кнопку "обновить", ожидая новых данных на заветной страничке. Но ведь надо и работать когда-то, поэтому задачу мониторинга странички с новостями мы поручим Delphi, а сами будем работать (или заниматься другим полезным делом – жизнь ведь прекрасна). Если что – всё будет скачано и представлено в удобном для нас виде.

В качестве "подопытного кролика" я выбрал многим известный цитатник рунета – bash.org.ru. Программа будет забирать с главной странички цитаты, и складывать их в базу. А с цитатами в базе можно делать что угодно.

Эта статья отличается от моих других тем, что я даю сразу готовое приложение и комментирую интересные моменты.

II. Общие замечания

Внешний интерфейс программы не претендует на награду. Я над ним особенно не задумывался, так как основная задача в другом. Интерфейс сделаете сами, если он вам нужен.

Это приложение построено по модульно-объектной технологии (мне больше нравится название "Разделяй и властвуй"). То-есть, для каждой сущности есть объект, и эти объекты взаимодействуют между собой. Так как связи и зависимости между ними минимальные, то можно легко их заменять и модифицировать.

Чтобы легче было искать место в коде, на которое я ссылаюсь, я использую специальные маркеры. В тексте статьи они выглядят так {текст}. Чтобы найти код, который соответствует ему, нужно сделать следующее. Перейти в Delphi, выбрать в меню View » ToDo List. Найти там соответствующий текст и кликнуть дважды. А по тексту программы вы увидите их как { TODO -oVadim -cView : текст }.

III. Класс базы данных (БД)

Обзор класса

Начнём разбор с класса, который обслуживает базу данных. Только объекты этого класса имеют доступ к базе данных, только они знают как с ней работать. Остальные классы не должны ничего знать о базе данных.

В самом верху юнита BBasa объявлен абстрактный класс TBBasaCustom {B1}. Этот класс имеет только один метод для добавления цитат в базу, да и тот абстрактный. Рабочий класс будет наследоваться от него. Это сделано специально, чтобы из того объекта, который будет добавлять данные, нельзя было бы обратиться к другим методам, и ему было всё равно, какие ещё методы есть у класса. Они ему не нужны. Это выглядит дивно, но позже станет понятно.

В этом же юните объявлен класс TBBasa {B2}. Этот класс наследуется от нашего класса и реализовывает всю нужную функциональность, а именно:

Открывает БД при своем создании. Если файл базы отсутствует – он его создаст. {B6}

Умеет добавлять цитату, так как реализовывает абстрактный метод Add. {B3}

Умеет найти в базе цитату по номеру – метод GetQuotes. {B4}

Посмотрите внимательно на public методы. Ни один из них не расскажет о том, как и где хранятся данные. Поэтому, никто не мешает переписать методы и хранить цитаты в текстовом файле или нескольких файлах. Остальной код этого никак не почувствует. Ощущаете силу такого подхода к программированию?

В качестве базы данных я использую SQLite.

Рассмотрим некоторые методы детальнее.

Метод Add

Этот метод {B3} получает два параметра – Number и Text – соответственно номер цитаты и её текст. Перед добавлением вначале проверяет, а нет ли уже цитаты в базе. Для этого он делает запрос на выборку цитат с заданным номером. Если цитата не найдена (количество найденных строк равно нулю), то добавляем в базу. Конечно, теоретически может быть, что в базе будет несколько записей с одним номером (программная ошибка, к примеру), но я не усложняю. В конце метода есть вызов SendCommand. Это оповещение интерфейса о том, что есть новые цитаты. Как это работает – будет рассказано ниже.

Метод GetQuotes

Этот метод {B4} по заданному номеру цитаты находит её и возвращает, предварительно удалив спецсимволы. Если цитата не найдена – возвращает пустую строку (оно логично). Интересно также то, что этот метод обращается к другому, который запрашивает "сырой текст" из базы.

IV. Класс потока

Обзор

Данный класс занимается основной работой – он скачивает главную страничку, парсит, и отдаёт поштучно цитаты объекту БД. Вся реализация находится в юните BTread.

Как видно из кода, у этого класса только три публичных метода – конструктор, деструктор и запрос на обновление. А больше ему и не надо.

Рассмотрим как всё это работает. Через конструктор {T1} при создании класса мы передаём ему ссылку на объект БД, чтобы потом иметь возможность добавлять цитаты.

После того, как поток будет запущен, начинает выполняться метод Execute {T2}. Он предельно прост – пока нас не завершили, повторять: скачать, распарсить и подождать. Все действия специально разделены, чтобы быть независимыми.

Скачивание страницы

Метод скачать страничку GetText {T3} просто возвращает в виде строки содержимое страницы. Если вам по каким-то идеологическим причинам не нравятся компоненты Indy, просто замените здесь на свой код, и всё. Сам метод хорош ещё тем, что показывает, как в RunTime создавать компонент и назначать методы.

Парсинг

Вытягивать цитаты {T4} наиболее просто с помощью регулярных выражений. Откуда я взял регулярное выражение – не спрашивайте. Учитесь сами его составлять. Кстати, на сайте есть статья, посвященная им. Больше в этом методе ничего интересного.

Сон

Между скачиванием цитат надо делать паузу. Так как мы находимся в потоке, то свободно можем писать 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. Выводы

Конечно, это очень сырой пример, и на выставку он не годится. Но он хорош тем, что является заготовкой для различных программ подобного типа – собирать новости, выкачивать галереи картинок, собирать данные.

И помните, в некоторых случаях подобные программы могут не дружить с законом! Будьте внимательны, и не нарушайте.

Файлы к статье »

Файловый архив

Разделы: Статьи | Компоненты | Plug-in's | Документация | Исходники | Программы | Игры | Изображения

Уважаемые читатели! Отправляйте полезные компоненты/модули, исходники, собственные программы/игры, документацию - книги, учебники и они будут размещены на сайте.

Название
Описание
Раздел
Объём
Ссылки
Vista Hint Style
Пример создания всплывающей подсказки в стиле Windows Vista на основе THintWindow.
199 Кб
Disk Visor
Программа подсчитывает размер любого каталога с учётом всех подкаталогов и файлов, содержащихся в нём. Также программа может использоваться для обзора структуры файлов и каталогов на диске и для нахождения данных, занимающих больше всего места.
72 Кб
GetColor
Небольшая программа для получения цвета любой точки экрана из любого другого приложения. Аналог "пипетки" в графических редакторах.
82 Кб
Icarus - Uses List Analyzer for Delphi

Программа, которая поможет разработчику удалить ненужные модули из раздела uses. Удаление ненужных модулей имеет следующие преимущества:
- неиспользуемый код не включается в конечное приложение;
- удаляются связи с ненужными модулями, код становится чище;
- уменьшается размер конечного файла (EXE, DLL, BPL).

Также программа подсказывает, какие модули можно перенести из раздела interface в раздел implementation.

1.33 Мб

TWhisperSplitter
Расширение стандартного компонента TSplitter: заливка градиентом, изменение цвета при наведении курсора, использование фонового изображения, программное управление положением компонента, автоматическое восстановление положения.

226 Кб

Программа-пример к статье "Читаем цитаты с bash.org.ru своей программой"

258 Кб

 
Всего новых файлов: 6  
2.17 Мб
 
 

Юмор

Ведущий раздела: Bruder

Переписка или "Как я завел себе почтовый ящик"

Завел я себе как-то новый ящик для электронной почты в Интернете. У меня и так-то этих ящиков штук восемь, но почти все неудачные. То ничего не отправить с них, а то и не получить. Письма теряются. А тут, зашел на один портал, а там - реклама завлекательная. Дескать, заводите у нас ящики почтовые - емкие, быстрые, бесплатные и навороченные. Ну, я и завел. Зарегистрировался, ответив на десяток вопросов. Честно сказать, - наврал много в этих ответах. Все врут. Посмотрел на разные дополнительные возможности и решил установить автоответчик. Никогда у меня такой штуки не было. Захотелось попробовать. Приходит, допустим, мне сообщение на этот адресок, а ящик мой сразу откликается: «Автоответчик Сергея Литовкина. Ваше письмо будет обязательно доставлено адресату. Посмотрите пока, плз., его авторские проекты по следующим URLам: http://www.litovkin.ru/ - «На флоте бабочек не ловят» ... ... ... и пр. (еще штук эдак пять).». Послал сам себе писульку через другой ящик и получил через минуту привет от автоответчика. Пр иятно, словно пообщался со старым другом.

Наутро проверяю я почту и обнаруживаю, что весь новенький ящичек забит какими-то письмами. И писем этих: - девятьсот восемьдесят шесть. Во! Удивился я. Так много мне еще не писали. Потом пришло разочарование. Почти все послания оказались одинаковыми. Все из одного адреса и с английским содержимым. Проколупавшись в своей почте полчасика, я выяснил следующее.

Когда я с вечера выключил свой компьютер, жизнь в Интернете не остановилась, и на мой новый ящичек от имени руководства портала было послано поздравление новому пользователю, то есть - мне. Мне писали, что я никогда не пожалею о том, что завел себе бесплатный ящик там где следует, а не в другом каком месте. При этом было указано, что отвечать на это теплое поздравление не обязательно, так как оно произведено с помощью автоматической программы. Однако мой автоответчик тактично отправил в ответ полагающийся текст: «Автоответчик Сергея Литовкина. Ваше письмо будет обязательно доставлено адресату. Посмотрите пока, плз., его авторские проекты по следующим URLам: http://www.litovkin.ru/ - «На флоте бабочек не ловят» ... ... ...». На другом конце хорошо бы и заткнуться. Но, не тут то было. Тот адресок, с которого всем, кому ни попадя, рассылались поздравления, числился запрещенным для приема корреспонденции. Вследствие этого, почтовый сервер сразу выдал на мой ящик сообщение, которое, переведя с английского, можн о изложить следующим образом: «Это сообщение создано автоматически системой поставки почты. Сообщение, которое Вы послали, не может быть доставлено получателю. Копия прилагается... ... .(далее - 65 строк)».

Если Вы думаете, что мой автоответчик это спокойно съел, то Вы ошибаетесь. Он отправил в ответ (в адрес автоматической системы поставки почты) свой, хорошо усвоенный, текст: «Автоответчик Сергея Литовкина. Ваше письмо будет обязательно доставлено адресату... ... ... ... .» - и так далее. Адресок, в который все это было отослано, как водится, вовсе не предназначался для получения чего-либо и числился запрещенным для приема корреспонденции. Следствием этого стало новое послание в адрес моего ящичка: «Это сообщение создано автоматически системой поставки почты. Сообщение, которое Вы послали, не может быть доставлено получателю. Копия прилагается... ... . (далее - 186 строк)». Мой ящик ответил скромно, но с достоинством. Текст Вы, как я полагаю, уже помните. Автоматическая система поставки почты не сдавалась. Так они между собой и перекидывались всю ночь до заполнения моего ящичка этим содержимым, после чего автоответчик замолчал и уже не смог перебросить перчатку противнику.

На тот портал я больше не хожу и в тот, забитый под завязку, ящик не лазаю, но собираюсь, все-таки, завести себе еще парочку автоответчиков для взаимной переписки. Есть в этом что-то человечное: «Автоответчик Сергея Литовкина. Ваше письмо будет обязательно доставлено адресату.... ... ...». А в ответ - не менее теплые слова. Пусть попереписываются. А там, и до искусственного интеллекта рукой подать...

Источник: bayanov.net

:))

Присылайте компьютерные анекдоты, рассказы и истории по этой ссылке и они будут опубликованы в ближайших выпусках рассылки.




Ведущий рассылки: Ерёмин Андрей


В избранное