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

Delphi - проблемы и решения

  Все выпуски  

Проблемы и решения в Delphi #25


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

Проблемы и решения в Delphi - выпуск 25 от 16.08.2001.


Чем бы детя не тешилось...
лишь бы девушки не программировали...


ВСЕ ВОПРОСЫ СПРОСИТЬ ПРЕДЛОЖИТЬ АРХИВЫ СКОЛЬКО НАС


Доброго Вам времени суток уважаемый читатель.
Старо как мир - не сажайте женщин за руль и пускайте молоденьких девушек
программировать. В нашем отделе женщин - программистов скоро будет столько же
сколько и мужчин! А как вы думаете - кто пишет программы?
Ладно, отвлекся...прошу прощения, если кого обидел.

Сегодня в выпуске :
~~~~~~~~~~~~~~~~~~~
1. Метки и ... метки.
2. Очередные вопросы.
3. Отвеченные вопросы.
4. Ищу подельника.
~~~~~~~~~~~~~~~~~~~


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

Думаю, что большенство из Вас уже давно не нуждаются в описании компонент
'Label' и 'StaticText', тогда это для совсем начинающих или, для не совсем
внимательных.
Обе эти компоненты служат для размещения текста на объекте(не забыли, что
многие компоненты позволяют размещать на себе другие компоненты). Подчеркну
основные совпадающие свойства и той, и другой компоненты. Это конечно же -
'Align','Alignment','Anchors', служащие для размещения и привязки компонент
(помните 23-й выпуск рассылочки),'Color' и 'Font', для установки параметров
фона и самого текста.
Довольно интересное свойство - 'Constraints'. Позволяет ограничивать размеры
вашей компоненты. Т.е. если вы, в процессе работы размещаете компоненту, в
разных местах и с разными размерами, то это свойство позволит оградить себя
от случайного перебора со значениями. Ну, 'Visible' наверное и так понятно -
позволяет скрыть либо показать компоненту.
Собственно из общих свойств интерес представляет еще только - 'Hint'. То, что
Вы в нем напишите будет показано при наведении на компоненту мышкой(всплывающие
подсказки).
Теперь различия.
У компоненты 'StaticText' есть свойство 'BorderStyle', где можно задать вид
вашей компоненты. Это - 'sbsNone'(обычный вид), 'sbsSingle'(с рамкой),
'sbsSunken'(вдавленный вид). Еще в свойстве 'Caption' компоненты 'Label'
можно сразу наколачивать несколько строк, а у 'StaticText' только одну строку.
И последнее свойство 'WordWrap'. Оно задает будет ли осуществлен автоматический
перенос строк в компоненте 'Label'.

А вообще, я бы предпочел иметь одну компоненту объединяющую в себе недостающие
свойства обоих.


2. Очередные вопросы.
---------------------


Вопрос 393:

От: Oleg Semiglazov

Подскажите пожалуйста, где можно найти описание и
примеры использования компонента TreeView? Помогите учащему Делфи,
плиз! :))


Ответить.

Ответ 1:


Вопрос 394:

От: Шкода Сергей Иванович

Вот возникли некоторые трудности в Дельфях:
Имеется база Exampl.dbf (dBase IV)
Tip Name
1 aaa
2 bbb
1 ccc
1 ddd
2 eee
Нужно создать отчет (QReport) следующего вида:
1
aaa
ccc
ddd
2
bbb
eee
Далаю я так:
1. Создаю SQL1 (select distinct tip from exampl order by tip)
2. Создаю DataSource (DS1.DataSet = SQL1)
3. Создаю SQL2 (select * from exampl where tip=:tip
SQL2.datasource = DS1)
При просмотре (PreView) отчет такой как нужен,
в программе выдает ошибку "SQL1 поле TIP не найдено"
В чем проблема.


Ответить.

Ответ 1:


Вопрос 395:

От: Ivan

Почему программы, написанные БЕЗ формы грузятся по меньшей мере 10
секунд,
даже если размер таковой не превышает 12 kb? Можно ли как-нибудь
"убыстрить"
программу? И старый вопрос: не знаю, может этот вопрос Вам покажется
простым
, но всё-таки: почему при работе с TButton на моей форме я могу поменять
её
регион, на эллипс например, но не могу поменять регион кнопки в винде,
зная
про неё всё(регион, width, handle и т.д.).



Ответить.

Ответ 1:


Вопрос 396:

От: ivc_dima

выполняю команду
MySheet.Cells.Item[11].CopyFromRecordset(ADODataSet1.recordset,EmptyPara
m,EmptyParam);

Под 2000 офисом работает нормально. Под 97 выдает Error:"Интерфейс не
поддерживается". В чем проблема? Помогите пожалуйста. А то ручками
выводить таблицу очень долго по времени.


Ответить.

Ответ 1:


Вопрос 397:

От: Нестеренко Кирилл



Открываю исходник а мне фигню пишут:
Error creating form: Invalid stream format.
Что делать подскажите...


Ответить.

Ответ 1:


Вопрос 398:

От: Врублевский Евгений Геннадьевич

Как сделать форму, которая бы отображалась на фоне рабочего
стола? Не откажусь и от версии на C++, но лучше на Delphi.


Ответить.

Ответ 1:


Вопрос 399:

От: xaoz

Вопрос такой, кто знает как работать с TField.DefaultExpression?
Ведь очень хорошая штука, а в процессе выполнения программы не работает.
Приходится открывать, и закрывать таблицу, а это согласитесь долго. И
еще
заметил глюк, TField.DefaultExpression с датой не хочет работать в
WinME, тоже
самое пишешь в Win98 все Ok. Буду благодарен любым ответам и
предложениям как
сделать красиво без или надеюсь с TField.DefaultExpression.



Ответить.

Ответ 1:


Вопрос 400:

От: Ivan


У меня такой вопрос(серьёзный): можно ли, написав свою функцию,
которая
представляет обычный цикл, каким-либо образом подключить её к delphi(
может
быть записать её в windows.pas или куда нибудь в иное место) и вызывать
её
как функцию без параметров, но только у себя разумеется.
Например(пример без формы).

program aCOOLa1_54;
uses
Windows, Messages;
var......;
function......!ЗДЕСЬ я хочу создать и назвать функцию!
begin
......
end.

Надеюсь идея понятна. Моя функция, которую я хотел бы сделать,
состоит из
цикла, из которого нельзя выйти в запущенном состоянии, кроме как по
ctrl+alt+delete. Т.е. ничего сверхъестественного там не происходит.
Одним словом как сделать и подключить функцию к delphi (!!! для
уменьшения
кода в программе, не использующей форму!!!)


Ответить.

Ответ 1:


Вопрос 401:

От: fade

В Паскале была функция readkey, которая опредеяла нажатую клавишу.
Есть ли какойто ее аналог в делфи?


Ответить.

Ответ 1:


Вопрос 402:

От: Andrei

У меня вопрос как в Delphi5 отключить мышь и клавиатуру во
всём Windows, (но только чтобы потом можно их включить)?
Говорят, что можно это сделать с помощью Windows API, но я не знаю как
пользоваться Windows API. Если вам не трудно расскажите, как вызывать
функции Windows API и где можно достать описания этих функции
(желательно на
русском языке).


Ответить.

Ответ 1:


Вопрос 403:

От: Сергей Красовский

Каков комплект поставки CORBA клиента? То есть какие dll надо поставлять
с исполняемым файлом?


Ответить.

Ответ 1:


Вопрос 404:

От: Karpova Elena

Хотелось бы по двойному щелчку на имени файла в компоненте FileListBox
иметь возможность автоматически открыть его в нужном приложении, как мы
делаем это в любом из коммандеров(Norton, Windows). Насколько реально
это осуществить? И, если не совсем утопично, то как?

Ответить.

Ответ 1:


Вопрос 405:

От: Ефремов Александр


как
убрать программу из Alt+Ctrl+Del. Как убрать все окно Alt+Ctrl+Del я
знаю, но это все же не то ! Наверно программу надо присоединить к какому
нибудь процессу, уже запущенному в системе, но как это сделать ? У меня
нет документации по WinAPI, скоро меня это окончательно доканает. Может
кто-нибудь (если его конечно не затруднит) приведет несколько примеров
работы с ПРОЦЕССАМИ с описанием параметров функций - я буду очень
благодарен. Помогите пожалуйста !



Ответить.

Ответ 1:


Вопрос 406:

От: Zelenin_ve@mail.ru

Скачал давеча FIB Plus для Делфей, утановил вроде все работает, но
есть одна проблема. В компонентах, которые я использовал до этого, для
создания исочиков данных использовались свойства MasterSource и
MasterFiels в FIB Plus есть свойство DataSource которое позволяет
связывать источники, но я не нашел свойсва которое указывает на поле
по которому происходит связь. К тому же в FIB очень много свойств
которых нет в стандартных компанентах для работы с InterBase не
подскажите где можно взять FAQ или Help на русском языке по FIB PLUS.
Если у кого есть то мыльните пожалуйста на GreenPeace@mail.kz :



Ответить.

Ответ 1:


Вопрос 407:

От: Oleg Martynov

Не могли бы вы просветить меня по следующему поводу:
В Windows с установленным IE 4.0 и выше существует компонент Microsoft
Windows Common Controls, файл MSCOMCTL.OCX. В нём OCX элементы
управления, в
частности, StatusBar. StatusBar весьма неплох, поддерживает вывод даты,
времени, состояния клавиш (Ins, Caps, Scroll, Num) и всё прочее, что
полагается строке состояния - есть смысл воспользоваться именно им, а не
городить что-то своё (или чужое:-). Проблема в следующем. Внизу слева
этого
бара должна рисоваться "цеплялка" SizeGrip для изменения размера окна (в
стандартом компоненте Delphi TStatusBar - свойство SizeGrip). У OCX
элемента
подобного свойства нет! Как я понял из документации, SizeGrip должен
появиться автоматически. В Visual Basic всё работает именно так, как
описано. При попытке импорта в Delphi или C++ Builder Grip не
появляется. Та
же картина при попытке воспользоваться им в Visual C++ и в ActiveX
Control
Test Container. В MSDN ничего найти не удалось - возможно, плохо искал.
Но
старался.
Буду благодарен за ваши соображения - в чём проблема? Что за
особенность
работы с этим ОСХ у Visual Basic? Знатоки OCX, подскажите, где (про что)
прочитать (желателько в MSDN или документации)? А может, что-то совсем
простое?



Ответить.

Ответ 1:


Вопрос 408:

От: Ефремов Александр


:Не подскажет ли кто, существуют ли в Delphi зарезервированные имена
(псевдонимы) для таких папок как Windows, Program files и т. п. Если
такие константы есть, подскажите, пожалуйста, в каком файле они
объявлены. Может быть существуют функции для получения псевдонимов или
их можно найти где-нибудь в реестре ?


Ответить.

Ответ 1:


Вопрос 409:

От: Lamer

В последнем выпуске прочел впечатления от Дельфи6. Я тоже ее себе поставил
и мне понравилась работа с Action-ами и особенно Action-bar-ы.
Есть ли способ сохранять состояния Action-ов не в файл
(как это делает ActionManager), а в соответвтующую ветку реестра (HKCU\...)?


Ответить.

Ответ 1:



3. Отвеченные вопросы.
----------------------


Вопрос 256:

От: Ернар Шамбаев

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

Какие компоненты являются наилучшими для написания
сокет-приложений (постоянный прием/отправка файлов)
для локальной сети и для модемных соединений?
Я пробовал с компонентами NetMasters (что на странице
FastNet), однако у NMUDP, похоже, ограничение на
буфер. Слышал, что в шестую версию Delphi включены
компоненты Indy. Насколько хороши они? Еще вроде бы
пользуются успехом сетевые компоненты какого-то
француза (Piette, хотя могу ошибиться).


Ответить.

Ответ 1:
Человек, зайди на http://users.swing.be/francois.piette/indexuk.htm это сайтик того самого F.PIETTE где на халяву
можно закачать InternetComponentStyle (с кучей компонент для дельфов(FTPsrv\client SMTP, pop3
MIMEenc\decode ... etc))


Вопрос 257:

От: Ернар Шамбаев

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

Одно из полей моей базы данных - BLOB.
Периодически при редактировании этого поля
в сетевом варианте вылетает ошибка
"Blob has been modified". Приходится
завершать работу приложений и паковать
БД. Только в результате этих действий
возможно продолжение нормальной работы.
Объясните, пожалуйста, в чем причина ошибки?


Ответить.

Ответ 1:
Обычно просто corrupted table в результате кэширования
BLOB - поставьте на onPost процедурку физического
завершения всех транзакций с базой:

DBISaveChanges(mytable.handle);

и количество ошибок снизится на порядок
Ответ 2:
Скорее всего надо блокировать запись которую в данный момент редактируешь
делается это командой LOCK ... есть одно только НО ... когда задаешь вопрос
про базы данных КРАЙНЕ желательно писать КАКАЯ у тебя база ... их ведь много
бывает ...
P.S. Ах, да совсем забыл ... причина ошибки в том что пока один этот блоб
редактировал другой его открыл и тоже редактировал в результате тебе ошибка
"Не могу продолжать так тот его тоже исправил":'


Вопрос 258:

От: Ернар Шамбаев

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

Скажите, пожалуйста, что означает сообщение об ошибке
"Index read only"? Она возникает у меня в приложении БД
"главный-подчиненный" при попытке добавить запись
в подчиненную таблицу.


Ответить.

Ответ 1:
Со своим вопросом от 29.04
(Скажите, пожалуйста, что означает сообщение об ошибке
"Index read only"? Она возникает у меня в приложении БД
"главный-подчиненный" при попытке добавить запись
в подчиненную таблицу) сам разобрался.

Оказывается, достаточно добавить подчиненной таблице
первичный индекс, а вторичный индекс этой же таблицы
сделать Maintained.


Вопрос 259:

От: Алексей Малиновский


Господа, подскажите как сделать форму типа формы Object Inspector с
функцией Stay on top?
Т.е. мне необходимо сделать висячую форму (примечание), которая бы
находилась на переднем плане, но фокус оставался бы главной формы...

Помогите пожалуйста, заранее спасибо.

С уважением, Алексей.


Ответить.

Ответ 1:
Данный код делает форму поверх всех остальных окон (не знаю то ты искал или нет)

SetWindowPos(Handle,HWND_TOPMOST,Left,Top,Width,Height, SWP_NOACTIVATE or SWP_NOMOVE or
SWP_NOSIZE);
Ответ 2:
Formstyle="fsStayOnTop"
Borderstyle="bsSizeToolWin" (чтобы окно могло изменять размер)
Borderstyle="bsToolWindow" (тоже самое только размер не меняется)


Вопрос 260:

От: Virus

Здравствуйте!
Как можно сделать "обрезание" формы по рисунку. То есть, я вставил на
форму рисунок (например кружок), и мне надо, что бы формы не было (что
бы она была, но только в форме кружка, то есть моего рисунка), а не
квадратная (обычная)?????? ЗАРАНИЕ БОЛЬШОЕ СПАСИБО!!!!!!


Ответить.

Ответ 1:
Компоненты 1stClass(component ImageForm)!
Ответ 2:
Чтобы сделать форму непрямоугольной, надо для окна назначить регион.

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

...
private
procedure WMNCHITTEST(var Msg: TMessage); message WM_NCHITTEST;
...

procedure TForm1.WMNCHITTEST(var Msg: TMessage);
begin
inherited;
Msg.Result := HTCAPTION;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
r, r1: hRgn;
begin
Form1.BorderStyle := bsNone;

Width := 400;
Height := 200;
r := CreateEllipticRgn(0, 0, 400, 200);
r1 := CreateRoundRectRgn(150, 60, 250, 140, 20, 10);
CombineRgn(r, r1, r, RGN_XOR);
SetWindowRgn(Form1.Handle, r, true);
end;


Вопрос 261:

От: Kolobaev Rodion


:Hi All
Кто знает как програмно создать таблицу (Paradox) через компонент TTable
и записать туда Password Security или добавить(удалить) пароль на
готовой таблице.

Kolobaev Rodion
Novokuznetsk
length@mail.ru <mailto:length@mail.ru>
Rodion@mail2000.ru <mailto:Rodion@mail2000.ru>


Ответить.

Ответ 1:


Вопрос 262:

От: anton

Здравствуйте.
Скажите как сделать для проигрывателя PlayList.Если у кого-нибудь есть
исходник PlayListа,то пришлите мне на мыло.


Ответить.

Ответ 1:
Очевидно, под PlayList'ом понимается список музыкальных композиций. Насколько я понимаю, сами диски CD,
и содержащие другие музыкальные форматы не имеют информации о названиях содержащиихся на них файлов
(разве что, некоторые диски имеют файлы с текстовыми описаниями путей к файлам). Потому, приходится
такие листы своими руками создавать. А общий принцип таков:
1. Сканируем каталог (или диск) для получения списка файлов нужного формата.
2. Во время сканирования имена вместе с маршрутами запоминаем в, скажем, TStringList (вот он и PlayList,
собственно).
3. Получение информации о конкретном (размер в мм:сс, например), файле зависит от того, как мы будем
играть - с MediaPlayer'ом или без него. Я играю wav- и mp3-файлы с использованием mci-функций модуля
MMSystem, так там целый арсенал флагов для получения системной информации о композиции. Вот только
собственные названия песен ("Катюша", "Голубой Дунай", "Road To The Hell" и т.д.) форматом wav не
поддерживаются.



Вопрос 263:

От: Ернар Шамбаев

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

Скажите, пожалуйста, как эффективно (другими словами,
быстро, надежно и значительно) сжать данные, содержащиеся
в типах Pointer и TStream?


Ответить.

Ответ 1:
*This message was transferred with a trial version of CommuniGate(tm) Pro*
Есть такой алгоритм (и не один), называется "алгоритм архивирования
данных" или что-то около того.
Впрочем, нет, этих алгоритмов - просто масса.
Однако, простых из них довольно мало.

Лично я на память помню только два, но очень простых, и качественных.
Один из них называется LZW.

- 1 -

Steve Blackstock

ОБЪЯСНЕНИЕ LZW И GIF

Я надеюсь, что этот маленький документ поможет просветить
тех, кто хочет знать немного больше об алгоритме сжатия Lempel-Ziv
Welch и, конкретно, о его реализации для формата GIF.

Перед тем, как мы начнем, немного о терминологии в свете
данного документа:
"Символ": фундаментальный элемент данных. В обычных текстовых
файлах это отдельный байт. В растровых изображениях,
которыми вы заинтересовались, это индекс, который
указывает цвет данного пиксела. Я буду ссылаться на
произвольный символ как на "K".
"Поток символов": поток символов такой, как файл данных.
"Цепочка": несколько последовательных символов. Длина цепочки
может изменяться от 1 до очень большого числа символов. Я
могу указывать произвольную цепочку как "[...]K".
"Префикс": почти то же самое, что цепочка, но подразумевается,
что префикс непосредственно предшествует символу, и
префикс может иметь нулевую длину. Я буду ссылаться на
произвольный префикс, как на "[...]".
"Корень": односимвольная цепочка. Для большинства целей это просто
символ, но иногда это может быть иначе. Это [...]K, где
[...] пуста.
"Код": число, определяемое известным количеством бит, которое
кодирует цепочку.
"Поток кодов": выходной поток кодов, таких как "растровые
данные".
"Элемент": код и его цепочка.
"Таблица цепочек": список элементов обычно, но не обязательно,
уникальных.

Этого должно быть достаточно для понимания документа.

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

В данный момент давайте рассмотрим обычное кодирование и
декодирование с помощью LZW-алгоритма. В GIF используется вариация
этого алгоритма.

При сжатии и раскрытии LZW манипулирует тремя объектами:
потоком символов, потоком кодов и таблицей цепочек. При сжатии
поток символов является входным и поток кодов - выходным. При
раскрытии входным является поток кодов, а поток символов -
выходным. Таблица цепочек порождается и при сжатии и при
раскрытии, однако она никогда не передается от сжатия к раскрытию
и наоборот.

- 2 -

Первой вещью, которую мы делаем при LZW-сжатии является
инициализация нашей цепочки символов. Чтобы сделать это, нам
необходимо выбрать код размера (количество бит) и знать сколько
возможных значений могут принимать наши символы. Давайте положим
код размера равным 12 битам, что означает возможность запоминания
0FFF, или 4096, элементов в нашей таблице цепочек. Давайте также
предположим, что мы имеем 32 возможных различных символа. (Это
соответствует, например, картинке с 32 возможными цветами для
каждого пиксела.) Чтобы инициализировать таблицу, мы установим
соответствие кода #0 символу #0, кода #1 to символу #1, и т.д., до
кода #31 и символа #31. На самом деле мы указали, что каждый код
от 0 до 31 является корневым. Больше в таблице не будет других
кодов, обладающих этим свойством.

Теперь мы начнем сжатие данных. Давайте сначала определим
нечто, называемое "текущим префиксом". Этот префикс мы будем
постоянно помнить и проводить сравнение с ним здесь и в
дальнейшем. Я буду обозначать его как "[.c.]". Изначально текущий
префикс ничего не содержит. Давайте также определим также "текущую
цепочку", которая образуется текущим префиксом и следующим
символом в потоке символов. Я буду обозначать текущую цепочку как
"[.c.]K", где K - некоторый символ.

Теперь посмотрите на первый символ в потоке символов. Назовем
его P. Сделаем [.c.]P текущей цепочкой. (В данной точке это,
конечно, корень P.) Теперь выполним поиск в таблице цепочек, чтобы
определить входит ли в нее [.c.]P. Конечно, сейчас это
произойдет, поскольку в нашу таблицу при инициализации были
помещены все корни. В этом случае мы ничего не делаем. Теперь
делаем текущим префиксом [.c.]P.

Берем следующий символ из потока символом. Назовем его Q.
Добавим текущий префикс, чтобы сформировать [.c.]Q, т.е. текущую
цепочку. Выполняем поиск в таблице цепочек, чтобы определить
входит ли в нее [.c.]Q. В данном случае этого, конечно, не будет.
Ага! Вот теперь нам нужно кое-что сделать. Добавим [.c.]Q
(которая в данном случае есть PQ) в таблицу цепочек под кодом #32,
и выведем код для [.c.] в поток кодов. Теперь начнем опять с
текущего префикса, соответствующего корню P. Продолжаем
добавление символов к [.c.], чтобы сформировать [.c.]K, до тех
пор, пока мы не сможем найти [.c.]K в таблице цепочек. Затем
выводим код для [.c.] и добавляем [.c.]K в таблицу цепочек. На
псевдо коде алгоритм будет описан приблизительно так:

[1] Инициализация таблицы цепочек;
[2] [.c.] <- пусто;
[3] K <- следующий символ в потоке символов;
[4] Входит ли [.c.]K в таблицу цепочек?
(да: [.c.] <- [.c.]K;
go to [3];
)
(нет: добавить [.c.]K в таблицу цепочек;
вывести код для [.c.] в поток кодов;
[.c.] <- K;
go to [3];
)

- 3 -

Насколько это просто! Конечно, когда мы выполняем шаг [3] и
в входном потоке не остается больше символов, вы выводите код для
[.c.] и покидаете таблицу. Все сделано.

Хотите пример? Давайте предположим, что мы имеем
4-символьный алфавит: A,B,C,D. Поток символов выглядит как
ABACABA. Давайте сожмем его. Сначала мы инициализируем нашу
таблицу цепочек: #0=A, #1=B, #2=C, #3=D. Первый символ есть A,
который входит в таблицу цепочек, следовательно [.c.] становится
равным A. Далее мы берем AB, которая не входит в таблицу,
следовательно мы выводим код #0 (для [.c.]), и добавляем AB в
таблицу цепочек с кодом #4. [.c.] становится равным B. Далее мы
берем [.c.]A = BA, которая не входит в таблицу цепочек,
следовательно выводим код #1, и добавляем BA в таблицу цепочек с
кодом #5. [.c.] становится равным A. Далее мы берем AC, которая не
входит в таблицу цепочек. Выводим код #0, и добавляем AC в таблицу
цепочек с кодом #6. Теперь [.c.] равно C. Далее мы берем [.c.]A =
CA, которая не входит в таблицу. Выводим #2 для C, и добавляем CA
к таблице под кодом #7. Теперь [.c.]=A. Далее мы берем AB, которая
ВХОДИТ в таблицу цепочек, следовательно [.c.] становится равным
AB, и мы ищем ABA, которой нет в таблице цепочек, поэтому мы
выводим код для AB, который равен #4, и добавляем ABA в таблицу
цепочек под кодом #8. [.c.] равно A. Мы не можем более взять
символов, поэтому мы выводим код #0 для A и заканчиваем.
Следовательно, поток кодов равен #0#1#0#2#4#0.

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

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

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

- 4 -

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

Нам необходимо определить нечто, называемое "текущим кодом",
на что мы будем ссылаться как "<code>", и "старым кодом", на
который будем ссылаться как "<old>". Чтобы начать распаковку
возьмем первый код. Теперь он становится <code>. Этот код будет
инициализировать таблицу цепочек в качестве корневого. Выводим
корень в поток символов. Делаем этот код старым кодом <old>.

(*) Теперь берем следующий код и присваиваем его <code>.
Возможно, что этот код не входит в таблицу цепочек, но давайте
пока предположим, что он там есть. Выводим цепочку,
соответствующую <code> в поток символов. Теперь найдем первый
символ в цепочке, которую вы только что получили. Назовем его K.
Добавим его к префиксу [...], сгенерированному посредством <old>,
чтобы получить новую цепочку [...]K. Добавим эту цепочку в таблицу
цепочек и установим старый код <old> равным текущему коду <code>.
Повторяйте от того места, которое я обозначил звездочкой и вы все
сделаете. Прочтите этот абзац еще раз, если вы только
"пробежались" по нему!!!

Теперь давайте рассмотрим ту возможность, что <code> не
входит в таблицу цепочек. Вернемся обратно к сжатию и постараемся
понять, что происходит, если во входном потоке появляется цепочка
типа P[...]P[...]PQ. Предположим, что P[...] уже находится в
таблице, а P[...]P - нет. Кодировщик выполнит грамматический
разбор P[...], и обнаружит, что P[...]P отсутствует в таблице. Это
приведет к выводу кода для P[...] и добавлению P[...]P в таблицу
цепочек. Затем он возьмет P[...]P для следующей цепочки и
определит, что P[...]P есть в таблице и выдаст выходной код для
P[...]P, если окажется, что P[...]PQ в таблице отсутствует.

Декодировщик всегда находится "на один шаг сзади"
кодировщика. Когда декодировщик увидит код для P[...]P, он не
добавит этот код к своей таблице сразу, поскольку ему нужен
начальный символ P[...]P для добавления к цепочке для последнего
кода P[...], чтобы сформировать код для P[...]P. Однако, когда
декодировщик найдет код, который ему еще неизвестен, он всегда
будет на 1 больше последнего добавленного к таблице.
Следовательно, он может догадаться что цепочка для этого кода
должна быть и, фактически, всегда будет правильной.

Если я декодировщик, и я увидел код #124, а моя таблица
цепочек содержит последний код только с #123, я могу считать, что
код с #124 должен быть, добавить его к моей таблице цепочек и
вывести саму цепочку. Если код #123 генерирует цепочку, на которую
я сошлюсь здесь как на префикс [...], то код #124 в этом особом
случае будет [...] плюс первый символ [...]. Поэтому я должен
добавить первый символ [...] к ней самой. Не так плохо.

- 5 -

В качестве примера (довольно часто встречающегося) давайте
предположим, что мы имеем растровое изображение в котором первые
три пиксела имеют одинаковый цвет. Т.е. мой поток символов
выглядит как : QQQ.... Для определенности давайте скажем, что мы
имеем 32 цвета и Q соответствует цвету #12. Кодировщик сгенерирует
последовательность кодов 12,32,.... (если вы не поняли почему,
возьмите минуту, чтобы понять.) Вспомним, что код #32 не входит в
начальную таблицу, которая содержит коды от #0 до #31.
Декодировщик увидит код #12 и транслирует его как цвет Q. Затем он
увидит код #32, о значении которого он пока не знает. Но если он
подумает о нем достаточно долго, он сможет понять, что QQ должно
быть элементом #32 в таблице и QQ должна быть следующей цепочкой
вывода.

Таким образом, псевдо код декодирования можно представить
следующим образом:

[1] Инициализация строки цепочек;
[2] взять первый код: <code>
[3] вывести цепочку для <code> в поток символов;
[4] <old> = <code>
[5] <code> <- следующий код в потоке кодов;
[6] существует ли <code> в таблице цепочек?
(да: вывод цепочки для <code> в поток символов;
[...] <- трансляция для <old>
K <- первый символ трансляции для <code>
добавить [...]K в таблицу цепочек;
<old> <- <code>
)
(нет: [...] <- трансляция для <old>
K <- первый символ [...];
вывод [...]K в поток символов и добавление его к
его к таблице цепочек;
<old> <- <code>
)
[7] go to [5];

Опять же, если вы обнаружите на шаге [5], что нет больше
символов, вы должны закончить. Вывод цепочек и нахождение
начальных символов в них ставят сами по себе проблемы
эффективности, но я не собираюсь здесь предлагать способы их
решения. Половина удовольствия от программирования состоит в
разрешении подобных штук!

- 6 -

---
А теперь вариации GIF'а на эту тему. В части заголовка
GIF-файла существует поле, называемое в потоке растровых данных
"кодом размера". Это весьма запутывающее название для этого поля,
но мы должны с ним смириться. На самом деле это "размер корня".
Фактический размер (в битах) кодов сжатия в действительности
изменяется в процессе сжатия/раскрытия, и я буду ссылаться на него
здесь, как на "размер сжатия".

Начальная таблица, как обычно, содержит коды для всех корней,
но к ее верхней части добавляются два специальных кода.
Предположим, мы имеем "размер кода", который обычно равен числу
битов на пиксел. Обозначим его N. Если число битов на пиксел равно
1, N должно равняться 2: корни занимают ячейки #0 и #1 в начальной
таблице и два специальных кода будут занимать ячейки #4 #5. В
любом другом случае N равно числу битов на пиксел, корни занимают
ячейки от #0 до #(2**N-1), а специальные коды равны (2**N) и (2**N
+ 1).

Начальный размер сжатия будет равен N+1 биту на код. Если вы
ведете кодирование, вы выводите сначала коды длиной (N+1) бит и,
если вы ведете декодирование, вы выбираете сначала (N+1) бит из
потока кодов. В качестве специальных кодов используются: <CC> или
код очистки, равный (2**N), и <EOI> или конец информации, равный
(2**N + 1). <CC> говорит кодировщику, что нужно снова
инициализировать таблицу цепочек и переустановить размер сжатия
равным (N+1). <EOI> означает что кодов больше нет. Если вы
ведете кодирование или декодирование, вы должны начать добавление
элементов в таблицу цепочек с <CC> + 2. Если вы ведете
кодирование, вам следует вывести <CC> в качестве самого первого
кода, и затем опять каждый раз, как только вы достигните кода
#4095 (шестнадцатиричное FFF), поскольку GIF не допускает размера
сжатия большего 12 бит. Если вы ведете раскрытие, вам следует
реинициализировать вашу таблицу цепочек, как только вы обнаружите
<CC>.

Переменный размер сжатия на самом деле не доставляет особых
хлопот. Если вы ведете кодирование вы начинаете с размера сжатия в
(N+1) битов, и, как только вы выведете код (2**(размер сжатия)-1),
вы увеличиваете размер сжатия на один бит. Следовательно,
следующий код вашего вывода будет на один бит длиннее. Помните,
что наибольший размер сжатия равен 12 битам, что соответствует
коду 4095. Если вы достигли этого предела, вы должны вывести <CC>
в качестве следующего кода и начать сначала. Если вы ведете
декодирование, вы должны увеличить ваш размер сжатия КАК ТОЛЬКО ВЫ
запишите элемент #(2**(размер сжатия) - 1) в таблицу цепочек.
Следующий код, который вы ПРОЧИТАЕТЕ будет на один бит длиннее. Не
делайте ошибки, дожидаясь, пока вам будет нужно добавить к таблице
код (2**размер сжатия). Вы уже пропустили бит из последнего кода.

Упаковка кодов в битовый поток растровых данных также
является потенциальным камнем преткновения для новичков
кодирования и декодирования. Младший бит кода должен совпадать с
младшим доступным битом первого доступного байта в потоке кодов.
Например, если вы начали с 5-битного кодов сжатия, и ваши три
первых кода, скажем, <abcde>, <fghij>, <klmno>, где e, j, и o
биты #0, ваш поток кодов начнется как:

- 7 -

byte#0: hijabcde
byte#1: .klmnofg

Таким образом различие между обычным LZW и LZW для GIF
заключаются в наличии двух дополнительных специальных кодов и
переменном размере сжатия. Если вы поняли LZW, и вы поняли эти
различия, вы поняли все!

В качестве P.S. Вы могли заметить, что кодировщик имеет
небольшую битовую гибкость во время сжатия. Я описал "жадный"
способ, выбирающий перед выводом кода настолько много символов,
насколько это возможно. Фактически такой способ является
стандартным для LZW и дает в результате наилучшую степень сжатия.
Однако, нет никакого правила, которое запрещало бы вам
остановиться и вывести код для текущего префикса, вне зависимости
от того, есть ли он уже в таблице или нет, и добавить эту цепочку
плюс следующий символ в таблицу цепочек. Существуют различные
причины, чтобы пожелать это сделать, особенно, если цепочка
слишком длинна и порождает трудности при хешировании. Если вам это
нужно, сделайте это.

Надеюсь, это поможет вам.

Steve Blackstock

Стиву Блэкстоку помог заговорить по-русски сотрудник
Института прикладной математики AH CCCP А.Самотохин


Вопрос 264:

От: Филинов Денис

Вопрос:

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


Ответить.

Ответ 1:
'Попробуй поставить на форму OleContainer, и кликни на нем два раза,
в раскрывшемся окне может что-то найдешь для себя.


Вопрос 265:

От: "Алексей"


:Здравствуйте. Только не смейтесь над моим вопросом, я чайник. Как,
допустим, при нажатии кнопки запускалась другая форма, окно? Например,
окно о создателе. Что нужно написать в обработчике событий onClick?
Спасибо.
Phiber


Ответить.

Ответ 1:
В обработчике OnClick можно написать все что угодно, а именно только
то, что тебе нужно обработать при нажатии на кнопку.

А теперь
небольшой пример:

...
Form2.ShowModal; // Вывести модальное окно на экран, т.е. форму 2.
// для вывода немодального окна нужно использовать
// две функции: Show - показать и Hide - спрятать.
...
Ответ 2:
Создать две формы - основную (пусть Form1) и вызываемую (Form2) - пункт меню File | New Form.
Перенести вторую форму из Auto-Create в Available - пункт меню Project | Options | Forms.
Прописать модуль второй формы в разделе uses первой формы - по умолчанию это скорее всего будет unit2, то
есть получится что-то типа

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Unit2;

Далее обработать событие OnClick для кнопки на основной форме:

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Create(Self);
Form2.ShowModal;
Form2.Free;
end;

После закрытия второй формы опять увидите первую.


Вопрос 266:

От: Сергей Сарычев

: Здравствуйте, господа программисты!
У меня имеется такой вопрос: Как сделать так, чтобы форма имела не
стандартный вид прямоугольного окна, а другой, необходимый
програмисту. Например, форма в виде круга или овала.
Как это можно реализовать?

Ответить.

Ответ 1:
Сначала нужно создать регион.
Это можно сделать функциями:
CreateEllipticRgn
CreateEllipticRgnIndirect
CreatePolygonRgn
CreatePolyPolygonRgn
CreateRectRgn
CreateRectRgnIndirect
CreateRoundRectRgn

Для создания сложных регионов пригодится
CombineRgn - она объединяет два региона.

Натешившись с созданием сложной фигуры можно присвоить свой дырчато-фигурный регион окну формы
SetWindowRgn - у неё всего три параметра. Хэндл окна, которое должно пострадать, регион и булевый параметр,
нужно ли перерисовать окно сразу после изменения региона. (Если окно не видимо, это излишняя процедура)

Окно сможет рисоваться и будет получать события мыши только внутри отведённого ей региона.

Когда это всё получится и ты присвоишь окну овальный регион, ты поймёшь, что в случае с формой, нужно ещё и
перекрыть её метод Paint, потому как не подозревающая подвоха форма попытается рисовать прямоугольник в овальном
регионе, и Windows просто отрежет углы формы, никому ничего не сказав. Так что вместо стандартного метода рисования
нужно будет сделать и своё рисование, соответствующее созданному региону.
Ответ 2:
Есть компоненты это реализующие, напр. библиотеки GLAD
=== Cut here start ===
unit main;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
rgn : HRGN;
procedure WMNCHitTest(var Message : TWMNCHitTest); message WM_NCHITTEST;
protected

public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
rgn := CreateEllipticRgn(0, 0, Width, Height);
SetWindowRgn(Handle, rgn, True);
end;

procedure TForm1.WMNCHitTest(var Message : TWMNCHitTest);
begin
if PtInRegion(rgn, Message.XPos, Message.YPos) then
Message.Result := HTCAPTION
else
Message.Result := HTNOWHERE;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteObject(rgn);
end;

end.
=== Cut here end ===:'



Вопрос 267:

От: "Тромбола Евгений"

Зравствуйте!
Нужна Ваша помощь :) !
Сообственно вопрос: "Нужно полностью заблокировать клавиатуру на время
выполнения программы. Как это реализовать?"


Ответить.

Ответ 1:
KeyDown.Disable:= false;

Вопрос 268:

От: Алексей Малиновский

Господа, подскажите где взять UNOReport?
Заранее спасибо.
С уважением, Алексей.


Ответить.

Ответ 1:


Вопрос 269:

От: Anna Ginkul

Кто знает можно ли в объекте типа TStringGrid закрашивать разными
цветами отдельные ячейки, если да то как!? Может какой-то другой
компонент обладает такими свойствами?
Макс...


Ответить.

Ответ 1:
Нужно написать обработчик события OnDrawCell
Я делал так:

procedure TRating.PlacesGridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
with PlacesGrid.Canvas do begin
if PlacesGrid.Cells[ACol,ARow]='' then begin
Brush.Bitmap:=Cross;
FillRect(Rect);
end;//If
end;//With
end;//TRating.PlacesGridDrawCell
Ответ 2:
Есть в Event свойство onDrawCell:

procedure DGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

ACol, ARow - координаты ячейки (от 0)
Rect - координаты углов ячейки в оконной форме.

а делаеться это примерно так (абстракцию там небольшую тарисовал, Пикассо типа :)):

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var t_Color : TColor;
begin
t_Color:=StringGrid1.Canvas.Brush.Color;
case ACol of
2 : begin
StringGrid1.Canvas.Brush.Color:=clRed;
StringGrid1.Canvas.FillRect(Rect);
end;
4 : begin
if (ARow = StringGrid1.Row) and (ACol = StringGrid1.Col) then begin
StringGrid1.Canvas.Brush.Color:=clBlack;
StringGrid1.Canvas.FillRect(Rect);
end else begin
StringGrid1.Canvas.Brush.Color:=clGreen;
StringGrid1.Canvas.FillRect(Rect);
end;
end;
end;
case ARow of
3 : begin
case ACol of
0..4 : begin
StringGrid1.Canvas.Brush.Color:=clBlue;
StringGrid1.Canvas.FillRect(Rect);
end;
5..10 : begin
StringGrid1.Canvas.Brush.Color:=clYellow;
StringGrid1.Canvas.FillRect(Rect);
end;
end;
end;
end;
StringGrid1.Canvas.Brush.Color:=t_Color;
end;

Переменная t_Color вводиться для того, чтобы можно было возвращать исстинное значение Brush.
В 5-й версии Дельфи она не нужна - StringGrid и так ее помнит, в 3-й вроде была нужна.
Учти еще, что изменение цвета фона ячейки будет влиять и на изменение цвета выборки. Т.е. выбор группы ячеек никак не
будет отражаться на перекрашенных. Если понадобиться, то нужно также перекрашивать их в другой цвет. Мне сейчас в
лом возиться, так что я вырисовал всю эту беду только для активной ячейки (смотри строку 4), а тебе нужно будет делать
это для всех, причем используя проверку на присутствие ячейки в блоке выборки. В Стринггриде для определения
квадрата выборки используеться пропертя Selection.

property Selection: TGridRect;
type TGridCoord = record
X: Longint;
Y: Longint;
end;
type TGridRect = record
case Integer of
0: (Left, Top, Right, Bottom: Longint);
1: (TopLeft, BottomRight: TGridCoord);
end;

Так что удачи.
Ответ 3:
Есть у StringGrid обработчик события OnDrawCell - его и надо Вам написать, установив свойство
TStringGrid.DefaultDrawing = False. Только учтите, что Вы берете на себя прорисовку АБСОЛЮТНО ВСЕХ ячеек
и установку сфокусированной ячейки (и ее прорисовку тоже). Прорисовка осуществляется на канве сетки, а
координаты ячейки и очерчивающий ее прямоугольник указаны в параметрах процедуры обработки.
Ответ 4:
WITH StringGrid DO Begin
Canvas.Brush.Color := clRed;
Canvas.FillRect(CellRect(2, 2));
End;
Ответ 5:
TDrawGrid как раз подойдет. Событие OnRepaint по моему.

Вопрос 270:

От: LYNX


1:Как сделать полноэкранный режим программы?
2:Как можно менять разрешение и цветность в программе?


Ответить.

Ответ 1:
Хорошее описание этой проблемы можно найти в книге М.Краснова "OpenGL графика в проектах Delphi".

Проще всего переключиться в полноэкранный режим создав форму без рамки и заголовка (свойство BorderStyle имеет значение
bsNone) и вставив в обработчик события OnCreate команду WindowState:=wsMaximized; Самое интересное то, что если установить
значение WindowState на этапе разработки то окно раскрывается не на весь экран (сам проверял!).

Для смены разрешения можно использовать API-функцию ChangeDisplaySettings.
Функция имеет 2 параметра. Первый - структура типа TDevMode, второй - набор флагов.
Описание структуры TDevMode:
Поле Назначение
dmSize Размер структуры в байтах (SizeOf(TDevMode))
dmBitsPerPel Глубина цвета
dmPelsWidth Разрешение по горизонтали
dmPelsHeight Разрешение по вертикали
dmDidplayFrequency Частота обновления

dmFields Указывает какие поля структуры задействованы в смене режима. Является
комбинацией следующих флагов:

DM_BITSPERPEL - задана глубина цвета
DM_PELSWIDTH - задано разрешение по горизонтали
DM_PELSHEIGHT - задано разрешение по вертикали
DM_DISPLAYFREQENCY - задана частота регенерации

Второй параметр функции показывает как должен устанавливаться режим:
0 - применить режим
CDS_UPDATEREGISTRY =1 - применить режим и сохранить в Реестре как используемый по умолчанию.
CDS_TEST =2 - проверить можно ли установить этот режим.

Функция возвращает результат
DISP_CHANGE_SUCCESSFUL=0 режим сменен успешно.
DISP_CHANGE_RESTART =1 режим будет сменен после перезагрузки.
DISP_CHANGE_BADFLAGS =-4 неверные флаги.
DISP_CHANGE_FAILED =-1 режим не установлен.
DISP_CHANGE_BADMODE =-2 режим не поддерживается.

Информация о функции ChangeDisplaySettings взята из справочной системы Delphi.
Ответ 2:
1. Установи у формы стиль clNone и выбери в свойстве обработчика
событий в State - Maximized...


Вопрос 271:

От: Загорский Антон

Здравствуйте
У меня вот какой вопрос:
Есть ListBox, и туда постепенно добавляются Item.Естественно, возникает
полоса прокрутки, но при добавлении следующего Item окно listBox не
прокручивается, чтобы стала видна самая последняя Item, а остаётся прежним
лишь бегунок скроллинга движется вверх, а надо чтоб он всегда был внизу.
Скажите пожалуйста, как это сделать.

Amber



Ответить.

Ответ 1:
Нужно посылать ListBox-у сообщение WM_VSCROLL сразу после добавления
нового элемента.
Делается примерно так:
SendMessage(ListBox1.Handle,WM_VSCROLL,SB_BOTTOM,0);
Ответ 2:
No problem:
...
ListBox.Items.Add( 'Text' );
ListBox.TopIndex := ListBox.Items.Count-1;
Ответ 3:
ListBox.ItemIndex := ListBox.Items.Add(Имя_Пункта) и будет выделен дбавленный пункт.


Вопрос 272:

От: kaktooss@mail.ru

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


Ответить.

Ответ 1:
Часто приложению, которое работает в интернете, требуется знать, подключён пользователь к
интернету или нет. Предлагаю Вам довольно гибкое решение этого вопроса.
Совместимость: Delphi 3.x (или выше)
Для работы Вам необходимо импортировать функцию InetIsOffline из URL.DLL:
function InetIsOffline(Flag: Integer): Boolean; stdcall; external 'URL.DLL';
а затем поместить в программу простой вызов функции для проверки статуса соединения:
if InetIsOffline(0) then
ShowMessage('This computer is not connected to Internet!')
else
ShowMessage(You are connected to Internet!');
Эта функция возвращает TRUE если соединение с интернетоm отсутствует,
или FALSE если соединение установлено.
Замечание: параметр Flag игнорируется, соответственно используем ноль.
Эта DLL обычно проинсталлирована на большинстве компьютеров.
Она также существует в Win98 либо поставляется с Internet Explorer 4
или выше, Office 97 и т.д.. Более подробно можно прочитать в MSDN.
Оригинал: http://msdn.microsoft.com/library/psdk/shellcc/shell/Functions/InetIsOffline.htm
Ответ 2:
Сам не проверял ,но один пример должен работать (скорее всего первый)
<<<1>>>
uses wininet;
var a:boolean;
procedure TForm1.timer1timer(Sender: TObject);
begin
if {есть соединение} InternetGetConnectedState(0,0)
then
begin
a:=true;
{+Ваша реакция на выход в инет}
end
else
if a then
begin
a:=false;
{+Ваша реакция на отключение от инета}
end;
end;
>>>1<<<

<<<2>>>
uses wininet;
var a:boolean;
procedure TForm1.timer1timer(Sender: TObject);
begin
if {есть соединение} InternetGetConnectedState(1,0)
then
begin
a:=true;
{+Ваша реакция на выход в инет}
end
else
if a then
begin
a:=false;
{+Ваша реакция на отключение от инета}
end;
end;
>>>2<<<

Вопрос 273:

От: Dmitriy

Шахматы.
Нужно найти всевозможные комбинации на шахматной доске выполненной в
IMAGE(8x8), 8-ми ладей таким образом что-бы они не угрожали друг другу.


Ответить.

Ответ 1:
Po-moemu edinstvennaya kombinaciya eto kogda ladi stoyat po diagonali,
ot kletki (1,1) do kletki (8,8), ili ot kletki (1,8) do kletki (8,1)
Ответ 2:
В оригинале задача была для ферзей, и решалась полным перебором вариантов.
Обычно используется как пример рекурсии. А что касается ладей, то поставь их
как угодно, лишь бы не в одном ряду, например по диагонали ;)
Ответ 3:
Алгоритм решения этой задачи такой.
Пусть i-я ладья имеет координаты Ki,Mi. Назовем функцию которая рисует ладью например DrawLadja(K,M).
For K1:=1 to 8 do
For M1:=1 to 8 do

For k2:=1 to 8 do
If k2<>k1 then
For m2:=1 to 8 do
If m2<>m1 then

For k3:=1 to 8 do
If (k3<>k1) and (k3<>k2) then
For m3:=1 to 8 do
If (m3<>m1) and (m3<>m2) then
..............
For k8:=1 to 8 do
If (k8<>k1) and (k8<>k2) and (k8<>k3) and (k8<>k4) and (k8<>k5) and (k8<>k6) and (k8<>k7) then
For m8:=1 to 8 do
If (m8<>m1) and (m8<>m2) and (m8<>m3) and (m8<>m4) and (m8<>m5) and (m8<>m6) and (m8<>m7) then begin
DrawLadja(K1,M1); DrawLadja(K2,M2); DrawLadja(K3,M3);....... DrawLadja(K8,M8);
end;
Ответ 4:
В книге [Дрейфус М., Ганглоф К. Практика программирования на Фортран. - М.:
Мир, 1978] подробно проанализирована (и решена, правда не на Pascal а на
FORTRAN) чуть более сложная задача:
<<Найти все положения, которые могут занимать 8 ферзей на шахматной доске,
расположенные так, чтобы ни один из них не находился "под боем". >>
В частности, показано что существует 92 таких позиции.
Попадалась мне книжка, изданная году эдак в 1987 в Риге (на русском
языке, конечно), где та же задача про ферзей решена на Pascal, однако
название и авторов не помню.


Вопрос 274:

От: "Демьян Коваль"


Вопрос: При работе с пограммой возникает ошибка "Invalid filter
expression character: .". "Танцы с бубном" вокруг BDE и установки
"параметров страны" результатов не принесли. Интересно, что на двух
машинах программа заработала без сучка-задоринки и после выставления
всех параметров как у них-> результат "0".
Хотя ошибка и возникает, в базе создается запись по условию
фильтра,а на печать не выводится.
Подскажите на какие грабли наступил и как с них слезть, времени
осталось 2 недели.


Ответить.

Ответ 1:


Вопрос 275:

От: maxxx

Можно ли использовать вычисляемые поля таблицы БД для отбора в операторе
SELECT в SQL. Если да, то как?
Роман.


Ответить.

Ответ 1:
Вообше-то нет. Вычисляемое поле является собственностью tTable
(tQuery), а select выбирает данные не из tTable, а непосредственно из
таблицы.
Вариант 1:
select
nametov,cena,kolvo,
cena*kolvo as summa {это вычисляемое поле}
from rashod
where summa <=1000

Вариант 2:
Если при вычислении есть условия, циклы и т.д. в Database Desktop
создай какое-нить поле, а его значение вычисляй в событии BeforePost,
а потом собственно выбирай select'ом...
Ответ 2:
Вычисляемые поля в Дельфи - это наворот на базу данных, используемый для того чтобы как-бы облегчить тебе задачу
(т.е. использование Table вместо реальных SQL запросов, чем в общем-то занимаеться сама Table вместо тебя). Так что
использовать их невозможно (если только кто-то не додумался написать такой компонент).


Вопрос 276:

От: Irinka


Вопрос:
Привет! Может кто подскажет: как легче всего под Windows работать с
COM-портом?
Заранее спасибо. V-tek@mail.ru <mailto:V-tek@mail.ru>


Ответить.

Ответ 1:
Работа ведётся через API-функции:
CreateFile, ReadFile, WriteFile и кое каких, более специфичных типа
GetCommState, DeviceIOCtrl и др.
Как с ними работать - описано в Win32SDK.hlp


Вопрос 277:

От: _rip_

Здравствуйте... Проблемка вот такая...Я хочу заполнить HTML форму,
например на сайте http://
www.mts.ru/sms <http://www.mts.ru/sms> , нажать там же на кнопочку,
прочитать результат отправки и вернуться обратно при этом не открывая по
возможности окно броузера... Нужно очень срочно, если можно...а доступ в
Инет ограничен, чтобы доки почитать :-( Обращаюсь к Вам, может поможете
примерчиком, а дальше разберусь... Заранее глубоко благодарен... Руднев
Олег


Ответить.

Ответ 1:


Вопрос 278:

От: Dizzer

Здравствуйте All.

Нужно запустить програму до загрузки винды(пока иконки на десктопе не
появились) и пока эта программа не завершится загрузка не
продолжается, наподобе как окошко "Вход в Виндоус" при загрузке.
Винда 98, Ме.


Ответить.

Ответ 1:
Решается это просто - в реестре Windows есть такой раздел
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
Так вот - запущенная в нем программа держит винду до своего
завершения. Но - ВИНДА УДАЛЯЕТ СТРОКИ СРАЗУ ПОСЛЕ ИХ ИСПОЛНЕНИЯ!!!
Но это обходится путем прописывания проги в
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
,которая вновь добавляет убитую строчку в реестр.


Вопрос 279:

От: Юрий Геннадьевич Батяев

Здравствуйте!
Вопрос такого плана. Мне необходимо рассылать сообщения от одного
Юзера другим с помощью стандартного НОВЕЛЛовского (версия NOVELL5.0)
из программы написанной на ДЕЛФИ. Стандартного SEND.exe в NOVELL5.0
нет. Сейчас (и в документации) можно послать сообщение используя
только мышку, а мне необходимо с командной строки.



Ответить.

Ответ 1:
используй параметры командной строки. процедурам все равно, на какое
сбытие они реагируют.


Вопрос 280:

От: Олег Гончаренко

HELP!
в моей БД храняться изображения, хочу сделать слайд-шоу
применяю такой код:

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
with Table1 do
begin
Table1.First;
while not Eof do
begin
Timer2.Enabled := True; /включаю таймер/
Table1.Next;

дале следует код вывода изображений на форму ........

end;
end;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
StatusBar1.Panels[3].Text := 'Слайд - шоу';
Timer2.Enabled := False; /выключаю таймер/
end;

но в результате после нажатия кнопки через какое-то время
вижу только последнюю картинку....
Может есть другой способ задать задежку в 2-3 секунды между
переходом от записи к записи (Table1.Next)


Ответить.

Ответ 1:
Есть такой прелестный орератор sleep(время в милисек)
удачи:'
Ответ 2:
Компонент TTimer предназначен для выполнения определнных действий, через определенные промежутки времени, но он
не задерживает выполнение программы. Следовательно данном коде он ни чего не делает, не считая того, что он себя
выключает и выводит одну и туже надпись, чтобы правльно реализовать данный пример код должен быть примерно
следующим:

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
Table1.First; //Перемещаемся на первую запись. Позиционироваться будем в обработчике таймера
Timer2.Enabled := True; //включаю таймер
while Timer2.Enabled do //Обрабатываем сообщения виндов в том числе и нашего таймера
Application.ProcessMesages;
//Делаем это для того, чтобы было видно действия производимы в таймере
//Более простого способа организации задержки для данного случая я не знаю
end;


procedure TForm1.Timer2Timer(Sender: TObject);
begin
StatusBar1.Panels[3].Text := 'Слайд - шоу';
with Table1 do
begin
код вывода изображений на форму ........
Next;
if Eof then
Timer2.Enabled := False;
end;//With
end;//TForm1.Timer2Timer
Green
Ответ 3:
сам отвечаю на свой вопрос
при нажатии на батон "Слайд-шоу":

procedure TForm1.ToolButton15Click(Sender: TObject);
with Table1 do
begin
/включает или выключает показ слайдов/
Timer2.Enabled := not Timer2.Enabled;
end;
end;

а это работа таймера

procedure TForm1.Timer2Timer(Sender: TObject);
begin
if not Table1.Eof then
begin
Table1.Next;
................
вывод изображения
.................
end
else if Table1.Eof then
begin
Timer2.Enabled := False; /останавливаем таймер/
ShowMessage('Просмотр данного раздела окончен!');
end;
application.ProcessMessages;
end;
Ответ 4:
Programma sdelala to chto ty napisal, probejala po vsei tablice,
ostanovivshis na poslednei zapisi.

Nado napisat tak

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
Table1.OPen;
Table1.First;
while not Table1.Eof do
begin
StatusBar1.Panels[3].Text := 'Slide show: Picture :' + <kakaya-to
vspomogatelnaya informaciya, mojet nomer, mojet, imya>
dalee kod vyvoda izobrajeniya na formu................................


// turn timer on
Timer2.Enabled := True;

// waiting
while Timer2.Enabled do;

Table1.Next;

end;

end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
Timer2.Enabled := False; /???????? ??????/
end;
Ответ 5:
Нужно немного изменить код:

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
with Table1 do
begin
Table1.First;
while not Eof do
begin
Timer2.Enabled := True; /включаю таймер/

// Добавляем такую проверку:
while Timer2.Enabled do Application.ProcessMessage;

Table1.Next;

далее следует код вывода изображений на форму ........

end;
end;
end;


При этом следующее изображение из БД не будет выбираться до тех пор,
пока Timer2.Enabled = true;





4. Ищу подельника.
------------------
Я сам сейчас разбираюсь с Делфями, но тупо ковыряя очень тяжело
добиться каких либо результатов. Хотелось бы найти какого нибудь
компаньёна который мог бы предложить написать что нибудь совмесное,
а я буду стараться оказать посильную помощь.
Мой mail: nks13@ukrpost.net .




Если Вы хотите как можно скорее получить ответ на свой вопрос, то
укажите в теме письма - delphiV,иначе письмо будет прочитано значительно
позже, если же у вас есть предложения то в теме письма укажите delphiP.

Для интересующихся - немного о себе. Работаю на
железнодорожном транспорте ведущим программистом.
Основные мои разработки это сбор и доставка клиентам
информации о вагонах и поездах: где находится(по России),
куда едет. В связи с этим программировал для e-mail,Socket,БД,ISAPI.

За сим прощаюсь - скорых Вам и качественных программ.

Автор рассылки - Дмитрий.
ICQ - 89533941.

ВСЕ ВОПРОСЫ СПРОСИТЬ ПРЕДЛОЖИТЬ АРХИВЫ СКОЛЬКО НАС



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться Рейтингуется SpyLog

В избранное