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

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

  Все выпуски  

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


Программирование на DELPHI
Выпуск #77 (24 ноября 2007 г.)

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

Delphi.int.ru

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

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

Сервер: irc.dalnet.ru (либо irc.tic-tac.ru)
Порт: 6667
Канал: #delphiintru

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

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

Запущен в тестовый режим IRC-канал сайта в сети RusNet. Данные для подключения:

Сервер: irc.rus.net (имена всех остальных серверов сети см. на официальном сайте сети)
Порт: 6667 (альтернативные порты см. там же, где и имена серверов)
Канал: #delphi.int.ru

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

Приглашаем Вас на наш канал!

Следует напомнить, что официальным каналом является канал в сети DalNet:

Сервер: irc.dalnet.ru (или irc.tic-tac.ru, irc.chatnet.ru, irc.blood.ru и др.)
Порт: 6667
Канал: #delphiintru

Обратите внимание, что название нового (тестового) канала включает точки, а название официального - не включает.

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

Всем тем, кто ещё не зарегистрировался на сайте, рекомендуется это сделать. Регистрация предоставит Вам полный доступ к возможностям сайта. Перейти к регистрации »

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

Количество экспертов: 40 (+3).
Участниками задано вопросов: 1134 (+87).
Экспертами отправлено ответов: 1710 (+109).
Количество сообщений на мини-форумах: 2083 (+142).
Максимальное число разосланных в день писем (за ноябрь '07): 1437 (12.11.2007).
Максимальное число разосланных в день писем (за всю историю): 1960 (28.10.2007, +140).

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

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

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

Количество читателей рассылки (24.11.2007, 12:00):
5596+1530+463= 7589 (+94)

Связь по e-mail:

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


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

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

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

11 ноября 2007 г.

1. Создана возможность указания часового пояса - добавлена опция в личные настройки. Эта возможность позволяет локализовать все отметки даты и времени на всех страницах сайта и в письмах, отправляемых с сайта. По умолчанию для всех участников установлен часовой пояс +3 (т.е. время сайта).
2. Добавлена возможность поиска участников по никам в сети IRC (страница Поиск участников).
3. Для сообщений в мини-форумах вопросов добавлено разделение на страницы.
4. Создан информационный блок "Оперативная информация". В данном блоке отображается информация о последних заданных вопросах, отправленных ответах, оставленных сообщениях на мини-форумах, количестве пользователей, которые в данный момент находятся на сайте и на канале в сети IRC. Блок доступен на любой из страниц сайта с помощью кнопки, расположенной в верхней части страницы.; он является интерактивным и может быть перемещён в любое место страницы.

 

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

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

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

Кол-во вопросов: 15
Кол-ответов: 29
Баллы за ответы: 84
 

Вопрос # 311

Как создать дистрибутив программы, написанной на Delphi 7?

Вопрос задала: Наташа (статус: Посетитель)
Вопрос отправлен: 13 февраля 2007, 14:38 (эксперты)
Всего ответов: 3

 

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

Точно так же, как дистрибутив любой другой программы. Для этого существует очень много программ-исталляторов (InstallShield, WiseInstaller, InnoSetup, др), а также можно написать собственный инсталлятор. В комплекте в Delphi идет урезанная версия InstallShield Express - можете попробовать с ее помощью. Интерфейс программы достаточно прост, и сложностей возникнуть у Вас не должно.
Если что - пишите в форум вопроса или в личку, помогу

Ответ отправил: Лукьяненко Алексей Валериевич (статус: 1-ый класс)
Ответ отправлен: 13 февраля 2007, 14:46

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

Есть ещё достаточно хорошая прога для деланья инсталов NSIS. Основная идея - всё на скриптах.

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 13 февраля 2007, 16:51

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

Здравствуйте, Наташа!
В смысле инсталлятор? Если да, то можно использовать InstallShield.
Его урезанная версия идет в поставке с самой Delphi.

Ответ отправил: Виталий Лещенко (статус: 4-ый класс)
Ответ отправлен: 13 февраля 2007, 18:18


Вопрос # 312

Здравствуйте, уважаемые эксперты. Подскажите ,пожалуйста, как правильно установить и войти в Borland Delphi 7 . Я скачал и установил данную версию, но при попытке войти, мне выдаёт ссылку на регистрацию программы, зайдя по ссылке регистрации не нахожу. Если не трудно подскажите пожалуйста надёжный источник на скачку етой программы не требующий регистрации, или ссылку на регистрацию етой версии.

Вопрос задал: Vitaliy (статус: Посетитель)
Вопрос отправлен: 13 февраля 2007, 17:41 (эксперты)
Всего ответов: 2

 

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

Поддержка Delphi 7 на данный момент отсутствует. Вы не можете её зарегистрировать обычным образом. Если всё таки хочеться, то покупается лцензия для BDS2006 а потом понижается.
Рекомендую скачать TurboDelphi - он бесплатен (не совсем - лицензия на 100 лет:) )и среда, и язык имееют много нового. Правда в бесплатной версии нельзя устанавливать компоненты. Но за небольшую плату вам пришлют лицензию.

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 13 февраля 2007, 18:51
Оценка за ответ: 5
Комментарий: Большое Вам спасибо за совет !

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

Здравствуйте, Vitaliy!
К сожалению и наверное радости регистрация на сайте Borland.com осуществляется только для пользователей, которые приобрели данный продукт через дилерскую сеть. Сам серийник поставляется вместе с дистрибутивом Delphi а для активации через инет проверяется соответствие данного серийника данному продукту.
Варианты искать пиратскую версию с кряком - но не рекомендую - поддержка продукта отсутствует полностью либо что наиболее оптимально приобрести лицензионную версию, которая вполне доступна по цене.

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 13 февраля 2007, 21:15
Оценка за ответ: 5
Комментарий: Спасибо !


Вопрос # 313

Уважаемые експерти объясните, как действует
LoadFromFile. Моя программа должна загружать
одну картинку, ждать определенное время и загружать вторую. Но она сперва ждет
это время, потом моментально загружает одну
за другой картинки. Что делать?

Приложение:

Вопрос задал: Бедзир Олександр (статус: Посетитель)
Вопрос отправлен: 13 февраля 2007, 23:07 (эксперты)
Всего ответов: 4; сообщений в мини-форуме вопроса: 1

 

1. Отвечает эксперт: Сергей Устинов

Здравствуйте, Бедзир Олександр!

После отображения первой картинки вставьте процедуру
Form1.Repaint;

Удачи!

Приложение:

Ответ отправил: Сергей Устинов (статус: 2-ой класс)
Ответ отправлен: 13 февраля 2007, 23:21
Оценка за ответ: 5
Комментарий: Спасибо работаєт

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

Вместо Repaint лучше вставить Application.ProcessMessages. Связано это с тем, что после загрузки содержимого файла компонент ничего не рисует, а прорисовка происходит при получении системного события WM_PAINT. Событие это будет обработано либо в ходе обработки Application.ProcessMessages, либо после окончания вашего кода (во время его обработки программа не реагирует ни на какие системные события)

Ответ отправил: Лукьяненко Алексей Валериевич (статус: 1-ый класс)
Ответ отправлен: 14 февраля 2007, 10:37
Оценка за ответ: 5
Комментарий: Спасибо тоже работает

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

Это всё верно и хорошо, но есть одно но. Не рекомендую создавать процедур, которые будут выполнятся дольше нескольких десятих секунды, так как этим вы тормозите интерфес программы. Можно сделать поток, но для такой простой задачи это уж слишком. Хотя, если вы надумаете сделать 10 картинок + ко всему хитрую логику их перемешивания (например зависящую от фазы луны:)), то тут уж только поток мутить. И паузы получаться точными, и грузиться всё будет. В потоке можно и sleep написать без угрызения совести. Но в вашем случае рекомендую воспользоваться таймером. После первой загрузки картинки выставляете время для таймера, и запускаете его. В обработчике таймера пишете вначале остановку таймера и загрузку нужной второй картинки. Работать будет хорошо

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 14 февраля 2007, 12:53

4. Отвечает эксперт: Косолапов Дмитрий Юрьевич

В дополнение к предыдущему ответу:
1) Вместо Form1.Repaint можно использовать Form1.Image1.Resresh
2) Вместо цикла достаточно воспользоваться процедурой Sleep, котороая ждет заданное количество миллисекунд.

Ответ отправил: Косолапов Дмитрий Юрьевич (статус: 5-ый класс)
Ответ отправлен: 14 февраля 2007, 14:59


Вопрос # 314

Доброго времени суток.
Подскажите как реализовать запрос на SQL , ситуация такая:
Есть БД
Id_remont
Data
Remont
Необходимо выташить Remont за определенный период (например с 01.01.2004 по 01.02.2004) и подсчитать обшее количество Remont.

Вопрос задал: Илья Бабаков (статус: Посетитель)
Вопрос отправлен: 15 февраля 2007, 18:48 (эксперты)
Всего ответов: 2

 

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

Здравствуйте, Илья Бабаков!
SELECT REMONT FROM MYTABLE WHERE DATA>='1.02.2004' AND DATA<='01.02.2003';

SELECT COUNT(REMONT) FROM MYTABLE WHERE DATA>='1.02.2004' AND DATA<='1.02.2004';

Удачи

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 15 февраля 2007, 21:19

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

Еще можно используя команду BETWEEN:

Remont за определенный период:
Select Remont from Table1
where PoleDat between '01/01/2004' and '01/02/2004';

Oбшее количество Remont:
Select Count(Remont) from Table1
where PoleDat between '01/01/2004' and '01/02/2004';

Good Luck!!!

Ответ отправил: Николай Рубан (статус: 7-ой класс)
Ответ отправлен: 16 февраля 2007, 01:31


Вопрос # 315

Скажите, пожалуйста, где сейчас можно достать Kylix 3?

Вопрос задал: Виталий Лещенко (статус: 4-ый класс)
Вопрос отправлен: 16 февраля 2007, 01:23 (эксперты)
Всего ответов: 2

 

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

Превед!
Набрал я в гугле "kylix скачать"... Ёмаё... Блин, чо за люди...

Смотри приложение.

Приложение:

Ответ отправил: min@y™ (статус: Студент)
Ответ отправлен: 16 февраля 2007, 08:29

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

Да, скачать можно, но вот только с установкой будут проблемы. Сам возился когдато. Ему нужны библиотеки нужных версий, и новые ядра ему не подходят. Ставте Lazarus и вы сразу получите всё что надо.

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 16 февраля 2007, 12:44


Вопрос # 316

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

Вопрос задал: Полушин Сергей Анатольевич (статус: Посетитель)
Вопрос отправлен: 16 февраля 2007, 20:32 (эксперты)
Всего ответов: 2

 

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

Смотрим функцию RGB, которая по трём своим параметрам формирует цвет. Параметры имеют тип byte - соответственно диапазон 0..255.
-----
Для движков задаём свойство max=255
дальше для них в обработчике OnChange пишем следующее
Label1.caption:=inttohex(RGB(Trackbar1.position,Trackbar2.position,Trackbar3.position),8);

ну или что то в виде Form1.color:=RGB(.....);

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 16 февраля 2007, 21:20
Оценка за ответ: 5

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

Здравствуйте, Полушин Сергей Анатольевич!Диапазон изменения каждого цвета 0-255;Поповоду второй части посмотри код,там есть функция GetColour(Red,Green,Blue:integer):TColor; - возвращает значение цвета в RGB.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 17 февраля 2007, 00:29
Оценка за ответ: 5


Вопрос # 317

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

procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Button1.Visible := false;
Button2.Visible := true;

Вопрос задал: Толков Геннадий Викторович (статус: Посетитель)
Вопрос отправлен: 17 февраля 2007, 00:52 (эксперты)
Всего ответов: 2; сообщений в мини-форуме вопроса: 2

 

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

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

Во первых на форме надо установить property KeyPreview:=true;
Далее обрабатываем событие OnMouseEnter кнопки 1 при наведении на неё мышью
Button2.Visible:=true;
Button1.Visible:=false;
При выходе из кнопки 2 обрабатываем её событие OnMouseLeave
Button1.Visible:=true;
Button2.Visible:=false;

Удачи!

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 17 февраля 2007, 05:57
Оценка за ответ: 4

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

Здравствуйте, Толков Геннадий Викторович!Используйте процедуру BringToFront.
Описание
Метод BringToFront позволяет изменять последовательность перекрытия компонентов на форме и тем самым управлять видимостью компонентов.
Перекрывающиеся компоненты на форме размещаются поверх друг друга в последовательности (называемой Z-последовательностью), соответствующей порядку размещения компонентов в процессе проектирования. Например, если вы поместили в одно и то же место формы две кнопки одинаковых размеров, то видна будет только вторая из размещенных кнопок, поскольку она расположена в Z-последовательности выше. Применение во время выполнения приложения метода BringToFront к нижней кнопке переместит ее наверх в Z
-последовательности и она станет видна пользователю.

Это справедливо по отношению к не оконным объектам, таким, как кнопки, метки, изображения и т.д., а также и к оконным компонентам, таким, как T
Memo, TComboBox и др. Но все не оконные компоненты всегда расположены в Z
-последовательности ниже оконных и метод BringToFront не может изменить это правило. Например, попытка перенести наверх методом BringToFront метку, размещенную под оконным компонентом, ни к чему не приведет.
1.Пусть вы хотите, чтобы в каком-то месте формы размещалась кнопка, которая в зависимости от текущего режима работы имела бы два различных набора свойств и выполняла бы различные функции. Вы можете разместить в нужном месте две кнопки друг на друге (пусть они имеют имена Button1 и Button2), задать каждой нужные свойства и для каждой описать соответствующие обработчики событий. Тогда для смены этих кнопок вы в соответствующих местах кода программы пишете операторы

Button1.BringToFront

или

Button2.BringToFront

и пользователь будет видеть то одну, то другую из этих кнопок.

2.Пусть в приложении в одном и том же месте формы друг на друге расположены две панели: Panel1 и на ней Panel2, содержащие какие-то управляющие компоненты для разных режимов работы. Panel2 расположена на Panel1, которая является, таким образом, ее родителем. В обработчик события формы OnCreate можно вставить операторы:

Panel2.Parent := Form1;
Panel2.BoundsRect := Panel1.BoundsRect;
Panel1.BringToFront;

Первый оператор делает родительским компонентом панели Panel2 форму Form1
. Второй оператор задает панели Panel2 то же местоположение и размеры, которые имеет панель Panel1. Последнее необходимо, поскольку при проектировании ее координаты соответствовали координатному пространству контейнера - клиентской области панели Panel1. А теперь ее родитель сменился на форму, и надо ее расположить в том же месте формы, в котором расположена Panel1. Третий оператор перемещает наверх форму Panel1.

Приведенный код можно сократить, и убрать из него первый оператор, если в процессе проектирования размещать панель Panel2 не на панели Panel1, а в каком-то другом месте непосредственно на форме. Тогда в обработчике события формы OnCreate достаточно двух операторов:

Panel2.BoundsRect := Panel1.BoundsRect;
Panel1.BringToFront;

изменяющих положение Panel2 и перемещающих наверх форму Panel1.
В результате работы приведенных операторов в момент создания формы на ней будет видна панель Panel1. В момент, когда ее надо заменить на Panel2
, можно выполнить оператор:

Panel2.BringToFront;

выносящий наверх вторую панель. Когда надо вернуть на экран изображение Panel1, можно выполнить операторы:

Panel1.BringToFront;

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


Вопрос # 318

Здравствуйте.Ответте мне пожалуйста на вопрос как свернуть все окна.

Вопрос задал: Толков Геннадий Викторович (статус: Посетитель)
Вопрос отправлен: 17 февраля 2007, 01:43 (эксперты)
Всего ответов: 3; сообщений в мини-форуме вопроса: 3

 

1. Отвечает эксперт: Сергей Устинов

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

keybd_event(VK_LWIN, 0, 0, 0);
keybd_event(Ord('D'), 0, 0, 0);
keybd_event(Ord('D'), 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);

Удачи!

Ответ отправил: Сергей Устинов (статус: 2-ой класс)
Ответ отправлен: 17 февраля 2007, 01:50
Оценка за ответ: 5

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

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

Вот рабочий пример консольного приложения

program Project3;
uses
Windows,
Messages;

var Count:integer;

function EnumProc (WinHandle: HWnd; Param: LongInt): Boolean; stdcall;
begin
if (GetParent (WinHandle) = 0) and (not IsIconic (WinHandle)) and
(IsWindowVisible (WinHandle)) then
begin
PostMessage (WinHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
Inc(Count);
end;
EnumProc := TRUE;
end;

begin
Count:=0;

EnumWindows (@EnumProc, 0);
Writeln('Minimized:',Count,' windows');
end.

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 17 февраля 2007, 06:53
Оценка за ответ: 4

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

Здравствуйте, Толков Геннадий Викторович!Можно сделать так: для начала нужно импортировать в среду Delphi компоненты, позволяющие получить доступ к функциям оболочки (Microsoft Shell Controls & Automation Type Library). Для этого откройте окно Project - Import Type Library. Найдите в списке строку "Microsoft Shell Controls & Automation (version 1.0)" и нажмите Install. Установленные компоненты при неизменных параметрах установки появятся на вкладке ActiveX.Компонент TShell как раз и предоставляет те функции оболочки, которые нас интересуют. Поместите его на форму. Он включает все необходимые методы. Например, чтобы свернуть все окна (аналог функции значка "Minimize all" на панели быстрого запуска), следует написать всего одну строку:
procedure TForm1.Button1Click(Sender: TObject);
begin
Shell1.MinimizeAll;
end;
Также я перечислю все остальные функции, которые теперь находятся в нашем распоряжении:

Explore('путь') - открытие Проводника Windows на указанном каталоге.

Open('команда') - примерно то же самое, что и функции WinExec(), ShellExecute() и т.д., т.е. выполнение указанной команды - запуск программы, открытие документа и т.д.

MinimizeAll - команда "Свернуть все окна".

UndoMinimizeALL - обратная команда - восстанавливает все окна, которые ранее были открыты.

FileRun - открывает диалог запуска программы (Пуск - Выполнить).

CascadeWindows - расставляет все открытые окна в каскадном порядке.

TileVertically - расставляет окна таким образом, чтобы все они были видны на экране и не перекрывали друг друга.

TileHorizontally - тоже самое, что и TileVertically только в горизонтальном направлении.

ShutdownWindows - запускает диалог завершения работы Windows.

SetTime - открывает окно установки даты и системного времени.

TrayProperties - открывает окно настроек иконок системной области (tray).

Help - вызывает справочную систему Windows.

FindFiles - запускает диалог поиска файлов.

FindComputer - запускает диалог поиска компьютеров.

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

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


Вопрос # 320

Здравствуйте. Подскажите как создать ScrollBar особой формы. Например шарик на ниточке. Либо как в Winampе на цветной полоске квадратная ручка с изображением. Я делал подобие ScrollBara рисуя его картинками и управляя Image компонентами описывая все условия немелкой программой. Может есть какой-то простой путь, типа описывания регионов компонента как в случае с фигурной формой?

Вопрос задал: Павлов Евгений Владимирович (статус: Посетитель)
Вопрос отправлен: 17 февраля 2007, 17:29 (эксперты)
Всего ответов: 3; сообщений в мини-форуме вопроса: 1

 

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

Здравствуйте, Павлов Евгений Владимирович!Скорее всего в данном случае прийдётся посоть свой компонент наследник TScrollBar или даже TCustomControl.Приведу на всякий случай вориант изменения цвета scrollbar-a;В Windows предусмотрено сообщение WM_CtlColorScrollBar, которое посылается окну, содержащему элементы управления ScrollBar (полосы прокрутки). В ответ на это сообщение окно должно вернуть системе кисть, которой надо закрасить полосу прокрутки. С помощью WM_CtlColorScrollBar можно получать разноцветные полосы прокрутки, что иногда бывает достаточно красиво.
В Delphi форма при получении этого сообщения посылает соответствующему компоненту типа TScrollBar сообщение CN_CtlColorScrollBar, перепоручая обработку ему. И тут мы сталкиваемся с явным глюком VCL: это сообщение передаётся в стандартную оконную процедуру, хотя сообщение само по себе нестандартное, и стандартная процедура заведомо не сможет его обработать. Из-за этого TScrollBar не может изменять свой цвет, хотя львиная доля работы, необходимой для этого, делается в VCL. Чтобы исправить это, достаточно передать обработку CN_CtlColorScrollBar в метод DefaultHandler вместо DefWndProc. Ещё надо перенести в раздел published свойство Color, чтобы получить возможность управлять цветом полосы прокрутки. Но, несмотря на то, что в VCL здесь явная ошибка, не исправленная, кстати, даже в седьмой версии Delphi, править исходный код StdCtrls всё же не стоит. Вместо этого лучше написать свой компонент, который доделает то, что не доделано в стандартном TScrollBar'е.Код этого компонента ниже.Создав и зарегистрировав такой к омпонент, вы получите возможность управлять цветом полосы прокрутки.В принципе, реализовав обработку CN_CtlColorScrollBar не с помощью процедуры DefaultHandler, а самостоятельно, можно получить не только цветную полосу прокрутки, но и полосу, раскрашенную разными узорами.

Приложение:

Ответ отправил: Роман (статус: 5-ый класс)
Ответ отправлен: 17 февраля 2007, 18:21
Оценка за ответ: 5
Комментарий: Очень содержательно

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

Здравствуйте, Павлов Евгений Владимирович!

Изучить разработку VCL компонентов, принципы наследования. Изучить исходные коды компонентов библиотеки VCL - они поставляются с дистрибутивом Delphi.

Удачи

Ответ отправил: Alex Van Glukhman (статус: 7-ой класс)
Ответ отправлен: 17 февраля 2007, 18:23
Оценка за ответ: 3
Комментарий: Одним словом, для придания форм объекту необходимо изучить всю среду программирования? Спасибо за совет. Пожалуй до такого я еще не дорос. Это очень круто.

3. Отвечает эксперт: Матвеев Игорь Владимирович

Здравствуйте, Павлов Евгений Владимирович!
Изменить форму ScrollBar-а можно, но что толку? можно конечно и функцию отрисовки перехватить, заменив своей, но это сложнее чем написать свой компонент с нуля (TWinControl или, если не требуется управление клавиатурой, т.е. контрол не должен принимать фокус - то и от TGraphicControl).

Есть и другой вариант - скин-библиотеки, можно воспользоваться ей и замениь тогда сразу не только ScrollBar-ы но и другое контролы. А можно поискать и реализацию ScrollBar-а с возможностью смены внешнего вида. Уверен, реалюзацию этого можно найти, если посикать.

Ответ отправил: Матвеев Игорь Владимирович (статус: Студент)
Ответ отправлен: 19 февраля 2007, 06:05
Оценка за ответ: 4
Комментарий: Могли бы и по-подробнее. Спасибо за помощь


Вопрос # 321

Здравствуйте. С кнопками у меня нечего не получилось, ну и
ладно. Я хочу задать вопрос, а с Image1 может так получится.
Я постараюсь правильно сформулировать вопрос.
На форму ложу Image1 и Image2, одну на другую.
Открываю в них две иконки в Image1 32*32, а в Image2 64*64.
Вопрос? Как мне сделать так, что бы наведя на иконку мышкой
(32*32 т.е Image1),появлялась иконка(64*64 т.е Image2),
а, убрав мышку с Image2(64*64), опять появлялась Image1(32*32), так
как это сделано с иконками в программах Talisman, Aston, StileXP,
ну и так далее.
А вот с окнами у меня подошёл один код, который отправил
Сергей Устинов. Спасибо ещё раз всем. Так как я начинающий,
поэтому информацию черпнул не плохую. Ну а если вернутся к окнам
то и здесь маленький нюанс, мне надо, что бы все окна сворачивались,
а моё (главной формы) не сворачивалось. Можно так сделать? И в
заключении ещё раз поблагодарю всех, кто помогает тем, кто в этом ещё
не силён. Большое спасибо.

Вопрос задал: Толков Геннадий Викторович (статус: Посетитель)
Вопрос отправлен: 17 февраля 2007, 23:07 (эксперты)
Всего ответов: 2

 

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

Вам достаточно будет написать такие обработчики:

//реагирует на движение мыши на Image1
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Image1.Visible:=false;
Image2.Visible:=true;
end;

//реагирует на движение мыши на форме
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if (x<Image2.Left) or (x>Image2.Left+Image2.Width) or
(y<Image2.Top) or (y>Image2.Top+Image2.Height)
then
begin
Image1.Visible:=true;
Image2.Visible:=false;
end;
end;

Еще я Вам рекомендую при создании формы сделать такие дополнительные настройки объектов:
procedure TForm1.FormCreate(Sender: TObject);
begin
Image1.AutoSize:=true;
Image2.AutoSize:=true;
Image2.Top:=Image1.Top;
Image2.Left:=Image1.Left;
Image2.Visible:=false;
end;

Good Luck!!!

Ответ отправил: Николай Рубан (статус: 7-ой класс)
Ответ отправлен: 17 февраля 2007, 23:45
Оценка за ответ: 5

2. Отвечает эксперт: Матвеев Игорь Владимирович

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

Бростьте заниматься ерундой!
Ваши сообщения CM_MOUSEENTER / CM_MOUSELEAVE.

При попадании курсора на контрол приходит CM_MOUSEENTER, при покидании - CM_MOUSELEAVE.

Например, TLabel (точнее TCustomLabel) ловит их и вызывает обработчики OnMouseEnter / OnMouseLeave. Посмотрите как это реализованно в StdCtrls.pas и добавьте для своего наследника TImage.

Дело 10 минут.

Ответ отправил: Матвеев Игорь Владимирович (статус: Студент)
Ответ отправлен: 19 февраля 2007, 06:11


Вопрос # 322

Здравствуйте. С кнопками у меня нечего не получилось, ну и
ладно. Я хочу задать вопрос, а с Image1 может так получится.
Я постараюсь правильно сформулировать вопрос.
На форму ложу Image1 и Image2, одну на другую.
Открываю в них две иконки в Image1 32*32, а в Image2 64*64.
Вопрос? Как мне сделать так, что бы наведя на иконку мышкой
(32*32 т.е Image1),появлялась иконка(64*64 т.е Image2),
а, убрав мышку с Image2(64*64), опять появлялась Image1(32*32), так
как это сделано с иконками в программах Talisman, Aston, StileXP,
ну и так далее.
А вот с окнами у меня подошёл один код, который отправил
Сергей Устинов. Спасибо ещё раз всем. Так как я начинающий,
поэтому информацию черпнул не плохую. Ну а если вернутся к окнам
то и здесь маленький нюанс, мне надо, что бы все окна сворачивались,
а моё (главной формы) не сворачивалось. Можно так сделать? И в
заключении ещё раз поблагодарю всех, кто помогает тем, кто в этом ещё
не силён. Большое спасибо.

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

 

1. Отвечает эксперт: Сергей Устинов

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

Пусть Image1 - маленькая картинка, Image2 - большая картинка.
Проще всего сделать так:
В обработчике формы OnMouseMove (FormMouseMove) пропишите:
Image2.Visible:=false;
Image1.Visible:=true;
а в обработчике Image1 OnMouseMove (Image1MouseMove)
Image1.Visible:=false;
Image2.Visible:=true;

Удачи!

Приложение:

Ответ отправил: Сергей Устинов (статус: 2-ой класс)
Ответ отправлен: 17 февраля 2007, 23:48
Оценка за ответ: 5

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

У TImage есть два хороших события - OnMouseEnter (мышь "зашла на комнонент") и OnMouseLeave ("покинула"). Если у вас делфи 7 и младше, то чтаем статью http://www.delphiworld.narod.ru/base/add_event_onmouseleave.html и пишем компонент с этими событиями.
Два. Запомните, что не всегда решение в лоб есть правильним и красивым. Иногда достаточно чуточку сменить идею решения и оно становиться простым и изящьним. В вашем случае, я обошёлся бы одним Image. Загрузил в него бОльшую картинку. Выставил свойство stretch = true. и задал бы размеры как для маленькой. Картинка автоматом отмаштабировалась. Теперь при наведении просто увеличиваем размеры.
А что бы вашу форму нельзя было свернуть, то нужно перехватить само события сворачивания и обработать самостоятельно. Делается это очень просто
Вначале в private части описания формы (под словом private) вставляем такой код
Private declarations}
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
Нажимаем Ctrl+Shift+C. Делфи згенерирует обработчик. Туда впишем следующее
if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0)
else
inherited;
Теперь при попытке свернуть или развернуть во весь экран оно будет пищать, но не будет выполнять. inherited нужен для того, что бы другие действия (например развернуть форму) были выполнены кодом по умолчанию. Без этой строки поведение будет странным (попробуйте в качесве эксперемента)

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 18 февраля 2007, 02:14
Оценка за ответ: 5


Вопрос # 323

Приветствую!!!Никто не сталкивался с иметационным моделированием в делфи???
EML (Events Modeling Language).помогите инфой или ссылками,хотелось бы найти библиотеку.

Вопрос задал: KilkaMS (статус: Посетитель)
Вопрос отправлен: 18 февраля 2007, 02:21 (эксперты)
Всего ответов: 1

 

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

пишем без ошибок "имитационным".
о самом моднлировании читаем здесь http://eml.ou.nl/eml-ou-nl.htm
а вот о библиотеках - не знаю. может вы напишете?

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 18 февраля 2007, 15:18
Оценка за ответ: 3


Вопрос # 325

Еще раз, здраствуйте господа программисты! Интересно, есть-ли для Delphi надстройка, компонент или что-то в этом роде, для написания програм под PocketPC(Windows Mobile 2003)?

Вопрос задал: Цопа Владимир Милузиевич (статус: Посетитель)
Вопрос отправлен: 18 февраля 2007, 16:27 (эксперты)
Всего ответов: 1; сообщений в мини-форуме вопроса: 3

 

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

Сама делфи не может генерить файлы под PocketPC. Но есть такое дело, как .NET. Под покеты майкрософт выпустила Compact FrameWork. Для Делфи (2006) толи есть патч, толи в следующей версии (2007, бетки уже есть) можно делать приложения

Ответ отправил: Вадим К (статус: Магистр)
Ответ отправлен: 18 февраля 2007, 16:48
Оценка за ответ: 3
Комментарий: Спасибо! Знать-бы как ".NET" этим пользоваться?!


Обучение Delphi

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

13. Ввод и вывод
14. Выбор (ветвления)
15. Подводим промежуточный итог

Циклы - общее понятие; цикл с параметром

Автор:
© Ерёмин А.А., 2007
Повторять следует только неповторимое!
Номер урока:
16
 

Введение

Запись последовательных команд не всегда может быть эффективным способом достижения поставленной цели. Очень часто в программе требуется выполнить одну и ту же последовательность действий несколько раз. Например, требуется вывести в текстовое поле (TMemo) числа от 1 до 100. Что делать в этом случае? Писать 100 строк кода? Конечно нет, это было бы просто глупо! Примеров можно привести множество. Причём во многих случаях число повторений может быть заранее неизвестно - в этом случае записать фиксированный набор команд просто невозможно.
На помощь придут циклы. Цикл - это специальная конструкция языка, позволяющая запрограммировать многократное выполнение определённого блока команд. Каждый "проход" цикла называется итерацией. В языке Pascal существует три типа циклов - цикл с параметром (цикл по переменной), цикл с предусловием и цикл с постусловием. В данном уроке мы познакомимся с циклом по переменной.

Цикл с параметром

Цикл с параметром (другое его название - цикл по переменной) позволяет выполнить набор команд фиксированное число раз, т.е. число итераций должно быть известно до начала выполнения цикла. Особенностью данного цикла является то, что заводится специальная переменная-счётчик, которая последовательно проходит указанный диапазон значений. Значение этой переменной может быть использовано в блоке кода, находящемся в цикле.

Цикл с параметром описывается зарезервированным словом FOR (англ. "для"). Общий вид конструкции цикла FOR:

FOR переменная-счётчик := начальное_значение [TO / DOWNTO] конечное_значение DO
    {Действия}

Переменная-счётчик - объявленная выше переменная перечислимого типа (в большинстве случаев - число).

Начальное значение и конечное значение - границы диапазона, который последовательно "пробежит" переменная-счётчик. Значения, естественно, того же типа данных, что и переменная-счётчик.

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

В качестве действий указывается какая-либо команда, либо набор команд. Если команд несколько, их, как обычно, следует заключать в блок BEGIN .. END.

Пример №1

Рассмотрим пример, речь о котором шла в начале статьи, только немного усложним его - будем выводить не только числа от 1 до 100, но и их квадраты.

Итак, мы заранее знаем, что нам следует выполнить одну и ту же команду - добавление строки в Memo, 100 раз. Запрограммируем это с помощью цикла FOR. Для начала следует разместить на форме TMemo (Memo1). Выполнение команд логичнее всего "повесить" на нажатие кнопки. Для добавления строк в TMemo следует воспользоваться методом Add его свойства Lines. Lines - это набор всех строк TMemo, а метод Add позволяет добавить указанную строку. Перед выполнением цикла содержимое Memo очищается.

Программа, выводящая квадраты чисел от 1 до 100
procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
  Memo1.Lines.Clear;
  for i := 1 to 100 do  
    Memo1.Lines.Add(IntToStr(i)+': '+IntToStr(Sqr(i)))
end;

Разберём, что здесь происходит: мы заводим переменную i (Integer, целое число) и указываем её как счётчик для цикла. Поскольку нам нужно вывести числа от 1 до 100, указываем соответствующий диапазон. Команда - добавление строки в Memo, содержащей текущее число и его квадрат. Преобразование типов (в данном случае - чисел в строки) обязательно. Как это будет работать: сначала переменной i будет присвоено значение 1, после чего выполнится указанная команда, т.е. в Memo добавится строка "1: 1", далее i станет равным 2 и снова команда повторится. Так произойдёт 100 раз - в результате в Memo и окажется 100 строк.

Замечание

Одна из часто встречающихся ошибок - использование значения переменной-счётчика после завершена цикла. После выполнения цикла значение переменной-счётчика не определено! В данном случае после завершения цикла значение i не будет 100, хотя по случайности оно может быть. Если Вы хотите использовать значение переменной далее, присвойте ей это значение явным образом.

Вложенные циклы

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

Никаких специальных конструкций для вложенных циклов нет. Всё работает точно также. Переменные-счётчики циклов, как правило, называют буквами I, J, K, хотя название, конечно, может быть любое.

Пример №2

Простейший пример применения вложенного цикла - вывод таблицы умножения. Для начала продумаем алгоритм: для вывода таблицы для одного конкретного числа (например, для 5), нужно создать цикл, который пройдёт значения от 1 до 9 и выведет произведение числа 5 на каждое из этих чисел. А чтобы вывести таблицу для самих чисел от 1 до 9, нужен ещё один такой же цикл.

Программа, выводящая таблицу умножения
procedure TForm1.Button1Click(Sender: TObject);
var i,j: Integer;
begin
  Memo1.Lines.Clear;
  for i := 1 to 9 do
    for j := 1 to 9 do
      Memo1.Lines.Add(IntToStr(i)+' x '+IntToStr(j)+' = '+IntToStr(i*j))
end;

Прерывание и продолжение цикла

Примечание: то, о чём пойдёт речь далее, применимо не только к циклу по переменной, но и к циклам с пред- и постусловием.

Не всегда выполнение фиксированного числа итераций приводит к нужному результату. Иногда в процессе выполнения могут возникнуть ситуации, когда цикл логично было бы завершить, не выполняя его до конца, т.е. нужно просто исключить все дальнейшие итерации. Такая возможность существует - для этого необходимо вызвать команду BREAK. Данная команда завершает цикл, который выполняется в данный момент, и продолжает выполнение программы. При этом текущая итерация не выполняется до конца - прерывание происходит именно в той строке, где указана команда Break.
Замечание: если цикл, выполнение которого прерывается командой Break, вложен в другой цикл, то "внешний" цикл продолжит своё выполнение, т.е. команда Break останавливает только один цикл, а не все имеющиеся.
Завершение цикла - экстренный метод. Иногда же нужно просто пропустить текущую итерацию и перейти к следующей. Вручную это можно сделать, заключив все команды в блок условного оператора, однако такой способен неудобен и только загромождает код. Именно поэтому существует команда продолжения цикла и называется она совершенно логично - CONTINUE. Эта команда "заставляет" цикл тут же перейти к следующей интерации, не продолжая выполнение текущей.

Пример №3

Данный пример призван продемонстрировать применение команды Break.
Задача. Определить, есть ли среди букв английского алфавита (A - Z, в верхнем регистре) такие символы, коды которых обладают следующим свойством: квадрат кода символа больше числа 5000. Если такие символы существуют, указать первый из них согласно алфавитному порядку.

Во-первых, следует определиться с циклом. Смвольный тип (Char) - перечислимый, значит его можно использовать для переменной-счётчика цикла For. Во-вторых, для определения кода символа служит функция Ord(). В-третьих, нам не обязательно просматривать абсолютно все символы - если будет найден хотя бы один, значит требуемое условие выполнено и этот символ мы должны вывести как результат работы. Просматривать остальные символы не требуется.

Опишем цикл, который последовательно пройдёт все символы от A до Z. Коды символов упорядочены согласно следованию соответстующих букв в алфавите, поэтому "пробег" произойдёт точно по алфавиту, для этого в коде не требуется дополнительно что-либо писать. Код будет приблизительно таким:

procedure TForm1.Button1Click(Sender: TObject);
var c: Char;
begin
  for c := 'A' to 'Z' do
    if Sqr(Ord(c)) > 5000 then
    begin
      ShowMessage('Символ: '+c+' (код: '+IntToStr(Ord(c))+', квадрат: '+IntToStr(Sqr(Ord(c)))+')');
      Break
    end
end;

Как сработает этот цикл: сначала будет взят символ "A", будет проверен код этого символа, после этого будет взят символ "B", проверен его код и т.д. Когда условие выполнится (это будет на символе "G"), будет выведено сообщение с результатом, но после этого цикл не продолжится - он тут же завершится. Мы уже нашли искомый символ, у нас есть результат, - зачем же тратить время на проверку остальных символов? В данном случае задержка по времени будет практически незаметна, ведь в алфавите всего 26 символов. Но что будет, если обрабатывать несколько тысяч записей?

Цикл с шагом

Цикл с шагом позволяет указать шаг прохода счётчиком указанного диапазона. Например, в случае, когда требуется пройти все числа от 0 до 1000, которые делятся на 10, шагом будет число 10, а границами диапазона - 0 и 1000. Цикл при этом будет выполняться таким образом: сначала будет взято первое число и выполнена соответствующая итерация, затем к счётчику будет прибавлена не 1, как обычно, а шаг, т.е. 10 - следующая итерация выполнится при значении счётчика, равном 10, далее - 20, 30 и т.д.
Однако есть одна проблема - в Pascal возможности задавать шаг... нет! Да, так уж сложилось, что этой конструкции не предусмотрено. В некоторых языках программирования она есть (например, в Basic), в некоторых - нет.

Однако не составляет труда написать небольшую надстройку над обычным циклом, которая позволит это сделать. Этот пример также продемонстирует использование команды Continue.

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

procedure TForm1.Button1Click(Sender: TObject);
var i,First,Last,Step: Integer;
begin
  First:=3;
  Last:=100;
  Step:=10;
  Memo1.Lines.Clear;
  for i := First to Last do
    if ((i - First) mod Step) <> 0 then
      Continue
    else
      Memo1.Lines.Add(IntToStr(i))
end;

Для тех, кто забыл: оператор mod выполняет деление с остатком. Разберёмся, как работает данный цикл: переменная-счётчик проходит значения указанного диапазона (в примере - от 3 до 100). Для проверки, является ли итерация "попадающей" под шаг, выполняется проверка, делится ли пройденное число единиц нацело на указанный шаг. В данном примере после 3 "попадание" будет на числе 13, т.к. 13 - 3 = 10 = Шаг * 1. Далее - 23, 33 и т.д. При этом первое значение диапазона всегда будет попадать в шаг, какое бы оно ни было, а последнее - не всегда (в данном случае 100 не попадёт).

Блок команд для выполнения в цикле в данном случае указывается после else.

Заключение

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


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

Статьи

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

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

Преобразование текста с помощью регулярных выражений
(или о том, как сделать HTML от MS Word меньше)

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

Задача

Я пишу эти статьи в MS Word по той причине, что он (Word) проверяет орфографию и грамматику. Но у него есть один существенный недостаток. Статьи в Интернет публикуются в формате HTML и, хотя MS Word и умеет конвертировать, но делает это отвратительно. Страничка, которая могла бы занимать 3-4 килобайта, имеет вес 20-30. Самое обидное, что всё можно вычистить "ручками", а внешний вид страницы и не изменится.

Чистить текст будем с помощью давно известного метода – регулярных выражений.

Инструментарий

Для того, что бы продолжить работу нам нужно:

- Delphi 7, 2005, 2006, 2007 версии. На младших версиях должно работать, но не гарантирую;
- Скачать библиотеку для регулярных выражений с сайта http://www.regexpstudio.com/RU/TRegExpr/TRegExpr.html. Если точнее, то http://www.regexpstudio.com/Downloads/regexpr_RU.zip и загрузить (это опционально) утилиту для тестирования регулярных выражений http://www.regexpstudio.com/RU/RegExpStudio.html. Всё это также можно взять в архиве к статье.
- Ну и напиток по вкусу :-)

Написание кода

Рабочий класс

Запускаем Delphi и сразу добавляем ещё один юнит (File –> New -> Unit). Сохраняем проект. "Unit2" я сохраняю под именем "ClassTextTransf.pas". "Unit1" как "Main.pas". А сам проект как "HTMLClean.dpr". Теперь из архива извлечем файл "Source\ RegExpr.pas" и скопируем его в папку к нашему проекту.

Возвращаемся к файлу ClassTextTransf. После строки interface подключаем нужные нам файлы – uses SysUtils, Classes, RegExpr;

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

type
 TTextTransf = class
 private
 FText:string;
 FFileName:string;
 public
 constructor Create(fileName:string);
 destructor Destroy; override;
 procedure Load;
 procedure Save;
 procedure Erase(Expr: string);
 end;

Теперь нажимаем Ctrl+Shift+C и Delphi допишет заготовки для кода.
Некоторые комментарии. FText – переменная, которая хранит собственно сам текст. Load и Save загружает текст из файла и соответственно сохраняет. Имя файла указывается в конструкторе. Рабочий метод у нас Erase. Он получает строку - регулярное выражение, чтобы знать, что заменять на пустую строку, мы ведь удаляем "лишний текст". Его реализацию мы и рассмотрим. Все остальные методы просты и их реализацию можно подсмотреть в прилагаемом архиве.

procedure TTextTransf.Erase(Expr: string);
 var r:TRegExpr;
begin
 r:=TRegExpr.Create;
 try
 r.Expression := Expr;
 FText := r.Replace(FText,'',false);
 finally
 r.free;
 end;
end;

Рассмотрим этот код подробнее. В начале мы создаём экземпляр класса (т.е. объект), который умеет обрабатывать регулярные выражения. Дальше передаём само регулярное выражение и вызываем функцию Replace. Её параметры следующие: первый – строка, в которой мы будем удалять текст, второй – на какой текст будем заменять. Так как мы удаляем, то у нас это пустая строка. Третий параметр пока оставляем False. Он расширяет функциональность и нам пока не нужен. Далее записываем полученный текст назад в нашу переменную. Как составлять регулярные выражения – разберёмся позже.

Интерфейс

Теперь пишем интерфейсный код – юнит main.pas. Для начала набросаем компоненты. У меня получилось так:

Интерфейс программы

Код кнопки "Обзор…" выглядит просто:

procedure TForm1.btnBrowseClick(Sender: TObject);
begin
 if not OpenDialog1.Execute then exit;
 edit1.Text := OpenDialog1.FileName;
end;

Тут пока ничего необычного.

Теперь для кнопки "Обработать". Сначала нужно подключить наш юнит с классом. Это просто. Меню File – Use unit и выбираем наш юнит (он там единственный).

И пишем обработчик для кнопки:

procedure TForm1.btnWorkClick(Sender: TObject);
 var tt:TTextTransf;
begin
 tt:=TTextTransf.Create(Edit1.Text);
 try
 tt.Load;
//здесь мы будем вставлять код обработки
 tt.Save;
 finally
 tt.free;
 end;
end;

Как видно – ничего сложного. Создали объект, загрузили текст и сохранили результат. Код обработки, который собственно выполняет основную роль, пока опущен.

Основы синтаксиса регулярных выражений

Итак, что же надо удалять? В дальнейшем повествовании я предполагаю, что вы знакомы с базовым синтаксисом HTML. Создадим в MSWord текст на несколько страниц (я экспериментировал на данной статье) и сохраним в html формате. Также сделайте резервную копию или немного модифицируqnt метод Save, чтобы он не удалял старый файл. Теперь откроем сам сохранённый файл. Как видно, MS Word очень любит вставлять тег span. Иногда по существу, иногда по факту переключения раскладки, а иногда как ему в голову придёт. Если удалить их, ни один браузер ничего не заметит (ну не совсем все, но детальнее разбираться – это уже другая история). У нас есть открывающий тег и закрывающий. С последним всё понятно – он одинаковый и можно было бы удалить и обычным поиском-заменой. В этом случае регулярное выражение будет простое - <\/span>. Только перед слешем я поставил обратный слеш. Дело в том, что слеш является спецсимволом и чтобы всё работало, символы надо "экранировать". К зарезервированн ым символам также относятся квадратные скобки, точка, плюс, крышка "^" и некоторые другие. Проверим наш код. Вставим на место комментария строку tt.Erase('<\/span>');

Запускаем, обрабатываем. Потом сравниваем. Должно работать.

Теперь сложнее. Надо удалить открывающий тег. Здесь могут быть различные варианты. Но для начала надо попытаться описать словами. У меня получается где-то так: "вначале угловая скобка, потом текст span потом любые символы кроме закрывающей скобки и собственно сама закрывающая скобка». На языке регулярных выражений это выглядит так:

<span[^>]*>

Конструкция [^>] означает любой символ кроме угловой закрывающей скобки. Если написать [abc], то это будет любой символ a, b или c. Конструкция вида [a-z] – какая-либо строчная буква латинского алфавита. Конструкция вида [^0-9] – все символы, кроме цифр.

Звёздочка (*) означает, что таких символов может быть 0 или больше. Если поставить +, то это будет означать, что должен быть хотя бы один символ.

Если теперь добавить ещё одну строку в наш код, то html очищается на 25%, а это уже неплохо!

Модернизация

Следующий ход – заменить конструкции вида "<p class=MsoNormal>" на просто "<p>". Наш класс не умеет делать такую замену. Но мы добавим ещё один метод. Назовём его Replace(FromText, ToText: string);

Если присмотреться, то можно заметить, что наш предыдущий метод является частным случаем этого. Erase(s) эквивалентно Replace(s,''). Поэтому добавим новый метод, скопируем туда код с метода Erase и поправим его. То-есть у нас получится так:

procedure TTextTransf.Replace(FromText, ToText: string);
 var r:TRegExpr;
begin
 r:=TRegExpr.Create;
 try
 r.Expression := FromText;
 FText := r.Replace(FText,ToText,false);
 finally
 r.free;
 end;
end;
 
procedure TTextTransf.Erase(Expr: string);
begin
 Replace(Expr,'');
end;

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

Теперь код замены для нашей строки будет выглядеть просто:

tt.Replace('<p\sclass=MsoNormal>','<p>');

Здесь только одна особенность - пробел нужно записать в виде \s.

Продолжаем очистку

MS Word любит вставлять комментарии в текст, чтобы потом ему было "легче". Но браузеру эти комментарии ни к чему. Казалось бы, всё просто – берём регулярное выражение "<!--.+-->". Но попробуйте применить его - что-то много удалилось... И действительно, открыв, вы увидите, что текста удалилось много. Дело в том, что по умолчанию регулярные выражения работают в "жадном режиме". То-есть, когда под маску попадает несколько вариантов, то они пытаются захватить "побольше". Нам это только мешает, поэтому мы отключим. Это всего одна строка.

tt.Erase('<![if !vml]>');
tt.Erase('<![endif]>');

Эти строки удалят что-то не совсем мне понятное, но мешающее нормальному отображению изображений в браузере. Самое интересное, что они мешают только Internet Explorer'у. Остальным браузерам этот код - не помеха.

Посмотрим теперь на странный текст после тега html в самом верху. Уж очень много там информации. Она нужна, чтобы у html документов, созданных Word'ом отображалась немного другая иконка и именно Word вызывался при попытке редактирования. Нам это не нужно. Здесь код прост:

tt.Replace('<html[^>]*>','<html>');
tt.Erase('<meta\sname\=[^>]*>');

Украшения

Теперь добавим немного "красоты". После наших удалений осталось множество пустых строк. Удалим их. Для этого будем использовать выражение Replace('\n\s*\n',''); В классе я оформил это в виде дополнительного метода.

Выводы

После всех манипуляций мне удалось вычистить текст более чем в 2 раза. В нём, конечно, есть ещё место для ручной обработки, но в целом очень неплохо. В коде вы найдете несколько дополнительных строк для оценки производительности.

Несомненным плюсом изучения регулярных выражений будет то, что они используются во многих других языках, таких как Perl, PHP. Эта библиотека совместима с Perl'овской реализацией и поэтому литературы в Интернете предостаточно.

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

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

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

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

Название
Описание
Раздел
Объём
Ссылки
MiTeC System Information Component Suite
MiTeC System Information Component Suite (MSICS) - это набор компонент для Delphi 5, 6, 7, 2005 (BDS3) и 2006(BDS4), предоставляющий огромное количество информации об операционной системе и компьютере.
Компоненты написаны на чистом VCL и Ассемблере - никаких дополнительных модулей не требуется.
1.37 Мб
WMA File
Класс TWMAfile предназначен для извлечения информации из звуковых файлов формата WMA.
Информация, которую можно получить:
- информация о файле: объём файла, режим звуковых каналов, длительность, битрейт;
- информация из тегов WMA: название, исполнитель, альбом, трек, год, жанр, комментарии.
9 Кб
OGGVorbis File
Класс TOggVorbis предназначен для извлечения информации из звуковых файлов формата OGG.
Информация, которую можно получить:
- информация о файле: объём файла, режим звуковых каналов, длительность, битрейт;
- информация из тегов: название, исполнитель, альбом, трек, год, жанр, комментарии, производитель.
10 Кб
Квадрикс
Вариация на тему тетриса. Большое поле и нестандартные фигуры, включая такие, у элементов которых нет точек соприкосновения.
167 Кб
Пятнашки
Классическая игра "Пятнашки".
313 Кб
 
Всего новых файлов: 5  
1.87 Мб
 
 

Юмор

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

Чайники веб-дизайна (часть I)

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

Чайники вредны и опасны. Чайники - заклятые враги всего грамотного и профессионального. Чайники дезориентируют и сбивают с толку. Они путают, дезинформируют и перевирают. Они заразнее гриппа: начинающий веб-дизайнер, столкнувшись с чайником, почти со стопроцентной вероятностью сам превратится в чайника. Заразны не только сами чайники, но и отходы их жизнедеятельности, проще говоря - экскременты, которые они бесстыдно разбрасывают по Сети, называя «страничками» и даже «сайтами». Медицине известно множество случаев, когда начинающий веб-дизайнер, по неосторожности столкнувшись с такими фекалиями, испытывал непреодолимое желание скопировать поведение испражнившегося чайника.

Как же отличить чайника, притаившегося в темном закоулке халявного хостинга? Как избежать роковой встречи с ним и опасной заразы?

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

Чайник ничего не знает и ничего не умеет. Иногда он имитирует какие-то навыки, однако при этом всего лишь подражает каким-то образцам: чаще всего - другим чайникам. Выявить чайника можно, задавая ему вопросы о смысле тех или иных его действий. Почему заголовок сделан синим цветом на бежевом фоне? Почему маркеры круглые, а не, например, квадратные? Почему ширина таблицы 620 пикселей, а не 610 или 630? Чайник никогда не сможет ответить на подобные вопросы, потому что никогда не задумывается над собственными действиями. В лучшем случае он сошлется на то, что «так все делают», или на то, что «знакомый NN сделал так же, мне понравилось и захотелось повторить».

Чайник не способен чему-либо учиться. Чайник обладает только одним механизмом реакции на критику: агрессией. Ему бесполезно объяснять, какие недостатки есть в его работе - он может понять только то, что его работа вам не понравилась, а это является для него безусловным поводом для агрессии. Hе рекомендуется критиковать чайника, находящегося без намордника и не привязанного к какому-либо устойчивому предмету.

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

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

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

Вот один из наиболее показательных случаев. Чайник, использовавший в работе тэги заголовков <H1> и <H2> (вместо тэга <FONT>, которым обычно пользуются чайники), получил от экспериментатора солидную подкормку. Уже в следующей работе чайник использовал четыре уровня заголовков, а еще в одной - двенадцать, употребив для этого тэги <H1>-<H12>, хотя и без всякой связи со структурой опытного документа.

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

Продолжение следует...

:))

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




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


В избранное