tag:blogger.com,1999:blog-84947551391465743712024-03-14T12:50:34.132+04:00Pro-DelphiНаучиться программировать не так сложно, как кажется. Уроки по принципу от простого к сложному. Исходные тексты программ. Видео уроки.Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.comBlogger60125tag:blogger.com,1999:blog-8494755139146574371.post-26980129080986121852014-11-28T21:09:00.001+04:002014-11-28T21:09:48.033+04:00Найди своего разработчика сайта<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt;">
<br /></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 70.8pt; margin-right: 0cm; margin-top: 3.0pt;">
<b><i>Кто мне сделает сайт, за который не стыдно
перед клиентами?<o:p></o:p></i></b></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 70.8pt; margin-right: 0cm; margin-top: 3.0pt;">
<b><i>Обязательно ли хороший сайт должен стоить
300 тысяч рублей, в то время как на рынке предлагают то же самое за 5 тысяч?<o:p></o:p></i></b></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 70.8pt; margin-right: 0cm; margin-top: 3.0pt;">
<b><i>По каким критериям мне нужно оценивать
предложения веб-разработчиков? <o:p></o:p></i></b></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
В планируемом
цикле статей я постараюсь дать не утомительный, но вполне развёрнутый анализ
рынка разработчиков web-интерфейсов (порталов, сайтов, интернет страниц),
обозначить “подводные камни”, с которыми обязательно столкнётся тот или иной
соискатель исполнителя (разработчика).<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
На
рынке приводится огромное количество классификаций, показывающих все
разнообразие веб-возможностей для удовлетворения самых различных потребностей.
Это можно сравнить с океаном, в котором плавают маленькие рыбки – сайты-визитки,
золотые рыбки – промо-сайты и киты веб-индустрии – социальные сети и поисковые
порталы. Во всем этом пестром многообразии видов и форм человеку далеко не просто
выбрать то, что ему действительно нужно, а еще сложнее – оценить реальное
соотношение – цена/качество. Под качеством в данном случае понимаем не только
качество исполнения, но и уровень
соответствия того, что человек хотел на старте, тому, что получилось.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Последнее
далеко не всегда совпадает, и тому есть ряд причин. Самая главная причина
связана с тем, что классификация сайтов, представленная вам, в 99% случаев основана
на функционале: сайт визитка – для одного, корпоративный сайт – для второго,
интернет-магазин – для третьего. А стоимость сайта зависит вовсе не от этого. <o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Для
упрощения договоримся: называть «интернет-сайтом» всё: большой, красиво
оформленный многофункциональный портал и
набор из двух простых интернет страничек. С точки зрения разработки они
отличаются только продолжительностью их создания. <o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Обозначим
исходные данные: имеется физическое лицо или представитель какой либо компании,
наделённый руководством соответствующими правами, которому необходимо найти
исполнителя, способного создать интернет-сайт. Назовём его “Заказчиком”.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Куда
бы ни обратился Заказчик: к друзьям-знакомым или к поисковой системе Яндекс, он
всегда получит некий набор предложений со стороны разработчиков, который можно
классифицировать следующим образом:<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
<br /></div>
<div class="1CxSpMiddle" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: 0cm;">
<!--[if !supportLists]-->1.<span style="font-size: 7pt; font-stretch: normal; line-height: normal;">
</span><!--[endif]-->Начинающие.<o:p></o:p></div>
<div class="1CxSpMiddle" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: 0cm;">
<!--[if !supportLists]-->2.<span style="font-size: 7pt; font-stretch: normal; line-height: normal;">
</span><!--[endif]-->Профессионалы.<o:p></o:p></div>
<div class="1CxSpMiddle" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: 0cm;">
<!--[if !supportLists]-->3.<span style="font-size: 7pt; font-stretch: normal; line-height: normal;">
</span><!--[endif]-->Коллективы.<o:p></o:p></div>
<div class="1CxSpMiddle" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; mso-add-space: auto;">
<br /></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
К
первой позиции – «начинающие» ‑ относятся вчерашние и нынешние студенты,
выпускники специальных курсов и самоучки. Представители этой группы очень хотят
получить какой угодно заказ за любые даже самые нелепые суммы вознаграждений.
Как правило, у них нет опыта выслушать и понять требования и пожелания
Заказчика. Начинающих разработчиков часто можно распознать по тому, как
они упрямо навязывают свои решения.
Происходит это от того, что других решений «они не проходили», умеют только
так, как их учили и боятся сделать шаг в сторону. Нередко они переоценивают
свои возможности, что приводит к взаимным претензиям и отрицательным
результатам в итоге.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
«Профессионалы»
‑ это web-мастера с достаточным опытом, богатым запасом знаний и
продолжительным стажем работы. Они, как правило, работают самостоятельно, редко
прибегая к сотрудничеству с кем либо. Умеют услышать, что хочет заказчик.
Способны сделать всё, что угодно. Знают настоящую цену своему творчеству.
Работают не быстро, потому что приходится решать все задачи самому. Но
результат, как правило, получается весьма качественным. <o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
«Коллективы»
‑ это группы разработчиков с разным опытом подготовки и различными
профессиональными навыками, объединённые в ту или иную компанию. Как правило,
все вопросы будут решаться комплексно, т.е. Заказчику не придётся обращаться
отдельно к дизайнеру или искать сертифицированного специалиста, способного
решить вопросы шифрования и защиты его данных.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
В
отдельную группу (при поиске исполнителя через интернет), я бы еще выделил
мошенников. Они пользуются простым приёмом: назначают конкурентно низкую цену
за свои услуги. Незадачливый Заказчик легко клюёт на такую «наживку». Что
получается в итоге ‑ нетрудно
догадаться: он теряет время и деньги, ничего не получая взамен. Об этой группе
я ниже упоминать не буду, нужно просто быть осторожней.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Что же
(или кого), в итоге, выбрать Заказчику?<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Если
Заказчику необходимо создать нечто глобальное, подобное поисковой машине
Яндекс, или сложно функциональное, то лучше обратиться к коллективу
разработчиков. Подобные решения невозможно воплотить исполнителю-одиночке.
Такие работы даже у коллектива разработчиков занимают довольно продолжительное
время, стоимость их высока и исчисляется сотнями тысяч рублей.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Если
задача у Вас как Заказчика создать пару ярких страниц, рекламирующих Вашу
продукцию или услуги, но при этом тратить более 10 тысяч рублей на решение
особого желания нет, то Вы вполне можете рискнуть обратиться к представителям
первой группы ‑ начинающим разработчикам.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
В том
случае, когда задача требует создания базы данных для хранения Вашей информации
и интерфейса работы с ней, то Вам не обойтись без услуг опытного программиста.
Цена вопроса в этом случае может колебаться в довольно широких пределах.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
Анализ
рынка показывает, что и в так называемом срединном сегменте (т.е. не студенты и
не акулы веб-пространства), диапазон цен варьирует от 20 тысяч до 150 тысяч
рублей за примерно один и тот же комплекс работ по созданию сайта. В данном
случае важно подчеркнуть, что оценивается не то, каким Ваш сайт будет по
функционалу, а какой объем работ предполагается осуществить, чтобы в полной
мере исполнить Ваши пожелания.<o:p></o:p></div>
<div class="1" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt; text-align: justify; text-indent: 35.45pt;">
В
следующих материалах я планирую более подробно остановиться на других аспектах
этой проблемы.<o:p></o:p></div>
<br />
<div class="MsoNormal" style="line-height: 150%; margin-bottom: 3.0pt; margin-left: 0cm; margin-right: 0cm; margin-top: 3.0pt;">
<br /></div>
Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-42489656341766794022012-06-18T15:58:00.000+04:002012-06-19T10:23:12.111+04:00Урок 49. Инсталлятор программы - это не сложно<div>
Помните, на <a href="http://pro-delphi.blogspot.com/2012/06/48.html">предыдущем уроке</a> я поместил в отдельную папку необходимые файлы? </div>
<div>
Это были файлы, разработанные нами в процессе создания программы "Расходы", т.е. обеспечивающие заданный функционал программы. </div>
<div>
<br /></div>
<div>
<div>
Еще раз отмечу, что мною выбран способ хранения настроек в файле ini, а не в реестре Windows, поэтому при создании установщика данный вопрос рассматриваться не будет (иными словами: все своё ношу с собой :-) )</div>
<br />
И после этих заявлений, любознательные могут спросить: "Ну и зачем нам тратить время на написание инсталлятора, если достаточно просто скопировать эту папку на другой компьютер и - пользуйся на здоровье?"</div>
<div>
<br /></div>
<div>
Не так все просто.</div>
<div>
<br />
<a name='more'></a><br /></div>
<div>
В <a href="http://pro-delphi.blogspot.com/2012/05/46.html">46 уроке</a> я говорил о создании сложного отчета, при проектировании которого был использован компонент, требующий наличия особой библиотеки. Т.е. теперь - самое время вспомнить о программах, библиотеках и прочих "сопутствующих товарах", которые обеспечивают работу созданной нами программы. </div>
<div>
Думаю, что надо по ходу создания установщика (инсталлятора) программы быть готовым, ответить на ряд вопросов, т.е. вспомнить, где хранится, например, <a href="http://pro-delphi.blogspot.com/2012/05/46.html">скачанная библиотека midas.dll</a> и как ее установить. Если бы функционал программы обеспечивал сканирование наиболее важных документов (чеков, счетов за услуги, товары и т.п.), я имею ввиду электронный архив, то для создания подобного функционала понадобилась бы еще одна библиотека и так далее.</div>
<div>
<br /></div>
Как я уже неоднократно утверждал, для решения любого вопроса почти всегда существует несколько путей. Можно написать программу инсталлятор собственно в среде Delphi. А можно воспользоваться уже готовыми программами. Я выбрал бесплатный вариант Inno Setup.<br />
<br />
<div style="text-align: center;">
* * *</div>
<br />
<a href="http://ru.wikipedia.org/wiki/Inno_Setup">Википедия:</a><br />
<br />
Inno Setup — <a href="http://ru.wikipedia.org/wiki/Open_source">open source</a> система создания инсталляторов для Windows программ. Впервые выпущенный в 1997 году, Inno Setup сегодня конкурирует и даже превосходит многие коммерческие установщики по функциональности и стабильности. <br />
<div style="text-align: center;">
<br />
* * *</div>
<br />
<br />
Достаточно прелюдий. <br />
<br />
После установки программы (а установка не должна вызвать никаких вопросов), загрузив программу, Вы получите вот такое окно с новым проектом:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSuY3v-dV7k8cy2uruS_JEf85xvzlAfeiXwic5phxkfW6q1letzy0FrsHPF3uq154U-d-vp2iQ2KL7NSJ6A6F3shbN4DhzesjyI1w4v-tn27wqcU9ypln-aldQm5Jr1xD39ifXm-OfvjPk/s1600/49_01.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSuY3v-dV7k8cy2uruS_JEf85xvzlAfeiXwic5phxkfW6q1letzy0FrsHPF3uq154U-d-vp2iQ2KL7NSJ6A6F3shbN4DhzesjyI1w4v-tn27wqcU9ypln-aldQm5Jr1xD39ifXm-OfvjPk/s320/49_01.png" /></a><br />
<br />
Нажмите на самую левую пиктограмму - "Туц..." ой, извините: "New...", начнет работу визард-помощник, который существенно облегчит решение задачи. Не бойтесь что-то сделать неправильно, позже всегда можно внести изменения.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC7mh_JL9uJ1k8PEvJJOhPzPQLN9HtgOpp8Kri0Kh7t9H3oreli2ChMLrpqbmy9QVw99HUzaHjkRQvAcZIHK5FOh8z3igi3unhU9_iV4UpPqIZkq4uI-o6Y3_-Hj4tqHkLWyohfK6ia1yV/s1600/49_02.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC7mh_JL9uJ1k8PEvJJOhPzPQLN9HtgOpp8Kri0Kh7t9H3oreli2ChMLrpqbmy9QVw99HUzaHjkRQvAcZIHK5FOh8z3igi3unhU9_iV4UpPqIZkq4uI-o6Y3_-Hj4tqHkLWyohfK6ia1yV/s320/49_02.png" /></a><br />
<br />
Оставив не отмеченным Check Box, нажмем Next и немного пофантазируем (или заглянем в опции проекта), чтобы заполнить поля в следующем окне:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhUbWO6GIolP9mj4NwOAnKKn3Mt-iLT10gl9FJwBOFDy8eWi9TBfFStuRIJecR6ireQBjrqP78xDzVNgYn8cQ6hOudGviaWOaXJ9jmxDwS1YIHeLhaU12SDfMVx1aiRCwb2s8-r2lZSf-j/s1600/49_03.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhUbWO6GIolP9mj4NwOAnKKn3Mt-iLT10gl9FJwBOFDy8eWi9TBfFStuRIJecR6ireQBjrqP78xDzVNgYn8cQ6hOudGviaWOaXJ9jmxDwS1YIHeLhaU12SDfMVx1aiRCwb2s8-r2lZSf-j/s400/49_03.png" /></a><br />
<br />
В следующем окне я пока оставлю все без изменений:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz7Lq-KdFJkTjQIpKGVSnT6PUvslZGaq6jOUZOPwJ_GyvS3NQDVda5fEE57ChuEhpW0xoKsIMr8wr-BBnN1eJijpGQXu7YZxYLdD6N39EAlyb_tm2t7cHIOPFMKtEH-Be0Js2Z7CC7FSIK/s1600/49_04.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz7Lq-KdFJkTjQIpKGVSnT6PUvslZGaq6jOUZOPwJ_GyvS3NQDVda5fEE57ChuEhpW0xoKsIMr8wr-BBnN1eJijpGQXu7YZxYLdD6N39EAlyb_tm2t7cHIOPFMKtEH-Be0Js2Z7CC7FSIK/s400/49_04.png" /></a><br />
<br />
<br />
Далее нужно указать главный исполняемый файл приложения (программы) и добавить в список все сопутствующие файлы (из той самой папки, которую я создал на предыдущем уроке):<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8EF-rK_MMmWL4aDQPH0EK0gcsj3QHU4gguLu7tXHrTk80oqg6kg5DXfxqlYHunlgIxiwNziMT1wF2b4G7FNOAizGtkloILfHAwn2V11tJ8d_9ku3x0MxZIOAm-7B85KUE9X3fHI4M_MVH/s1600/49_05.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8EF-rK_MMmWL4aDQPH0EK0gcsj3QHU4gguLu7tXHrTk80oqg6kg5DXfxqlYHunlgIxiwNziMT1wF2b4G7FNOAizGtkloILfHAwn2V11tJ8d_9ku3x0MxZIOAm-7B85KUE9X3fHI4M_MVH/s1600/49_05.png" /></a><br />
<br />
В следующем окне спрашивается, какие иконки нужно создать и где, и дать ли пользователю, устанавливающему программу, разрешение что-то изменять (оставляю без изменения):<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEFRmMCducI8aA8R4XYpMPFLFrcq7RCdO_7YAMtcCjVTTPvRRvmNaWggwaq1tcn-ysIpqKr5h8tw6CsqEwp8Zio_3ZDX8Q7FUcHdU7fLa8PAUjiMrPgJJ6_cg53VBRktrbEoZHMhhj6mBQ/s1600/49_06.png" style="background-color: white;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEFRmMCducI8aA8R4XYpMPFLFrcq7RCdO_7YAMtcCjVTTPvRRvmNaWggwaq1tcn-ysIpqKr5h8tw6CsqEwp8Zio_3ZDX8Q7FUcHdU7fLa8PAUjiMrPgJJ6_cg53VBRktrbEoZHMhhj6mBQ/s400/49_06.png" /></a><br />
<br />
Забыл... Серьезным делом занялся, а текста лицензионного соглашения не подготовил. Да и файла Read_Me нет... Нужно их быстренько сочинить, потому что в следующем окне нас попросят указать пути к этим файлам:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifVGpWn6FyheM27aTlLH6Qc8gnNAGD4PJ1TLiODtSndZ_vwLhhHltQClKVQy6yxoqoUlbRth7nOpltIC_br9ePr7hvA4CeAZgRjrODomOkH1clqFMXac0BU0KNVnbFajLwb93f-6ZgmlCF/s1600/49_07.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifVGpWn6FyheM27aTlLH6Qc8gnNAGD4PJ1TLiODtSndZ_vwLhhHltQClKVQy6yxoqoUlbRth7nOpltIC_br9ePr7hvA4CeAZgRjrODomOkH1clqFMXac0BU0KNVnbFajLwb93f-6ZgmlCF/s400/49_07.png" /></a><br />
<br />
В следующем окне просто укажите галочкой, какой (или какие) языки должен использовать будущий инсталлятор (картинку не буду приводить здесь и так все понятно).<br />
<br />
<br />
Я думаю, что работа визарда близится к завершению, поскольку в следующем окне спрашивается, куда разместить результат работы компиллятора, как его назвать, какую иконку к нему присовокупить и нужно ли защитить установку паролем:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipfIp8HSPyUxNmRrvl8-TP3QwvFKDBugeA6R6JIvV2N34M-SaPxuZ-dQfICnsKWztLYjPJT69tVHVTE5QUYmbrMxhHDZk8bAqn7FQBwLeMUpZSRmGUgQHGVU8Gd1jEjJwKsXsmVYM5lXQu/s1600/49_08.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipfIp8HSPyUxNmRrvl8-TP3QwvFKDBugeA6R6JIvV2N34M-SaPxuZ-dQfICnsKWztLYjPJT69tVHVTE5QUYmbrMxhHDZk8bAqn7FQBwLeMUpZSRmGUgQHGVU8Gd1jEjJwKsXsmVYM5lXQu/s400/49_08.png" /></a><br />
<br />
Осталось только нажать кнопку "Finish" в следующем окне, чтобы получить готовый скрипт и вопрос "Хотите ли Вы сразу же совершить компилляцию проекта?"<br />
<br />
Отвечаю утвердительно на этот и следующий вопрос о сохранении проекта перед его обработкой. Файл проекта получит расширение *.iss.<br />
<br />
В результате работы Inno Setup в папке OutputFolder появится файл Setup.exe, это и будет первый вариант установочного файла.<br />
<br />
Побалуйтесь, запустите его:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg0cBvmWjlWfyBfERCJSejDtf1ph500g0N50KsuFAOzZE7uI9W_Kfx_PieRSJ8q8twZSAtiOPpnfXxVBnXu1KOhhzp8fBgnXS5ZVGJmIgOop7FEen7uQ_OLAvYUEWEBZTyyVInhKUSNJvB/s1600/49_09.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg0cBvmWjlWfyBfERCJSejDtf1ph500g0N50KsuFAOzZE7uI9W_Kfx_PieRSJ8q8twZSAtiOPpnfXxVBnXu1KOhhzp8fBgnXS5ZVGJmIgOop7FEen7uQ_OLAvYUEWEBZTyyVInhKUSNJvB/s320/49_09.png" /></a><br />
<br />
Если Вы ничего не меняли в процессе установки, то в папке C:\\ProgramFiles\Rashod появится не только весь набор необходимых файлов, но и файлы деинсталлятора:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjxj81w8XJdystlFrIaEwO69k_mjpywyxJPSTflEtr1NLm9Zgs6ENWxyK6Nhc7SWhD8byBgwNcElODkXtSgZ5DE3LQFeAV4iUmMpuvo998zhxgpUdPtXQf12ma5Tf5GFZPtKiovy4QI3-0/s1600/49_10.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjxj81w8XJdystlFrIaEwO69k_mjpywyxJPSTflEtr1NLm9Zgs6ENWxyK6Nhc7SWhD8byBgwNcElODkXtSgZ5DE3LQFeAV4iUmMpuvo998zhxgpUdPtXQf12ma5Tf5GFZPtKiovy4QI3-0/s400/49_10.png" /></a><br />
<br />
Красота? <br />
<br />
Не совсем... Все установится и будет работать на Вашем компьютере без проблем, поскольку на нем Вы вели разработку, следовательно, в системе имеются все необходимые библиотеки. Рекомендую ради эксперимента отправиться к знакомому, который не имеет понятия о Delphi и попробовать порезвиться у него на компе с его, разумеется, разрешения... Результат Вас разочарует.<br />
<br />
Для исправления ситуации нужно добавить в папку For Install следующие каталоги и файлы, касающиеся библиотеки Midas.dll:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmrCN_GOFi6bWp1TksU3SkWCw373qiyJM-wmg8KTjoi-Lrh18WsEyh4rsIldJ1W2-waN3mz9QJw9g89f18UhjwdqJT0ruCM9drR1LgdTN026ComK7pc91b-N7K8-Vk1RgrzbIw0fQDo9eQ/s1600/49_11.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmrCN_GOFi6bWp1TksU3SkWCw373qiyJM-wmg8KTjoi-Lrh18WsEyh4rsIldJ1W2-waN3mz9QJw9g89f18UhjwdqJT0ruCM9drR1LgdTN026ComK7pc91b-N7K8-Vk1RgrzbIw0fQDo9eQ/s1600/49_11.png" /></a><br />
<br />
Теперь в окне программы Inno Setup необходимо добавить две строчки в секцию [Files]:<br />
<br />
<span style="color: orange;">Source: "X:\Lessons\InternetBusiness\! VideoLessons\Les 49\For install\Необходимые библиотеки\Midas\Midas.dll"; DestDir: {app}; Flags: deleteafterinstall</span><br />
и<br />
<br />
<span style="color: orange;">Source: "X:\Lessons\InternetBusiness\! VideoLessons\Les 49\For install\</span>
<span style="color: orange;">Необходимые библиотеки</span> <span style="color: orange;">\Midas\RegisterMidas.bat"; DestDir: {app}; Flags: deleteafterinstall</span><br />
и одну строчку - в секцию выполнения [Run], чтобы созданный нами когда-то *.bat файл сработал:<br />
<br />
<span style="color: orange;">Filename: {app}\RegisterMidas.bat; WorkingDir: {app}; StatusMsg: wait</span><br />
Обратите внимание, что после установки программы, файлы Midas.dll и RegisterMidas.bat в целевой папке с установленной программой больше не нужны, поэтому в указанных выше строчках присутствует метка (флаг) DeleteAfterInstall (удалить после установки).<br />
<br />
Теперь после запуска вашего Setup.exe, в процессе установки будет повторно размещена в системе необходимая библиотека Midas, о чем пользователь в процессе работы установщика получит сообщение в виде:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwD8ha_R_zdr7TfGOOhsQmTXquBiY78zfdDgF7KI-HH9WFzCcIpG8d8l5u6eEq3lyRh752I1rd3tKeJWZO7jbj4txVVbeSeupumxTkdkirfMnf0GOuv_RWTNXW3tBbPT1ack_bLhn_K_AV/s1600/49_12.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwD8ha_R_zdr7TfGOOhsQmTXquBiY78zfdDgF7KI-HH9WFzCcIpG8d8l5u6eEq3lyRh752I1rd3tKeJWZO7jbj4txVVbeSeupumxTkdkirfMnf0GOuv_RWTNXW3tBbPT1ack_bLhn_K_AV/s1600/49_12.png" /></a><br />
<br />
А давайте еще ради интереса заглянем в "Панель управления" на страницу "Программы и компоненты". Мы ничегошеньки не писали в системный реестр, но знает ли при этом операционная система хоть что-то о программе "Rashod.exe"?<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqB3npGQ2dRoiqyylcyZptlN6V5PB1nwtRV5y3zI2g6kH8ZxMQIbJcPcN0tfxGqu3IQWEq-4WVkiTEXQpTUA4zpQiLzPBxLgXIYZbyDOnFfuA1oVtHaX4rFCM2KcD7W-5_LKlSTU-55ouq/s1600/49_14.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqB3npGQ2dRoiqyylcyZptlN6V5PB1nwtRV5y3zI2g6kH8ZxMQIbJcPcN0tfxGqu3IQWEq-4WVkiTEXQpTUA4zpQiLzPBxLgXIYZbyDOnFfuA1oVtHaX4rFCM2KcD7W-5_LKlSTU-55ouq/s1600/49_14.png" /></a><br />
<br />
<br />
<br />
<br />
Вот она, "родимая"! В Windows - все под контролем :-) и даже - результат нашего творчества. И, если нажать на кнопку "Удалить", то сработает деинсталлятор и...<br />
<br />
На этом рассказ о создании программы для учета расходов можно считать законченным. <br />
<br />
Обещаю в ближайшее время выложить в разделе<a href="http://pro-delphi.blogspot.com/p/blog-page_20.html"> "Скачать" </a>готовый работоспособный вариант программы, наделенный еще двумя-тремя полезными функциями, о которых я здесь лишь вскользь упоминал.<br />
<br />
Всем - удачи. До новых встреч.<br />
<br />
<br />
PS<br />
<br />
В меню "Пуск" и на рабочем столе иконки работать не будут, пока Вы в секцию<br /><br />[Icons]<br />
<br />
не добавите ключевое слово WorkingDir<br />
<span style="background-color: white;"><br /></span><br />
Name: "{group}\Rashod"; Filename: "{app}\Rashod.exe"<span style="color: orange;">; WorkingDir: {app}</span><br />
Name: "{commondesktop}\Rashod"; Filename: "{app}\Rashod.exe"; Tasks: desktopicon<span style="color: orange;">; WorkingDir: {app}</span><br />
<div>
<br /></div>
<br />
<br />
PPS<br />
<br />
Кто может ответить: после завершения работы деинсталлятора, что будет с библиотекой midas.dll. Останется она "жить" в системе или будет так же удалена? А?<br />
<br />
<br class="Apple-interchange-newline" />Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-41606513867739969132012-06-05T13:54:00.001+04:002012-06-05T13:54:25.055+04:00Урок 48. Много разных файлов в папке с проектом? Пора разобраться.Я хочу подготовить моего читателя к написанию инсталлятора программы.<br />
Прежде всего, для этого нужно из всей массы файлов, расположенных в папке с проектом, отобрать нужные.<br />
<br />
<a name='more'></a><br /><br />
У меня в папке скопилось великое множество всякой всячины:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMSV8P2uLNQm684cN5gBrrGV3Kj58Abkq1cs6GzpB6hL6scCPJAri8gaWndx9f0HIhv6Pjpf_-24CGq5GHbyHXO9gGi8sLhNJySMUNEFoEaNE_zyfUhsd4FWnMQ7dANO2qex6aFpUYOn8M/s1600/48_00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMSV8P2uLNQm684cN5gBrrGV3Kj58Abkq1cs6GzpB6hL6scCPJAri8gaWndx9f0HIhv6Pjpf_-24CGq5GHbyHXO9gGi8sLhNJySMUNEFoEaNE_zyfUhsd4FWnMQ7dANO2qex6aFpUYOn8M/s320/48_00.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если Вы внимательно следили за развитием проекта, повторяя все действия за мной, то у Вас, скорее всего, их не меньше.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Прежде всего, готовый exe-ник обработайте Compress.bat, в котором находится одна команда:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
upx Rashod.exe</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Второе: обнулите базу данных. На этом шаге можно оставить самые необходимые счета в списке счетов.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Третье: нужно создать отдельную папку, в которую мы будем складывать лишь самое необходимое.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Как же определить, что должно входить в состав "самое необходимое"?</div>
<div class="separator" style="clear: both; text-align: left;">
Если бы я, давая эти уроки, был книжным теоретиком, то, скорее всего, результат моего творчества не содержал бы различных обработчиков внештатных ситуаций.</div>
<div class="separator" style="clear: both; text-align: left;">
Поэтому, можно смело положить в отдельную папку (я назвал ее "For Install"), всего лишь один исполняемый файл Rashod.exe и попытаться его запустить. Программа сразу отреагирует на нехватку библиотеки:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8QpxWHJUZ7FnnbyHdwPeAX-9jLulZQIilZVm4jrxY-CtLjivYlXeQgBZQmNZEF7w-AkByyxfChiqgp2S2Ux91LrTbAUzRmiyWAVYPN1l-yAjtcl8ejkOExojlgcgiJXU6hTyo5AWV2Pqb/s1600/48_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="121" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8QpxWHJUZ7FnnbyHdwPeAX-9jLulZQIilZVm4jrxY-CtLjivYlXeQgBZQmNZEF7w-AkByyxfChiqgp2S2Ux91LrTbAUzRmiyWAVYPN1l-yAjtcl8ejkOExojlgcgiJXU6hTyo5AWV2Pqb/s320/48_01.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Скопируйте файл ProDelphiLyb.dll и еще раз запустите программу. Реакция не заставит себя долго ждать:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHFJi6UCAHXho-mb7Kzn0G8iSV1Icp4pc5Xm7cher7_xpl81ZQG0Av-_6O2tu02vk2YqZ-Wl496KvTbSiV4kyLrXA15RpbNkY2zMq9BDeYWWllVlprOiqYjJVTuK-1sqT4qBeRXpAKS9qv/s1600/48_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHFJi6UCAHXho-mb7Kzn0G8iSV1Icp4pc5Xm7cher7_xpl81ZQG0Av-_6O2tu02vk2YqZ-Wl496KvTbSiV4kyLrXA15RpbNkY2zMq9BDeYWWllVlprOiqYjJVTuK-1sqT4qBeRXpAKS9qv/s320/48_02.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Добавьте и файл настроек в отдельную папку, но! Откройте его и поменяйте строку подключения к базе данных, вписав в соответствующее место имя папки "For Install" (секция [General], параметр ConnectionString, переменная Data Source=...). Внимание: "For Install" и "For install" - разные папки!!! Имейте это ввиду. Чтобы избежать ошибок, лучше скопируйте абсолютный путь из проводника Windows.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Еще раз пробуем запустить программу. На экран будет выведено предупреждение о некритической ошибке:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDjPqE7TwYPz5ZZ3EBwqpUdaykBcN4xwKzv7dBuexyfH0vyBIH3jgzXJKPXYCVHe9OaNc6QKKgwd0jaR9FZKV902CUJILLfEfHjXGkPK55-_rVPaw0F_WjQ2xaeYC3TT7y3f8Bm_c8DWWJ/s1600/48_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="87" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDjPqE7TwYPz5ZZ3EBwqpUdaykBcN4xwKzv7dBuexyfH0vyBIH3jgzXJKPXYCVHe9OaNc6QKKgwd0jaR9FZKV902CUJILLfEfHjXGkPK55-_rVPaw0F_WjQ2xaeYC3TT7y3f8Bm_c8DWWJ/s320/48_03.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Что означает термин "некритическая ошибка"? Лишь то, что программа после нажатия кнопки "ОК" продолжит свою работу. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Копируем файлы языковой поддержки *.lng, и пытаемся начать вводить данные, но программа не может найти базу данных в месте, указанном строкой подключения, и предлагает нам сделать это самостоятельно (некритическая, а досадная :-) ошибка):</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY0qh4LNb42d0nScNy96I1IZaz8xvr0S6QT6c7eb6rI5czDtDfYkJygS3sUg24sGb6IWnQM5VOV8NN9etWYnXLN5urqD225jLYCM34Eo7FubwVvj0feR2hyWaKQDkufOlnrxpibWobKRU6/s1600/48_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY0qh4LNb42d0nScNy96I1IZaz8xvr0S6QT6c7eb6rI5czDtDfYkJygS3sUg24sGb6IWnQM5VOV8NN9etWYnXLN5urqD225jLYCM34Eo7FubwVvj0feR2hyWaKQDkufOlnrxpibWobKRU6/s320/48_04.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Копируем "слона" - базу данных. </div>
<div class="separator" style="clear: both; text-align: left;">
Запуск программы наконец-то будет удачным. Но это - на первый взгляд. Попробуйте вызвать справку любым известным способом (меню или F1), и Вы получите следующее (уже системное) сообщение об ошибке:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwPc1H6ti5Q7alfEFOSOaQWU_mFfuSAwwlarMygS5WqRpHy8EhVJ8BTV4tTAx_VjZqnTvrMdOz0pQJpcWKna4KPykxVklOfnrfL0Lgr38BVcvd1N2oylNViZSNJt6r-qVCNJjiBocsOGGz/s1600/48_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="129" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwPc1H6ti5Q7alfEFOSOaQWU_mFfuSAwwlarMygS5WqRpHy8EhVJ8BTV4tTAx_VjZqnTvrMdOz0pQJpcWKna4KPykxVklOfnrfL0Lgr38BVcvd1N2oylNViZSNJt6r-qVCNJjiBocsOGGz/s320/48_05.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Значит, нужно и файл справки RASHODHELP.HLP тоже взять с собой в папку "For Install".</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
И тут Вы подумали: "Ну, теперь-то уж, наверное, все..." и ошиблись. Справка не реагирует на кнопку "Содержание". Зря что ли мы так долго над ней бились? Нет, нужно захватить с собой файл RashodContext.cnt.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В итоге, в отдельной папке "For Install" должен собраться набор из следующих файлов:</div>
<ul>
<li>Файл программы Rashod.exe</li>
<li>Файл библиотеки ProDelphiLyb.dll</li>
<li>Файл настроек Rashod.ini</li>
<li><span style="text-align: left;">Файлы языковой поддержки Rus.lng и Eng.lng.</span></li>
<li>Файл базы данных Rashod.mdb</li>
<li>Файл справки RASHODHELP.HLP</li>
<li>Файл содержания справки RashodContext.cnt</li>
</ul>
<div>
Это и будет исходный материал для написания инсталлятора программы, подготовкой которого мы займемся на следующем уроке.</div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-92118030942444880132012-06-04T14:24:00.000+04:002012-06-04T14:24:40.525+04:00Урок 47. Подскажите как...? Пожалуйста - Справочная система.Программа "Расходы", о разработке которой я рассказывал последнее время, обросла уже достаточным функционалом, чтобы решать поставленные перед ней задачи. И даже немного больше - я показал, как сделать локализацию интерфейса. А те, кто "следил за развитием событий", надеюсь, нашли для себя что-то новое и интересное. Дописывать и оптимизировать программу можно далее до бесконечности, например: для удобства учета данных из разных источников можно придумать БД и написать механизм импорта из нее в основной массив данных; можно озадачиться и решить вопрос с учетом кредитов и других долговых обязательств.<br />
<br />
Но вряд ли при этом будет интересно повторять здесь описание одних и тех же приемов или толковать еще раз о тех компонентах, о которых уже говорилось.<br />
<br />
<a name='more'></a><br />
<br />
В связи с этим я предполагаю осветить еще две-три темы, чтобы это наше детище (или любое другое) было еще больше похоже на настоящий серьезный продукт и к юбилейному 50-му уроку завершить свой рассказ об этой разработке.<br />
<br />
Чего в первую очередь недостает программе "Расходы"? Что происходит в других программах при нажатии кнопки "F1"?<br />
<br />
Вызывается справочная система.<br />
<br />
Забегая вперед, покажу, что для программы "Расходы" такая система тоже создана, и выглядит она как любая другая:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQhyphenhyphenk97GD-6LuxujpVKtwX8ofAkxjpCGGEHkTiclzindFrRLFNfd_9mlmiFsUXHbEe2UnmtOR_Rc6B5j1y3A0CvRlb_F5LizINxShyhMLMOrIwglMW-ZCkc-j9MJdYRec1cOEybQLDqpM9/s1600/47_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQhyphenhyphenk97GD-6LuxujpVKtwX8ofAkxjpCGGEHkTiclzindFrRLFNfd_9mlmiFsUXHbEe2UnmtOR_Rc6B5j1y3A0CvRlb_F5LizINxShyhMLMOrIwglMW-ZCkc-j9MJdYRec1cOEybQLDqpM9/s640/47_01.png" width="540" /></a></div>
<br />
Например, страничка описывающая интерфейс, о котором велась речь на <a href="http://pro-delphi.blogspot.com/2012/05/46.html">прошлом уроке</a>, выглядит вот так:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQUpPySfx2GZ99VGkn-Wg2V3GZq-TxKAmkAeM0SObCv-ax40Y1ICV0Z7ZydCU1a4HmPojesZErNe8XcjD4IBXK6zgtov33nguqAWALT7gGbGjpOgJXhiic20tnlsADgVIUOuTRkmDKtCzM/s1600/47_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQUpPySfx2GZ99VGkn-Wg2V3GZq-TxKAmkAeM0SObCv-ax40Y1ICV0Z7ZydCU1a4HmPojesZErNe8XcjD4IBXK6zgtov33nguqAWALT7gGbGjpOgJXhiic20tnlsADgVIUOuTRkmDKtCzM/s320/47_02.png" width="313" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Любознательные спросят: в чем прок? Программа анонсировалась как программа для учета домашних расходов, стало быть - для себя любимого. Зачем же самому себе Help писать?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Самому себе, конечно, незачем, верно. Но при разработке больших систем без описания, руководства пользователя и справочной системы не обойтись. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Поэтому придется поупражняться в текстовом редакторе.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Наберите текст в том же MS Word (или Open Office, Google Docs), включите в него рисунки, сделайте красивое форматирование, выделив заголовки разных уровней, списки и т.п.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Сохраните файл в формате rtf.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both;">
На следующем шаге нужно придать документу (rtf) определенную структуру: разбить на разделы, снабдить служебными сносками, установить перекрестные ссылки. Таким образом, файл будет подготовлен к компиляции в программе <b id="internal-source-marker_0.5509472023695707" style="font-weight: normal;"><span style="font-family: Arial; font-size: 16px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;">Microsoft Help Workshop</span></b>, которую можно бесплатно скачать на сайте производителя.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Раздел справки представляет собой фрагмент справочной системы, отображаемой в окне программы Winhelp. <br />
<br />
Текст каждого раздела должен находиться на определенной странице документа (заканчиваться символом "разрыв станицы"). <br />
<br />
<b id="internal-source-marker_0.5509472023695707" style="font-weight: normal;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">После того как текст разделов будет набран, нужно, используя сноски, пометить заголовки разделов справочной информации (сноски используются компилятором справочной системы в процессе преобразования rtf-файла в hlp-файл справки). </span></b><br />
<div>
<b style="font-weight: normal;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;"><br /></span></b></div>
<div>
<b><span style="font-family: Arial; font-size: 16px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;">Для того чтобы пометить заголовок раздела сноской, нужно установить курсор перед первой буквой заголовка раздела и из меню Вставка выбрать команду Сноска. В открывшемся диалоговом окне "Сноски" в группе "Вставить сноску" нужно установить переключатель в положение обычную, а в группе "Нумерация" - в положение другая. В поле ввода номера сноски следует ввести символ # и нажать кнопку ОК.</span></b><b><span style="font-weight: normal;"><img height="246px;" src="https://lh6.googleusercontent.com/BdUcDOhPLE1smS5sygAyifRGzBwsGFNQXzQ3Mba52soMvxAQzKKO5v36LlTwNuUTJ3tjS5wZp6tlglG1yNYHlzyQaIG6Zkiyw-yI0VxS4EOlhVvkvA" width="302px;" /></span></b><br />
<div dir="ltr" style="font-weight: normal;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="51"></col><col width="572"></col></colgroup><tbody>
<tr style="height: 0px;"><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Сноска</span></div>
</td><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Назначение</span></div>
</td></tr>
<tr style="height: 0px;"><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">#</span></div>
</td><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Задает идентификатор раздела справки, который может использоваться в других разделах для перехода к помеченному этой сноской разделу.</span></div>
</td></tr>
<tr style="height: 0px;"><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">$</span></div>
</td><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Задает имя раздела, которое будет применятся для идентификации раздела справки в списке поиска и в списке просмотренных тем во время использования справочной системы.</span></div>
</td></tr>
<tr style="height: 0px;"><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><div dir="ltr" style="margin: 0pt 0.5pt;">
<span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">K</span></div>
</td><td style="border: 1px solid rgb(0, 0, 0); padding: 0px; vertical-align: top;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Задает список ключевых слов, при выборе которых из списка диалога поиска осуществляется переход к разделу справки, заголовок которой помечен этой сноской.</span></td></tr>
</tbody></table>
</div>
<b>
</b></div>
<div>
Лучше, чтобы идентификатор раздела справки начинался с префикса IDH_. В этом случае во время компиляции rtf-файла будет проверена корректность ссылок на разделы справки и выведена информация о несоответствиях.<br />
<br />
Должно получаться примерно так:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix6CtpuYmaWkDs3AkbQ-Rm-_dvjo5ctxlqNEC9ropGtTq0V8atBtPJFP8MzRLiaTxXP6GdK_-PHwO0hahr4ePLLvA4HOSrGeIDma0wRABgyiC7xuDxxpqBOkE3u0lw7S4SOd7atZUD_iTv/s1600/47_03.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix6CtpuYmaWkDs3AkbQ-Rm-_dvjo5ctxlqNEC9ropGtTq0V8atBtPJFP8MzRLiaTxXP6GdK_-PHwO0hahr4ePLLvA4HOSrGeIDma0wRABgyiC7xuDxxpqBOkE3u0lw7S4SOd7atZUD_iTv/s400/47_03.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF1USW75VlF_8aH70W8y-cO_r3eZtHhrj5vxaeEj63qcJjscmL8Yrum7czsVr9DVNfOMGEF5hSu_v79gqQ9dlH8n6b0uzKHk7DJWxJT4AaLB7JUdeh0dTmvemQKQSw_dfgXqJYj-oB2zpJ/s1600/47_04.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF1USW75VlF_8aH70W8y-cO_r3eZtHhrj5vxaeEj63qcJjscmL8Yrum7czsVr9DVNfOMGEF5hSu_v79gqQ9dlH8n6b0uzKHk7DJWxJT4AaLB7JUdeh0dTmvemQKQSw_dfgXqJYj-oB2zpJ/s1600/47_04.png" /></a></div>
<div>
<br />
<div class="separator" style="clear: both;">
<b style="font-weight: normal; text-align: -webkit-auto;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;"><br /></span></b></div>
Во время подготовки текста справочной информации, слово-ссылку, при выборе которой происходит переход к другому разделу справки, следует подчеркнуть двойной линией. Сразу за ссылкой, без пробела, поместить идентификатор раздела справки, к которому должен быть выполнен переход (например "Далее" и "Назад"). </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTlBojzBQxWBQQanvStoyx6qaW3NQ_PkOq79VSSUYykVQGxuGzKBRif6Y9cx1-2mrKJWF8JBx8ZS2zov8vxB9znxONg_5_rl1ABaI9kdtdqp_OSt1On7hjWlFTiqbFFPHywkj5oqcbnY8V/s1600/47_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="524" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTlBojzBQxWBQQanvStoyx6qaW3NQ_PkOq79VSSUYykVQGxuGzKBRif6Y9cx1-2mrKJWF8JBx8ZS2zov8vxB9znxONg_5_rl1ABaI9kdtdqp_OSt1On7hjWlFTiqbFFPHywkj5oqcbnY8V/s640/47_05.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Вставленный идентификатор необходимо оформить как скрытый текст. При этом рисунки, как и текст, можно использовать для ссылки на другой раздел. Для этого рисунок соответствующим образом подчеркивается, а контекст раздела помещается сразу после рисунка. На предыдущим рисунке приведен вид окна редактора текста во время подготовки файла справочной информации. Слово "Назад" помечено как ссылка на другой (предыдущий) раздел справки, обозначенный сноской # и имеющий идентификатор IDH_000.<br />
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;"><br /></span></b></div>
Теперь откройте программу HCW.EXE скачанную из даунлод центра корпорации Майкрософт.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMeWxUDz3IxJMjnHuXwog4MOtQW-O7pSHjj7ydgEAlmBy7s_2wTvzIxFfGii53qLwLAmiG3RRxwPJmzhdVwWDp53M8r4ikmT53dYNzOKr3hGs44OTWRc46GmTNxJbU-LSV_aq4OV54PfH/s1600/47_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMeWxUDz3IxJMjnHuXwog4MOtQW-O7pSHjj7ydgEAlmBy7s_2wTvzIxFfGii53qLwLAmiG3RRxwPJmzhdVwWDp53M8r4ikmT53dYNzOKr3hGs44OTWRc46GmTNxJbU-LSV_aq4OV54PfH/s320/47_06.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both;">
Основным файлом компилятора является файл проекта. </div>
<br />
Для того чтобы приступить к созданию справочной системы, нужно из меню File выбрать команду New, затем в открывшемся диалоговом окне New указать тип создаваемого файла - Help Project.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdx59_bgYu-_KujiR882p8PDcaiQpkBe7N_8W_UVyc7xePot7RhN7qbdI5-W978nS1Xe7NigiHRPT2jNJvqghUOVx5PRHMKj9wbVKXSGPvLy2XIogCqU5Z8aXj109aYwkNUnVMG03F3BbH/s1600/47_07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdx59_bgYu-_KujiR882p8PDcaiQpkBe7N_8W_UVyc7xePot7RhN7qbdI5-W978nS1Xe7NigiHRPT2jNJvqghUOVx5PRHMKj9wbVKXSGPvLy2XIogCqU5Z8aXj109aYwkNUnVMG03F3BbH/s1600/47_07.png" /></a></div>
<br />
<br />
Далее следует выбрать папку, где находится программа, для которой создается справочная система, и где уже должен находится файл документа справочной системы (rtf-файл). Затем в поле Имя файла нужно ввести имя файла проекта справочной системы. Файлу проекта присваивается расширение HPJ.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilaPpEPwY4Cww-E_aooHDPnEEryZE2DHCOVvFVxBIx5uhPjJcZMzaVvN28RIvAORysHWjDHGZxCw8hVwNjHde4H5zjGMZSvqVCL-YrA1UCP3IEBwBrSfrB0nGMn_PSafWiNrGZPXHGnB_Q/s1600/47_08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilaPpEPwY4Cww-E_aooHDPnEEryZE2DHCOVvFVxBIx5uhPjJcZMzaVvN28RIvAORysHWjDHGZxCw8hVwNjHde4H5zjGMZSvqVCL-YrA1UCP3IEBwBrSfrB0nGMn_PSafWiNrGZPXHGnB_Q/s320/47_08.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В папке с проектом у меня уже имеется файл проекта готовой справочной системы RashodHelp.hpj. Поэтому, чтобы проиллюстрировать процесс создания такого файла, я не буду "ломать" и "комкать" уже имеющийся файл, а создам новый - RashodNew.hpj. В окне программы будет выведено следующее сообщение:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFO3FfNcIQn8xd-lCZP1J43A9s-zCCta4qvgJcjRsFd0MEmRlQlgN4MqFIFoOaohdry8j-lxkwX09EQksIqn-U27IJVxg9yOKM1foUOuPd8mmXJ2zC01pvs1l2xIW3k8ppMKmYn5wPIb2U/s1600/47_09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="305" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFO3FfNcIQn8xd-lCZP1J43A9s-zCCta4qvgJcjRsFd0MEmRlQlgN4MqFIFoOaohdry8j-lxkwX09EQksIqn-U27IJVxg9yOKM1foUOuPd8mmXJ2zC01pvs1l2xIW3k8ppMKmYn5wPIb2U/s400/47_09.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Нажмите справа кнопку "Files", и затем - кнопку "Add", чтобы добавить созданный ранее файл rtf:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8SQRQTd6RLExkFQ457AXwtuebiLCuxEXYNPHp4YgBYDorNie9aov_Gva9xrHwtMX4mqsuyzK0eq4yNDwi9T0uqAemT88nyAjlF9Piezqq3RYqOCJUUPA7cgN1aLLtgaZfmsVe1FPYzBJk/s1600/47_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8SQRQTd6RLExkFQ457AXwtuebiLCuxEXYNPHp4YgBYDorNie9aov_Gva9xrHwtMX4mqsuyzK0eq4yNDwi9T0uqAemT88nyAjlF9Piezqq3RYqOCJUUPA7cgN1aLLtgaZfmsVe1FPYzBJk/s400/47_10.png" width="362" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
В результате этих действий в окне проекта появится раздел [FILES], в котором будет указано имя файла справочной информации. Если справочная информация распределена по нескольким файлам, то операцию добавления файла нужно повторить. Для того чтобы задать характеристики главного окна справочной системы, надо в окне проекта нажать кнопку Windows. Появится окно Create a window. В поле Create a window named надо ввести main.<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;"><br /></span></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://lh4.googleusercontent.com/0PAWD5y3w7M0qEpJNfTaTLfBYHK3G-QJbCEgMqHErSm1SF1YK1bSCeKFMEax6GPz59h-yKRfgiObEVmOziLJ-mbk7KleUxkmG4CzX6WoJun8gw15iA" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="196px;" src="https://lh4.googleusercontent.com/0PAWD5y3w7M0qEpJNfTaTLfBYHK3G-QJbCEgMqHErSm1SF1YK1bSCeKFMEax6GPz59h-yKRfgiObEVmOziLJ-mbk7KleUxkmG4CzX6WoJun8gw15iA" width="212px;" /></a></div>
<br />
<b style="font-weight: normal;"><span style="font-family: Arial; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Нажмите "ОК" и заполните свойства окна (Window Properties), как показано ниже:</span></b>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghwlt4Y_kjJC50hf3GRl91JE8_dv6lisiqFmsYJoz8O9PBhgUT5SdY7_E0lJuG45oxR1ohc2pUJM_srdXC34Y6P9cBMXI_NwgjwH0pb-iprMIAstn17zVIfr52wd2bjtl8wE7aE4XOGhQd/s1600/47_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghwlt4Y_kjJC50hf3GRl91JE8_dv6lisiqFmsYJoz8O9PBhgUT5SdY7_E0lJuG45oxR1ohc2pUJM_srdXC34Y6P9cBMXI_NwgjwH0pb-iprMIAstn17zVIfr52wd2bjtl8wE7aE4XOGhQd/s320/47_11.png" width="320" /></a></div>
<br />
Затем перейдите на вкладку "Position" и нажмите кнопку "Auto Sizer", позиционируйте окно, как считаете нужным, и нажмите "ОК". Проверьте вкладку "Color", используя которую, Вы можете поменять цвет фона будущего окна справки.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<b style="font-weight: normal; text-align: -webkit-auto;"><img height="325px;" src="https://lh5.googleusercontent.com/nFNPADB-pqP99T8EBah88vcITPLoJtrsOc-qG_jmr2CN8bf08Hir_MZjPcMxYypVcvm3V94KEIp4WO_hMYr-cIxjLbedMhPtFONHc2-EWlqJuA4K9g" width="350px;" /><img height="215px;" src="https://lh6.googleusercontent.com/saFuYeDubLUK7w5Y6LATSGB81dNsbegERP7gezCTG5mgJl2Gw7HZbJLKdiRL1jG9qwO8NnqWCqLg8PHXPymhhoIJ7Cv-KZtaX_FsqpcEzv8tGeiqmA" width="240px;" /><img height="325px;" src="https://lh5.googleusercontent.com/gFrg61sBGNWJ2ULNQFBxVtiyOZ9On_glD0f6Q6OUbYK3aT_QJNvc4eXQIJK3c2VC4BHS1buNiLKHyiA6fhDJFuTxUMs54Gyw-Ecz6eBsUpHDKR9X2w" width="350px;" /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;">Файл проекта таким образом пополнится еще одним разделом:</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh99tetDFwyydrHzPrwuyKAoow0nnZ0WTsIHmjl3x80CYho26UigLNARdubf8LY44Z0wacLcBqJ-jOCD2xwvQd8hHIdaiJLtH6fAhd6EFWqlEtLTdi0yXhfmf1VbvfBxP0PyHtrH_DwMHlq/s1600/47_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh99tetDFwyydrHzPrwuyKAoow0nnZ0WTsIHmjl3x80CYho26UigLNARdubf8LY44Z0wacLcBqJ-jOCD2xwvQd8hHIdaiJLtH6fAhd6EFWqlEtLTdi0yXhfmf1VbvfBxP0PyHtrH_DwMHlq/s320/47_12.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
Чтобы программа, использующая справочную систему, могла получить доступ к конкретному разделу справочной информации, нужно определить числовые значения для идентификаторов разделов, т.е. установить соответствия между номерами контекстов управляющих элементов приложения и разделами справочной системы. Чтобы это сделать, надо в окне проекта справочной системы нажать кнопку Map, в результате чего откроется диалоговое окно Map. <div>
<br /></div>
<div>
В этом окне с помощью кнопки "Add" добавляется новое соответствие, а кнопкой "Rеmove" - производится удаление существующего. Соответствия отображаются построчно в виде пар значений, разделенных знаком равенства. Слева находится контекст раздела справочного файла (сноска, обозначенная символом #), а справа - номер контекста управляющего элемента приложения.<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;">В результате должна получиться вот такая картина:</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtWQJq399f1RFgq_h4pSmsNCXgAgnhByGtn0rq_zvJTJy1a8dQpZzPZWL6MdaDWIIopuc2KhwqAN6-jMCW0m4fQkLSk479Z0qHPYO4D1LBhVyR0VDUBzCktWJqjIY0dmWq4c388kpGoqRU/s1600/47_14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtWQJq399f1RFgq_h4pSmsNCXgAgnhByGtn0rq_zvJTJy1a8dQpZzPZWL6MdaDWIIopuc2KhwqAN6-jMCW0m4fQkLSk479Z0qHPYO4D1LBhVyR0VDUBzCktWJqjIY0dmWq4c388kpGoqRU/s640/47_14.png" width="468" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Чтобы посмотреть, как будет выглядеть готовая справка, воспользуйтесь меню File - Compile вместо кнопки "Save and Compile", установив отметку Automatically display help file in WinHelp when done (Автоматически показывать созданную справочную систему по завершении компиляции).<div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
Если все сделано правильно, на экран будет выведено окно справочной системы, а в окне программы Microsoft Help Workshop - сообщение о результатах обработки.</div>
<div>
<br /></div>
<div>
Можно было бы поставить точку, но лучше потратить еще немного времени и сделать "Содержание". Для этого создайте новый файл, на сей раз - Help Contents
(Cnt), укажите соответствующий ему только что полученный файл hlp и заголовок. А затем, используя кнопки справа, добавьте заголовки и топики:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8cw5Uh3WUeWEMC3opA3J_kLHUeR6XDu6iEQhmuVoTEm2fzx8n_gXt9h2MP8fq6A4vA41fi-hlOcIDnq72Ig3B9q38zIWkhb51Ex7KiudKCkmREFwkI1r6jjFYd0uTv1Ru7Dldwz8ZgtX/s1600/47_16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL8cw5Uh3WUeWEMC3opA3J_kLHUeR6XDu6iEQhmuVoTEm2fzx8n_gXt9h2MP8fq6A4vA41fi-hlOcIDnq72Ig3B9q38zIWkhb51Ex7KiudKCkmREFwkI1r6jjFYd0uTv1Ru7Dldwz8ZgtX/s640/47_16.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
После создания cnt-файла его нужно добавить в проект справки. Для этого надо открыть ранее созданный проект справочной системы, нажать кнопку Options и в открывшемся окне на вкладке Files в поле Contents file ввести имя cnt-файла.<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizqsYyyZPaSLNZ2Ohq3lJJH1CYXZuHX1Es6oDFFp4oO4iLzBV5_a8oQU3wFPEumMAmFX5brKkbfIvHcfe-8GeeeF9bm5kcA1Ti-XDS_iHdbmBAaNt99maajbooA1slYC0Rr7-yr-CHN9w8/s1600/47_17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizqsYyyZPaSLNZ2Ohq3lJJH1CYXZuHX1Es6oDFFp4oO4iLzBV5_a8oQU3wFPEumMAmFX5brKkbfIvHcfe-8GeeeF9bm5kcA1Ti-XDS_iHdbmBAaNt99maajbooA1slYC0Rr7-yr-CHN9w8/s400/47_17.png" width="383" /></a></div>
<div>
<br /></div>
<div>
<br /><div class="separator" style="clear: both; text-align: left;">
<b style="font-weight: normal; text-align: -webkit-auto;"><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
* * *</div>
<div>
<br />
Ну, а теперь - о главном: как все это использовать в программе.<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В модуле формы Main укажите:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">uses</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">..., WinHelpViewer, ...;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
и добавьте для начала обработчик пункта меню "Справка":</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TMainFrm.N12Click(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> WinHelp(MainFrm.Handle,'RASHODHELP.HLP',HELP_CONTEXT,0);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<br /></div>
Таким образом, при выборе пункта меню "Справка" или нажатии <f1> на экран будет выводиться файл справки в том виде, в котором он представлен на самом первом изображении.</f1><br />
<br />
Все это хорошо, но наша конечная цель отстоит на один шаг дальше - нам нужна контекстно-зависимая справка. Что это значит? Это означает, что когда фокус (курсор) находится на определенном элементе управления, нам интересно прочитать в справке именно про этот элемент, а не получать на экран стартовую страницу или перечень заголовков в виде содержания.<br />
<br />
Поэтому, предлагаю открыть в конструкторе любой пункт меню, например: "Отчетные формы - Оборотная ведомость" и... в инспекторе объектов, в свойстве HelpContxt указать номер контекста (в моем случае это номер 15, см. раздел [MAP] файла *.hlp)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXPZ6zU-JHboR_0iwfXgUffJW8Yzt4kh5ogzK1wFcZlfhAOVG1njGAfVm_iNo2XgY0t3BJbocGQQhThM5_502AzI05pTzAWL-Jo-qyWuiGKWMW7HSW4TLYHYA_kfeYf7-6Z-ZNLuY2723o/s1600/47_18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXPZ6zU-JHboR_0iwfXgUffJW8Yzt4kh5ogzK1wFcZlfhAOVG1njGAfVm_iNo2XgY0t3BJbocGQQhThM5_502AzI05pTzAWL-Jo-qyWuiGKWMW7HSW4TLYHYA_kfeYf7-6Z-ZNLuY2723o/s640/47_18.png" width="640" /></a></div>
<br />
Чтобы убедиться, что мы на правильном пути, нужно компилировать проект Rashod, открыть пункт меню "Отчетные формы - Оборотная ведомость" и нажать F1. Результат - справка по работе с оборотной ведомостью:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1U7R6qIuGStL_sS-F96Dq0uE-Ecz-zqeuJHZdr0N-IutQ76tk4K6QcCALxDDAQXZVCPtWNOlIwPvzjGzUAN_KfqjShBj4qUfcAu0YP0g9COx9X2ZLetPvAEUTIj8qo8vF100LPq3F3uC-/s1600/47_19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1U7R6qIuGStL_sS-F96Dq0uE-Ecz-zqeuJHZdr0N-IutQ76tk4K6QcCALxDDAQXZVCPtWNOlIwPvzjGzUAN_KfqjShBj4qUfcAu0YP0g9COx9X2ZLetPvAEUTIj8qo8vF100LPq3F3uC-/s400/47_19.png" width="400" /></a></div>
<br />
Чтобы завершить начатый путь, нужно сделать большой файл справки, разбив его на множество разделов, и затем каждому элементу управления назначить номер контекста.<br />
<br />
<br />
<br />
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br /></div>
</div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-1293520266596418302012-05-31T16:35:00.000+04:002012-05-31T16:40:29.100+04:00Урок 46. Обобщающий графический отчетПройдет время. Скажем, год. База данных наполнится цифрами...<br />
И Вам обязательно захочется взглянуть на некую общую картину. А мне, как и прежде, уже сейчас хочется рассказать о практическом применении тех компонентов, о которых мы пока не говорили.<br />
<br />
<a name='more'></a><br /><br />
Кроме того, графические отчеты, которые я представлял ранее были псевдо статичны, т.е. не менялись после их составления. Новый отчет будет практически динамическим, т.е. он, конечно, не в реальном масштабе времени будет строиться (не та задачка у нас), но будет изменять свой вид по желанию оператора, как сейчас говорят - будет интерактивен.<br />
<br />
Добавьте в проект новую форму (<a href="http://pro-delphi.blogspot.com/2011/10/23.html">как это сделать рассказано в нескольких предыдущих уроках</a>)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfbM9cRUEJ-LoZDUhYBoigAimjimTYvaetUbgVULYhkcwCGBfz8scMJJgrz1vohPVK1NG9CYMyxiC8MG0J5J8cdUppZRHKHDCzAbyJ0hjSo2P4RLnHe1LTdfrpDPyfUD8TBzSWP0QeC4au/s1600/46_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfbM9cRUEJ-LoZDUhYBoigAimjimTYvaetUbgVULYhkcwCGBfz8scMJJgrz1vohPVK1NG9CYMyxiC8MG0J5J8cdUppZRHKHDCzAbyJ0hjSo2P4RLnHe1LTdfrpDPyfUD8TBzSWP0QeC4au/s640/46_06.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
назвав ее AnalizTrendsForm, а модуль формы соответственно AnalizTendenc.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Большинство компонентов (кнопки, панели, TPageControl и TDBGridEh) нам знакомы, вряд ли стоит подробно останавливаться на них. К тому же, если компонент не обрабатывается в коде, то я даже не имею привычки его переименовывать.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
К таким же привычным компонентам можно отнести TADOQuery, которому советую не забыть назначить свойство Connection. Любознательно-наблюдательные читатели спросят, а, может быть, даже упрекнут меня в том, что вместо этого компонента можно использовать имеющийся на главной форме TempQuery. Да, можно. Внесите изменения (оптимизируйте) самостоятельно :-)</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqbcqRMqaLnXEdrgETeD_CNeeKrijYUncSf1mh0G2M2iHaGGq7LYEf5RgDrcKW7xjuriPZuZyGCJkaUx8zyXvWzkyica51Uxx5G7gnCp2K16r71DYipHPcjw39Y2wiUPi7vDqPAQqRXZ_A/s1600/46_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqbcqRMqaLnXEdrgETeD_CNeeKrijYUncSf1mh0G2M2iHaGGq7LYEf5RgDrcKW7xjuriPZuZyGCJkaUx8zyXvWzkyica51Uxx5G7gnCp2K16r71DYipHPcjw39Y2wiUPi7vDqPAQqRXZ_A/s640/46_10.png" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Таким же привычным компонентом уже стал, наверное, компонент <a href="http://pro-delphi.blogspot.com/2012/04/41.html">TChart</a>.</div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGIoKcUSPg58cYO_EIZQ4y4miqd5qgKVdXIrjvynraD-LYKZl9cUMrh7ZIWAIu3gBXYmJfE1XVFAY7Y_lHF_QOzarOvsgKdqgATsvE2gLQqxTHvIBxTSy0mIFBEH5LQGAzHNwliUZaMYAk/s1600/46_09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="467" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGIoKcUSPg58cYO_EIZQ4y4miqd5qgKVdXIrjvynraD-LYKZl9cUMrh7ZIWAIu3gBXYmJfE1XVFAY7Y_lHF_QOzarOvsgKdqgATsvE2gLQqxTHvIBxTSy0mIFBEH5LQGAzHNwliUZaMYAk/s640/46_09.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Одним из новых для нас компонентов будет компонент TStringGrid. Чуть позже будет понятно, почему я выбрал именно его.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjcCHpWYhvphTc_fmqJCGGk-I_BeqitzVrtFamt-VcCQM3vVhNg4NwQa18hAhGow1086J5B8ERcosmCvz9qX0keHC1VCYVWOytvpyk1YBxeEneZw0ivNhE8Ue33cbU7pe3c7VMifXb6GMp/s1600/46_08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjcCHpWYhvphTc_fmqJCGGk-I_BeqitzVrtFamt-VcCQM3vVhNg4NwQa18hAhGow1086J5B8ERcosmCvz9qX0keHC1VCYVWOytvpyk1YBxeEneZw0ivNhE8Ue33cbU7pe3c7VMifXb6GMp/s640/46_08.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
И уж совсем "неожиданным" будет использование компонента TClientDataSet, на котором я хотел бы остановиться немного подробнее.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5_OyeSV2o9izopmjBkQtYOEdElKLwnvUvDDgzXZVC5_-03qaEr-DtbaGWuA7jprPoJ7YzOTsqpHKIfK6HzLkQW98k7FTL8B6nt5ZeZ-zPY1BH8jeNNIgOvi9BOxlYS5f3mD2KbMBvU0tl/s1600/46_07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5_OyeSV2o9izopmjBkQtYOEdElKLwnvUvDDgzXZVC5_-03qaEr-DtbaGWuA7jprPoJ7YzOTsqpHKIfK6HzLkQW98k7FTL8B6nt5ZeZ-zPY1BH8jeNNIgOvi9BOxlYS5f3mD2KbMBvU0tl/s640/46_07.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
По сути этого компонента можно сказать, что это невизуальный компонент, аналогичный обычному массиву. Все, что в него попадает, остается в ОЗУ, поэтому работает он очень быстро. Но, есть одна особенность. Являясь стандартным компонентом, устанавливаемым совместно со средой обработки, этот компонент не будет работать без наличия в системе специальной библиотеки <a href="http://www.dll.ru/dll/10977.html">midas.dll</a>, что удивительно. Этот файл необходимо расположить в каталоге C:\Windows\System32, а затем зарегистрировать его с помощью "Выполнить: regsvr32 c:\windows\system32\midas.dll". Если Вы не знаете, как это сделать, <a href="https://docs.google.com/open?id=0B0V8YJCT7hdLQ0N0QU5maEd6OE0">скачайте исполняемый файл</a>, разместите его в том же каталоге, куда скачали Dll, и дважды щелкните по этому файлу. Все произойдет само собой :-) </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Не убирайте далеко в корзину и навсегда файл библиотеки. Ближе к финалу данной темы я планирую рассказать о создании (мы же с Вами - взрослые люди) настоящего инсталлятора для программы "Расходы", так что файл библиотеки нам еще пригодится.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Самое "страшное" на сей раз позади, "продолжаем разговор", как говорит любимый мультяшный герой Карлсон.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Слиентский датасет можно создать (наполнить полями) в конструкторе, но ниже я покажу, как это сделать программно.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Чтобы данные, размещенные в CDS были видны в таблице, расположенной на одноименной вкладке на форме, необходимо оформить связь:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRBszGQ4ZBMBwTNybrjJNDhJNZ_OeV7vn1RXNFlSJo5b56gQ51iCi3adALILScx_qZ5nGnbZAVhEHJQqJPZJkRRYpECle4TVh9RNPMnn8RGz2uTsplioKbAYbZHp89NdvPAelXGu2CezUf/s1600/46_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRBszGQ4ZBMBwTNybrjJNDhJNZ_OeV7vn1RXNFlSJo5b56gQ51iCi3adALILScx_qZ5nGnbZAVhEHJQqJPZJkRRYpECle4TVh9RNPMnn8RGz2uTsplioKbAYbZHp89NdvPAelXGu2CezUf/s640/46_11.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
В качестве вступительного слова при переходе к коду программы, приведу почти знакомый фрагмент, включающий традиционные процедуры создания формы, закрытия ее и некоторые другие:<br />
<br />
<br />
<span style="color: orange;"> private</span><br />
<span style="color: orange;"> { Private declarations }</span><br />
<span style="color: orange;"> procedure MyClose();</span><br />
<span style="color: orange;"> procedure Prepare();</span><br />
<span style="color: orange;"> public</span><br />
<span style="color: orange;"> { Public declarations }</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">var</span><br />
<span style="color: orange;"> AnalizTrendsForm: TAnalizTrendsForm;</span><br />
<span style="color: orange;"> MyColor: array[1..16] of TColor = (</span><br />
<span style="color: orange;"> clMaroon</span><br />
<span style="color: orange;"> ,clGreen</span><br />
<span style="color: orange;"> ,clYellow</span><br />
<span style="color: orange;"> ,clOlive</span><br />
<span style="color: orange;"> ,clNavy</span><br />
<span style="color: orange;"> ,clPurple</span><br />
<span style="color: orange;"> ,clTeal</span><br />
<span style="color: orange;"> ,clLime</span><br />
<span style="color: orange;"> ,ClGray</span><br />
<span style="color: orange;"> ,clRed</span><br />
<span style="color: orange;"> ,clSilver</span><br />
<span style="color: orange;"> ,clBlue</span><br />
<span style="color: orange;"> ,ClFuchsia</span><br />
<span style="color: orange;"> ,clAqua</span><br />
<span style="color: orange;"> ,clMoneyGreen</span><br />
<span style="color: orange;"> ,clSkyBlue</span><br />
<span style="color: orange;"> );</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">implementation</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">{$R *.dfm}</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">Uses Main;</span><br />
<span style="color: orange;"><br /></span><br />
<br />
<div style="color: orange;">
// Традиционный набор процедур</div>
<div style="color: orange;">
procedure TAnalizTrendsForm.FormCreate(Sender: TObject);</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
StringGrid1.ColWidths[0]:=50;</div>
<div style="color: orange;">
StringGrid1.ColWidths[1]:=150;</div>
<div style="color: orange;">
PageControl1.ActivePage:=TabSheet1;</div>
<div style="color: orange;">
Prepare();</div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
procedure TAnalizTrendsForm.FormClose(Sender: TObject; var Action: TCloseAction);</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
Action:= caFree;</div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
procedure TAnalizTrendsForm.FormKeyDown(Sender: TObject; var Key: Word;</div>
<div style="color: orange;">
Shift: TShiftState);</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
case Key of // Start Case</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
VK_ESCAPE:</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
MyClose;</div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
else</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
End; // End case</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
procedure TAnalizTrendsForm.MyClose();</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
close;</div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
procedure TAnalizTrendsForm.PrDOkButton1Click(Sender: TObject);</div>
<div style="color: orange;">
begin</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
if (ModalResult=1) OR (ModalResult=2)</div>
<div style="color: orange;">
then</div>
<div style="color: orange;">
Begin</div>
<div style="color: orange;">
MyClose;</div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
<div style="color: orange;">
end;</div>
<div style="color: orange;">
<br /></div>
А ниже - то, ради чего все это затевалось:<br />
<br />
Процедура очистки графика:<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizTrendsForm.BitBtn1Click(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Очистка графика</span><br />
<span style="color: orange;"> With Chart1 do</span><br />
<span style="color: orange;"> While SeriesCount>0 do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> Series[0].Free;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;">end;</span><br />
<div>
<br /></div>
<div>
Здесь я должен пояснить основную идею, которую должна реализовать данная форма:</div>
<div>
в список слева (StringGrid) нужно вывести все счета, по которым были обороты в текущем году. При щелчке по строке этого списка программа должна добавлять в график новую серию, раскрасив ее в один из 16 оговоренных в массиве MyColor цветов и изменив масштаб отображения.</div>
<div>
<br /></div>
<div>
Использованная в процедуре создания формы подпрограмма Prepare() по сути - наполняет список счетов в StringGrid (обратите внимание, что здесь, как и в следующей процедуре прописан <a href="http://pro-delphi.blogspot.com/2012/03/38.html">механизм обработки ошибок</a>):</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TAnalizTrendsForm.Prepare();</span></div>
<div>
<span style="color: orange;">Var</span></div>
<div>
<span style="color: orange;"> MyStr: String;</span></div>
<div>
<span style="color: orange;"> j,i: Integer;</span></div>
<div>
<span style="color: orange;"> ErrKod: Integer; // Код ошибки</span></div>
<div>
<span style="color: orange;"> ErrMes: String; // Описание ошибки</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">Label</span></div>
<div>
<span style="color: orange;"> ErrorsLab; // Метка, после которой начинается текст обработчика ошибок</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Стартовые значения</span></div>
<div>
<span style="color: orange;"> ErrKod:=0;</span></div>
<div>
<span style="color: orange;"> ErrMes:='Операция завершена успешно';</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Определить количество задействованных счетов в течение года</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Active:=False;</span></div>
<div>
<span style="color: orange;"> ADOQuery1.SQL.Clear;</span></div>
<div>
<span style="color: orange;"> MyStr:='SELECT Accounts.ID, Accounts.Name ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'FROM Accounts INNER JOIN Main ON Accounts.ID = Main.D ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'WHERE (((Accounts.Analiz)=True) AND ((Year([Main]![MyDate]))='+FormatDateTime('yyyy',(now()))+')) ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'GROUP BY Accounts.ID, Accounts.Name';</span></div>
<div>
<span style="color: orange;"> ADOQuery1.SQL.Add(MyStr);</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Active:=True;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Есть ли данные за текущий год?</span></div>
<div>
<span style="color: orange;"> If Not (ADOQuery1.RecordCount>0)</span></div>
<div>
<span style="color: orange;"> then</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"> ErrKod:=1;</span></div>
<div>
<span style="color: orange;"> ErrMes:='Список пуст:'+CR+'Нет счетов, задействованных в текущем году';</span></div>
<div>
<span style="color: orange;"> GoTo ErrorsLab;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Создать CDS</span></div>
<div>
<span style="color: orange;"> CDS.Active:=False;</span></div>
<div>
<span style="color: orange;"> CDS.FieldDefs.Clear;</span></div>
<div>
<span style="color: orange;"> CDS.FieldDefs.add('Месяц',ftInteger,0,False); // Будут вписаны номера месяцев от 1 до 12</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // В цикле по созданному массиву создаем поля - коды счетов в заголовках</span></div>
<div>
<span style="color: orange;"> // а также - наполняем сетку, отображающую набор счетов</span></div>
<div>
<span style="color: orange;"> j:=0;</span></div>
<div>
<span style="color: orange;"> while (Not ADOQuery1.Eof) do</span></div>
<div>
<span style="color: orange;"> Begin</span></div>
<div>
<span style="color: orange;"> CDS.FieldDefs.add(ADOQuery1.FieldByName('ID').AsString,ftInteger,0,False);</span></div>
<div>
<span style="color: orange;"> StringGrid1.Cells[0,j]:=ADOQuery1.FieldByName('ID').AsString;</span></div>
<div>
<span style="color: orange;"> StringGrid1.Cells[1,j]:=ADOQuery1.FieldByName('Name').AsString;</span></div>
<div>
<span style="color: orange;"> StringGrid1.RowCount:=StringGrid1.RowCount+1;</span></div>
<div>
<span style="color: orange;"> inc(j);</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Next;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"> StringGrid1.RowCount:=StringGrid1.RowCount-1; // Одна строка лишняя</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> CDS.CreateDataSet; // Создание датасета</span></div>
<div>
<span style="color: orange;"> CDS.IndexFieldNames:='Месяц';</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Наполнение CDS</span></div>
<div>
<span style="color: orange;"> // Номера месяцев</span></div>
<div>
<span style="color: orange;"> For j:=1 to 12 do</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"> CDS.Insert;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Обнуление CDS</span></div>
<div>
<span style="color: orange;"> for i := 0 to CDS.FieldCount - 1 do</span></div>
<div>
<span style="color: orange;"> CDS.Fields[i].Value:=0;</span></div>
<div>
<span style="color: orange;"> CDS.FieldByName('Месяц').Value:=j;</span></div>
<div>
<span style="color: orange;"> CDS.Post;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Данные</span></div>
<div>
<span style="color: orange;"> CDS.First;</span></div>
<div>
<span style="color: orange;"> While Not CDS.Eof do</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Active:=False;</span></div>
<div>
<span style="color: orange;"> ADOQuery1.SQL.Clear;</span></div>
<div>
<span style="color: orange;"> MyStr:='SELECT Month([MyDate]) AS Mes, Sum(Main.Summa) AS [MySum], Accounts.Name, Accounts.ID ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'FROM Accounts INNER JOIN Main ON Accounts.ID = Main.D ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'WHERE (((Accounts.Analiz)=True) AND ((Year([Main]![MyDate]))='+FormatDateTime('yyyy',(now()))+')) ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'GROUP BY Month([MyDate]), Accounts.Name, Accounts.ID, Year([Main]![MyDate]) ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'HAVING (((Month([MyDate]))='+CDS.FieldByName('Месяц').AsString+'))';</span></div>
<div>
<span style="color: orange;"> ADOQuery1.SQL.Add(MyStr);</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Active:=True;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> While Not ADOQuery1.Eof do</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"> CDS.Edit;</span></div>
<div>
<span style="color: orange;"> CDS.FieldByName(ADOQuery1.FieldByName('ID').AsString).Value:=ADOQuery1.FieldByName('MySum').Value;</span></div>
<div>
<span style="color: orange;"> CDS.Post;</span></div>
<div>
<span style="color: orange;"> ADOQuery1.Next;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> CDS.Next;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Настройка сетки</span></div>
<div>
<span style="color: orange;"> DBGridEh1.Columns.AddAllColumns(True);</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> exit; // Нужен, если нет необходимости выводить сообщение об успешном завершении операции</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">ErrorsLab:</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> case ErrKod of // Start Case</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> 0:</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Сообщение об успешном завершении</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.TitleString:='...';</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.MessageType:=mtInformation;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"> else</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Сообщения об ошибках</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.TitleString:='Ошибка ('+IntToStr(ErrKod)+')';</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.MessageType:=mtError;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"> End; // End case</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.MessageString:=ErrMes;</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.Buttons:=[mbOk];</span></div>
<div>
<span style="color: orange;"> MainFrm.MyMessenger.ShowMessage;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
</div>
<br />
А теперь - обработчик клика по сетке (списку счетов):<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizTrendsForm.StringGrid1Click(Sender: TObject);</span><br />
<span style="color: orange;">Var</span><br />
<span style="color: orange;"> i: Integer;</span><br />
<span style="color: orange;"> ErrKod: Integer; // Код ошибки</span><br />
<span style="color: orange;"> ErrMes: String; // Описание ошибки</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">Label</span><br />
<span style="color: orange;"> ErrorsLab; // Метка, после которой начинается текст обработчика ошибок</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Стартовые значения для</span><br />
<span style="color: orange;"> ErrKod:=0;</span><br />
<span style="color: orange;"> ErrMes:='Операция завершена успешно';</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Если в сетке ничего нет, то - выход</span><br />
<span style="color: orange;"> If StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row]=''</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> exit;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Первая из возможных проверок (количество графиков не может быть более 16)</span><br />
<span style="color: orange;"> If Chart1.SeriesCount=15</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> ErrKod:=1;</span><br />
<span style="color: orange;"> ErrMes:='Возможно создать только 16 графиков';</span><br />
<span style="color: orange;"> GoTo ErrorsLab;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Добавление новой серии</span><br />
<span style="color: orange;"> With Chart1 do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> i:=SeriesCount;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> AddSeries(TLineSeries.Create(Self));</span><br />
<span style="color: orange;"> Series[i].Name := 'Serija_'+IntToStr(i);</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> With Chart1.Series[i] do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> CDS.First;</span><br />
<span style="color: orange;"> While not CDS.Eof do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> Add(CDS.FieldByName(StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row]).Value, CDS.FieldByName('Месяц').Value, MyColor[i+1]);</span><br />
<span style="color: orange;"> CDS.Next;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> exit; // Нужен, если нет необходимости выводить сообщение об успешном завершении операции</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">ErrorsLab:</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> case ErrKod of // Start Case</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> 0:</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Сообщение об успешном завершении</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.TitleString:='...';</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.MessageType:=mtInformation;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> else</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Сообщения об ошибках</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.TitleString:='Ошибка ('+IntToStr(ErrKod)+')';</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.MessageType:=mtError;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> End; // End case</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> MainFrm.MyMessenger.MessageString:=ErrMes;</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.Buttons:=[mbOk];</span><br />
<span style="color: orange;"> MainFrm.MyMessenger.ShowMessage;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<div>
<br />
В результате Вы получите вот такие графики, если станете щелчком выбирать строки в списке (в моей БД сохранилась информация только за первые два месяца :-) ):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidBV0VGmt6L-VJSUWjgCejIwRmC9nLlcRC_OE-4kGGkhQJdoJ6eRHB3iv5PHhREoW-FXDcxBs1Vm19gLqpT9xwf-itJMAscKp7LzGCqDyqopt7c5ogTQglAwj4tyy4ABafUVz4PnXeLjKR/s1600/46_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidBV0VGmt6L-VJSUWjgCejIwRmC9nLlcRC_OE-4kGGkhQJdoJ6eRHB3iv5PHhREoW-FXDcxBs1Vm19gLqpT9xwf-itJMAscKp7LzGCqDyqopt7c5ogTQglAwj4tyy4ABafUVz4PnXeLjKR/s400/46_12.png" width="400" /></a></div>
<br /></div>
<br />
Я надеюсь, что дал достаточно пояснений в комментариях (//). Если же у кого-то остались вопросы - <a href="http://pro-delphi.blogspot.com/p/blog-page.html">пишите</a>.<br />
<br />
<div>
<br /></div>
<div>
<br /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-54016929691148390852012-05-15T15:08:00.001+04:002012-05-15T15:08:59.929+04:00Обновление файла ProDelphiLibСегодня я получил вот такое сообщение:<br />
<br />
<i>"</i><i><span style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: arial, sans-serif; font-size: 13px;">Boris прокомментировал:</span></i><div>
<span style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: arial, sans-serif; font-size: 13px;"><br /></span></div>
<div>
<i>Здравствуйте, Александр! Я подписался на рассылку Ваших уроков про Delphi. Потихоньку изучаю. На вашем блоге есть раздел "Скачать". Так вот у меня такой вопрос. Как скачать библиотеку компонентов ProDelphiLibPack. Я скачал ProDelphiLibPack.dpk, пытался установить но появляется ошибка - Delphi не находит MyComponentsPack. Как установить библиотеку. Поясните, пложалуйста. "</i><div>
<span style="color: #222222; font-family: arial, sans-serif; font-size: x-small;"><br /></span></div>
<div>
Должен признаться, что просмотрел этот грешок. Библиотеки компонентов, как провода в углу, оставленные без присмотра, моментально превращаются в узловатый ком. Если не принять мер сразу, распутать такой ком бывает потом очень сложно.</div>
<div>
<br /></div>
<div>
Поэтому я выражаю свою благодарность Boris (жаль, мне не известно настоящее имя), с одной стороны.</div>
<div>
<br /></div>
<div>
С другой стороны, получая такие письма, осознаешь, что эта затея приносит кому-то пользу. Это - положительные эмоции. Спасибо.<br /><br />
Я подправил некоторые некорректности в ресурсах библиотеки и обновил архив.<br />
<br />
Ссылка для скачивания последней версии библиотеки: <a href="https://docs.google.com/open?id=0B0V8YJCT7hdLVS1TTlJnTnhMOWs">https://docs.google.com/open?id=0B0V8YJCT7hdLVS1TTlJnTnhMOWs</a> - добро пожаловать! Получить доступ к этому архиву Вы так же можете со страницы <a href="http://pro-delphi.blogspot.com/p/blog-page_20.html">"Скачать"</a>.<br />
<br />
Надеюсь, что все будет теперь в полном порядке.<br />
<br />
<h4>
Об установке библиотеки. </h4>
1. Скачайте <a href="https://docs.google.com/open?id=0B0V8YJCT7hdLVS1TTlJnTnhMOWs">архив библиотеки ProDelphiLib</a>.<br />
2. Распакуйте его в папку, например C:\Program Files\Borland\BDS\4.0\lib\Pro-Delphi<br />
3. Откройте в среде разработки Delphi файл ProDelphiLibPack.bdsproj, полученный из архива в папку на шаге 2.<br />
4. Выполните компиляцию и установку пакета:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQgL4FwVyUWCN1pVA4Jt_Ci7wE3wjqE4jIfOb1NelPQxGSsSJq3L0HcAe1eNaaUTLOMP_jnnksQOwIYah3Gf8qD1Ly2PoEAcW5ZHNFAQII0ONUXoEQjP_OFSvlrRR4TyN7jKw9G7_qQlEG/s1600/46_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQgL4FwVyUWCN1pVA4Jt_Ci7wE3wjqE4jIfOb1NelPQxGSsSJq3L0HcAe1eNaaUTLOMP_jnnksQOwIYah3Gf8qD1Ly2PoEAcW5ZHNFAQII0ONUXoEQjP_OFSvlrRR4TyN7jKw9G7_qQlEG/s320/46_01.png" width="253" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
в окне Project Manager кликните правой кнопкой на файле .bpl и в контекстном меню выберите "Install".</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
При успешном окончании процесса, Вы получите вот такое сообщение:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8Ec1ka9xlZ2oaqwnMVVDTcBhcOQ_9hlq82ZxCXQpkWqD6nuqLUfZLO5glOx0WTutDyvsYeG5FtQoOnEyC0GkZlNFDwiH4k_ELtWUjpyn5LRHa-FcgkXl-bTSgFxuzMD00o16kRTtXKGTE/s1600/46_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8Ec1ka9xlZ2oaqwnMVVDTcBhcOQ_9hlq82ZxCXQpkWqD6nuqLUfZLO5glOx0WTutDyvsYeG5FtQoOnEyC0GkZlNFDwiH4k_ELtWUjpyn5LRHa-FcgkXl-bTSgFxuzMD00o16kRTtXKGTE/s640/46_02.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
5. Обязательно нажмите кнопку сохранить:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9SrvuaIYDG1essiqYGDLvxOHt8g5amXR1YfbK1lAbhynuCjgJnejrtkeZCMo-BT9XomAMVPy6P9j37FUjP8aL5LgqaCj7DjdHgp7M09DFVewKOnE5q1RskgWtzgLcBcDPnNNsxJfyk5CV/s1600/46_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9SrvuaIYDG1essiqYGDLvxOHt8g5amXR1YfbK1lAbhynuCjgJnejrtkeZCMo-BT9XomAMVPy6P9j37FUjP8aL5LgqaCj7DjdHgp7M09DFVewKOnE5q1RskgWtzgLcBcDPnNNsxJfyk5CV/s1600/46_03.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
6. Выполните меню File - Close All.</div>
<br />
7. Проверьте наличие установленных компонентов, для чего выполните меню Component - Install Packages:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHDuHEYGyT-TPcpEb6ZPCH2K8S5A7Y-aPzgcFylaXOICKODSs-BkyiCOiCb4qjX67avIRmUi2jK5W53leEJhnJVOaooOMmSpIP6qktbnsiIQarfdsRLLD9azl_O6r4i-oMpsNt4Vpn17g8/s1600/46_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHDuHEYGyT-TPcpEb6ZPCH2K8S5A7Y-aPzgcFylaXOICKODSs-BkyiCOiCb4qjX67avIRmUi2jK5W53leEJhnJVOaooOMmSpIP6qktbnsiIQarfdsRLLD9azl_O6r4i-oMpsNt4Vpn17g8/s400/46_04.png" width="400" /></a></div>
<br />
<br />
8. Проверьте наличие пути к файлам установленной библиотеки, выполнив меню Tools-Options- Library Win32:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigRf1eQf8CQUjzpPHU5GGliQCB_zJYViLn-NqN6z82Rr6ryC1r2tfDUSze6qCN86uV44HuZoprZcfMouC8ciptnJHazt_Zm2x6L7SuRQfJ0PY17-UZ2qd8tlzr4fvLNopnDfp6OFGwHozJ/s1600/46_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="412" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigRf1eQf8CQUjzpPHU5GGliQCB_zJYViLn-NqN6z82Rr6ryC1r2tfDUSze6qCN86uV44HuZoprZcfMouC8ciptnJHazt_Zm2x6L7SuRQfJ0PY17-UZ2qd8tlzr4fvLNopnDfp6OFGwHozJ/s640/46_05.png" width="640" /></a></div>
<br />
Если путь к библиотеке (см. пункт 2) в списке Directories отсутствует, то нажмите кнопку с многоточием, найдите нужную папку и добавьте ее кнопкой "Add".<br />
<br />
<br /></div>
</div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-52928830736168283522012-05-14T13:55:00.000+04:002012-05-14T14:07:04.073+04:00Урок 45. Отчет по группам затрат. Детализация<div class="separator" style="clear: both; text-align: left;">
Как ты думаешь, дорогой читатель, для чего я <a href="http://pro-delphi.blogspot.com/2012/05/43.html">так много времени посвятил</a> каким-то абстрактным группам затрат?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Ответ прост: чтобы получить еще пару удобных отчетов.</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<a name='more'></a><br />
<br />
<div class="separator" style="clear: both; text-align: left;">
Добавьте в проект новую форму, назвав ее AnalizGroupFrm, как уже описывалось ранее, не забыв прописать имя модуля в Uses главной формы и исключив ее из автоматически загружаемых в установках проекта.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZUzG5f49whMLUch0d_S9lsqzPWPO49Exb3CK8WzBo9ZXMIvVIDa-DVI22LuP30QZLeA-AeurRc89rAPdsXj2xiT-59yajgq1tC3v5JWHulwV04xXZaztGXSo1i9ofqJQr6lYM0BmLitwt/s1600/45_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZUzG5f49whMLUch0d_S9lsqzPWPO49Exb3CK8WzBo9ZXMIvVIDa-DVI22LuP30QZLeA-AeurRc89rAPdsXj2xiT-59yajgq1tC3v5JWHulwV04xXZaztGXSo1i9ofqJQr6lYM0BmLitwt/s640/45_01.png" width="640" /></a></div>
<br />
На второй вкладке расположена сетка с итогами в футере:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvdJYZmu05su8DYGyF_GteuuhBs0HUEh2KcdjBKsb2vU_Wd9w0WsUpJ1HsOtFCP9Fa0Ibc3mfG3NZP5dQiuvxWgKu2cXZ-gmxkY03QEsTuE-1zpx6ENk4PqCnGb95H4zECFY29qZn4x7AD/s1600/45_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvdJYZmu05su8DYGyF_GteuuhBs0HUEh2KcdjBKsb2vU_Wd9w0WsUpJ1HsOtFCP9Fa0Ibc3mfG3NZP5dQiuvxWgKu2cXZ-gmxkY03QEsTuE-1zpx6ENk4PqCnGb95H4zECFY29qZn4x7AD/s400/45_02.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В разделе implementation модуля формы (я назвал его AnalizGroup) имеются уже привычные процедуры, которые я здесь приведу (для порядку), но особого интереса они уже для нас не представляют, как привычные:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">implementation</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">{$R *.dfm}</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">Uses Main</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> , AnalizGroupDetails</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TAnalizGroupFrm.FormCreate(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Создание формы</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Задание начальных значений для контролов - дат</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Date_N.Value:=Now()-365;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Date_K.Value:=Now()+1;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Назначение подключения запросу</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQuery1.Connection:=MainFrm.ADOConnection1;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TAnalizGroupFrm.FormClose(Sender: TObject; var Action: TCloseAction);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Освобождение памяти</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Action:= caFree;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TAnalizGroupFrm.FormKeyDown(Sender: TObject; var Key: Word;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Shift: TShiftState);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> case Key of // Start Case Обработка нажатий клавиш</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> VK_ESCAPE:</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyClose;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> else</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> End; // End case</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TAnalizGroupFrm.MyClose();</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">Begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Close;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TAnalizGroupFrm.ButtonClickExecuteExecute(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Акшн, обрабатывающий события нажатия кнопок (ОК и Cancel) при наличии</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if (ModalResult=1) OR (ModalResult=2)</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyClose;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
<br />
Еще одна знакомая вещь - использование<a href="http://pro-delphi.blogspot.com/2012/03/34-dll.html"> ранее разработанной функции</a> экспорта в Excel:<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizGroupFrm.N_ExportClick(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"> Try</span><br />
<span style="color: orange;"> MainFrm.ExportTo(PCHAR('Лист 1'), DBGridEh1, MainFrm.XLApp, PCHAR('Затраты по группам'), PCHAR('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));</span><br />
<span style="color: orange;"> Finally</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;">end;</span><br />
<br />
А теперь - собственно алгоритм получения результатов:<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizGroupFrm.Button1Click(Sender: TObject);</span><br />
<span style="color: orange;">Var MyStr: String;</span><br />
<span style="color: orange;"> j: Integer;</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Наполнение грида</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Подготовка запроса</span><br />
<span style="color: orange;"> ADOQuery1.Active:=False;</span><br />
<span style="color: orange;"> ADOQuery1.SQL.Clear;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Формирование строки запроса</span><br />
<span style="color: orange;"> MyStr:='SELECT ExpenseGroup.ID, ExpenseGroup.Name, Sum(Main.Summa) AS [MySum] ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'FROM (Accounts INNER JOIN (ExpenseGroup INNER JOIN ExpenseAcc ON ExpenseGroup.ID = ExpenseAcc.IDGroup) ON Accounts.ID = ExpenseAcc.IDAcc) INNER JOIN Main ON Accounts.ID = Main.D ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'WHERE (((Accounts.Val)='+IntToStr(MySelect.MySel_IDVal)+') ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'AND ((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#)) ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'GROUP BY ExpenseGroup.ID, ExpenseGroup.Name ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'ORDER BY Sum(Main.Summa) DESC';</span><br />
<span style="color: orange;"> ADOQuery1.SQL.Add(MyStr);</span><br />
<span style="color: orange;"> ADOQuery1.Active:=True;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Сопоставление полученных в запросе данных сериям на графике</span><br />
<span style="color: orange;"> j:=1;</span><br />
<span style="color: orange;"> With Series1 do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> Clear;</span><br />
<span style="color: orange;"> while (Not ADOQuery1.Eof) do</span><br />
<span style="color: orange;"> Begin</span><br />
<span style="color: orange;"> if j>16</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> j:=1</span><br />
<span style="color: orange;"> else</span><br />
<span style="color: orange;"> j:=j+1;</span><br />
<span style="color: orange;"> Add(ADOQuery1.FieldByName('MySum').Value, ADOQuery1.FieldByName('Name').Text, MyColor[j]);</span><br />
<span style="color: orange;"> ADOQuery1.Next;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> Active:=True;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<div>
<br /></div>
<div>
Пару слов о строке, формирующей запрос.</div>
<div>
Составить необходимый запрос проще в среде MS ACCESS:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhra2TXU-sNMsU1jGvFWukR4BAQj754bmpFJq4X9aNM16wvA5YBqCvn1vcmXnTEnfFD_fjyzAQyEPUToUcO9p7Yq4vUdIPKM4CdofkYatMG9fcKCaJo7jyrmDuXy-1Su_33aHQYaGPscnx/s1600/45_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhra2TXU-sNMsU1jGvFWukR4BAQj754bmpFJq4X9aNM16wvA5YBqCvn1vcmXnTEnfFD_fjyzAQyEPUToUcO9p7Yq4vUdIPKM4CdofkYatMG9fcKCaJo7jyrmDuXy-1Su_33aHQYaGPscnx/s640/45_03.png" width="640" /></a></div>
<div>
<br /></div>
<div>
В результат запроса должны быть отобраны записи, счета Дебета в таблице Main, которых присутствуют в корреляционной таблице ExpenseAcc.</div>
<div>
Запрос содержит два условия:</div>
<div>
<ul>
<li>Выбираются записи по одной из валют (поле Val)</li>
<li>Выбираются записи в интервале дат</li>
</ul>
<div>
Условия отбора я указал не через переменные и параметры, на напрямую.</div>
</div>
<div>
Еще раз обращаю Ваше внимание, что даты в Access положено заключать в символы "#".</div>
<div>
Этот запрос - запрос с группировкой (интересует общая сумма по той или иной группе с учетом условий).</div>
<div>
<br /></div>
<div>
Теперь не сложно взять текст SQL из конструктора запросов Access и перенести его в среду разработки:</div>
<div>
<br /></div>
<div>
<div>
SELECT ExpenseGroup.ID, ExpenseGroup.Name, Sum(Main.Summa) AS MySum</div>
<div>
FROM ExpenseGroup INNER JOIN ((Accounts INNER JOIN ExpenseAcc ON Accounts.ID = ExpenseAcc.IDAcc) INNER JOIN Main ON Accounts.ID = Main.D) ON ExpenseGroup.ID = ExpenseAcc.IDGroup</div>
<div>
WHERE (((Accounts.Val)=1) AND ((Main.MyDate)>=#1/1/2011# And (Main.MyDate)<#1/1/2012#))</div>
<div>
GROUP BY ExpenseGroup.ID, ExpenseGroup.Name</div>
<div>
ORDER BY Sum(Main.Summa) DESC;</div>
</div>
<div>
<br /></div>
<div>
Обратите внимание, что постфикс "DESC" указывает на обратный порядок сортировки по полю сумм.</div>
<div>
<br /></div>
<div>
В итоге должен получиться ответ на интересующий вопрос: список затрат по группам:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikcLwLo0R9LxKFdWtcV9RMLUSXTpgz-ZCzIHK3jG1NCLr6nZDGHotgItejeFlrd9FM9zEZb_6fdvHfIP3YYTXzX1Nt_17I90vQz14mkq-VCx39inkvdeH6_Id8NMW1OD0ZfuS8Z1Xm9caA/s1600/45_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikcLwLo0R9LxKFdWtcV9RMLUSXTpgz-ZCzIHK3jG1NCLr6nZDGHotgItejeFlrd9FM9zEZb_6fdvHfIP3YYTXzX1Nt_17I90vQz14mkq-VCx39inkvdeH6_Id8NMW1OD0ZfuS8Z1Xm9caA/s1600/45_04.png" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Точно такую же табличку нужно получить в Grid на форме.</div>
<div>
Остается только подставить текст запроса в переменную MyStr, указав вместо кода валюты и даты начала и конца периода обработанные (преобразованные) значения соответствующих переменных и контролов:</div>
<div>
<br /></div>
<div>
IntToStr(MySelect.MySel_IDVal) - код валюты преобразуется в строковое значение,</div>
<div>
FormatDateTime('mm/dd/yyyy',Date_N.Value) - значение даты из контрола Date_N преобразуется в строковое значение приемлемого формата.</div>
<div>
<br /></div>
<div>
В итоге, должна получиться вот такая картинка:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_OWdGtE8VXN2RpFuc3ab5DxiCBF8q1J5ZVxoVGHuYzrPdhy0AmswocVeispxcHgAaIcLFyNjDuy1Ch2YVLsiVuhWasJHOC4AqcNhE-CaBsxY11CesBJwfgv_Yh76a3YWLDLWzeFF69qz6/s1600/45_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_OWdGtE8VXN2RpFuc3ab5DxiCBF8q1J5ZVxoVGHuYzrPdhy0AmswocVeispxcHgAaIcLFyNjDuy1Ch2YVLsiVuhWasJHOC4AqcNhE-CaBsxY11CesBJwfgv_Yh76a3YWLDLWzeFF69qz6/s400/45_05.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Но, любого бухгалтера (или вторую половинку:-)) такая диаграмма устроит мало. Вот, чтобы она не огорошила Вас вопросом: "А чего это такой большой зеленый столбик? Откуда эта огромная сумма? Куда делись деньги? А?" Чтобы Вам не пришлось краснеть у руководства и мямлить: "Так, ведь, это ж за целый год...", предлагаю подумать, как использовать кнопку "Детализация", которую я предусмотрел на форме.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Вы можете использовать текущую форму, а можете создать другую, очень похожую.</div>
<div class="separator" style="clear: both; text-align: left;">
Пусть это будет небольшим домашним заданием. </div>
<div class="separator" style="clear: both; text-align: left;">
Картинка, к которой можно стремиться, примерно вот такая:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGZnjNRMWv6UTWEdLItGmt0X31dcdQ35DdRKkdUg2lMsN3kXXtbAjBpLF2ayryWiXfEZMxtq9jmt_U1tklveBF-XhCyTvmhdSWoshqYhu409NBxJyD6o9kSGAyDwBj_MprKCOSbPqu4M2y/s1600/45_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="422" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGZnjNRMWv6UTWEdLItGmt0X31dcdQ35DdRKkdUg2lMsN3kXXtbAjBpLF2ayryWiXfEZMxtq9jmt_U1tklveBF-XhCyTvmhdSWoshqYhu409NBxJyD6o9kSGAyDwBj_MprKCOSbPqu4M2y/s640/45_06.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div>
Имея детализированный отчет, Вы быстро можете ответить, из чего и в какой пропорции складываются затраты по той или иной группе.<br />
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<br />Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-41703456686685185112012-05-11T14:04:00.000+04:002012-05-11T14:27:20.477+04:00Урок 44. Drag & DropВ<a href="http://pro-delphi.blogspot.com/2012/05/43.html"> предыдущем уроке</a> я подробно рассказывал, как сделать интерфейс, позволяющий набирать в группу счета или удалять их из группы.<br />
<br />
Но, я всегда говорил и говорю теперь, что одну и ту же задачу можно решить множеством разных способов.<br />
<br />
Вот в подтверждение своих слов я и хочу еще раз остановиться на том же интерфейсе, но модернизировать его под использование технологии перетаскивания (Drag & Drop).<br />
<br />
<a name='more'></a><br /><br />
Для начала нужно удалить некоторые элементы управления:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwmakRxxM90ByYXqoFlHp_iXtE-IWGunC7pR1PIw31rmefLfo5PeIOSKVYwvb6ZgLnzluI_niLg7psSE5uXPmdjQjApu0DNzHMEyIhu7XOzAbzVMfPw9kySeqdm9BG5RymGQWDXS_vRh34/s1600/44_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwmakRxxM90ByYXqoFlHp_iXtE-IWGunC7pR1PIw31rmefLfo5PeIOSKVYwvb6ZgLnzluI_niLg7psSE5uXPmdjQjApu0DNzHMEyIhu7XOzAbzVMfPw9kySeqdm9BG5RymGQWDXS_vRh34/s400/44_01.png" width="400" /></a></div>
<br />
- DBGridEh3 и пару кнопок со стрелками. Компонент TDataSource по имени DataSourceAcc тоже не понадобится.<br />
<br />
Соответственно, удалить и процедуры обработки (я воспользовался символами комментариев, поскольку, это не тот случай, когда "ломать - не строить: душа не болит"):<br />
<br />
<br />
// procedure DBGridEh3DblClick(Sender: TObject);<br />
// procedure Button2Click(Sender: TObject);<br />
// procedure Button1Click(Sender: TObject);<br />
<div>
<br /></div>
<div>
и</div>
<div>
<br /></div>
<div>
<div>
{</div>
<div>
procedure TGroupsFrm.Button1Click(Sender: TObject);</div>
<div>
begin</div>
<div>
MyAdd();</div>
<div>
end;</div>
<div>
<br /></div>
<div>
procedure TGroupsFrm.DBGridEh3DblClick(Sender: TObject);</div>
<div>
begin</div>
<div>
MyAdd();</div>
<div>
end;</div>
<div>
<br /></div>
<div>
procedure TGroupsFrm.Button2Click(Sender: TObject);</div>
<div>
begin</div>
<div>
MyDelete;</div>
<div>
end;</div>
<div>
}</div>
</div>
<div>
<br /></div>
<br />
На место удаленной сетки добавьте компонент TListBox, выровняв его как и прежде по правому краю:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8q3Tsqyyuwse5JrG_YsG3HYqHo2KnHyYs7C4aZJHERKrL7fCQxaQEj8iXoDX5MCSAWMqpIIjP6WQCtVRrvrDRZrd4oYQ0KSj6Rtv7JV_z1FRveejEER_vu-pMWZESPKL8VfafTq10Iooz/s1600/44_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8q3Tsqyyuwse5JrG_YsG3HYqHo2KnHyYs7C4aZJHERKrL7fCQxaQEj8iXoDX5MCSAWMqpIIjP6WQCtVRrvrDRZrd4oYQ0KSj6Rtv7JV_z1FRveejEER_vu-pMWZESPKL8VfafTq10Iooz/s400/44_02.png" width="400" /></a></div>
<br />
(как в конструктор в детстве играю, ей Богу :-) )<br />
<br />
Напишите новую процедуру, которая наполнит ListBox значениями:<br />
<br />
<br />
<span style="color: orange;">Procedure TGroupsFrm.ListBoxRefresh();</span><br />
<span style="color: orange;">Var</span><br />
<span style="color: orange;"> i: Integer;</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Очистка списка</span><br />
<span style="color: orange;"> For i:=0 to ListBox1.Items.Count-1 do</span><br />
<span style="color: orange;"> ListBox1.Items.Delete(0); // Это важно - удалять всегда только 0-ой элемент</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Наполнение ListBox</span><br />
<span style="color: orange;"> With MainFrm.ADOTableAcc do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // В источнике произведены изменения (присвоено новое значение</span><br />
<span style="color: orange;"> // признаку Groups, по которому настроен фильтр,</span><br />
<span style="color: orange;"> // поэтому необходимо вновь запросить данные из источника</span><br />
<span style="color: orange;"> Requery();</span><br />
<span style="color: orange;"> First;</span><br />
<span style="color: orange;"> While not eof do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> ListBox1.Items.Add(FieldByName('Name').AsString);</span><br />
<span style="color: orange;"> next;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;">end;</span><br />
<br />
<span style="color: red;">Обратите внимание</span>, что<br />
<br />
1. Подсчет элементов списка ведется от нуля до количества элементов списка минус единица. Например, если в списке 3 элемента, то их порядковые номера будут 0, 1, 2 (а не 1,2,3).<br />
2. Из ListBox1 удаляется в цикле только 0-ой элемент, поскольку после удаления очередного элемента список перестраивается. В нулевой позиции всегда располагается некий Item вплоть до последнего.<br />
<br />
В написанную ранее процедуру, обрабатывающую событие создания формы, необходимо добавить ListBoxRefresh, чтобы после появления формы на мониторе, список был наполнен значениями:<br />
<br />
<br />
procedure TGroupsFrm.FormCreate(Sender: TObject);<br />
Var MyStr: String;<br />
begin<br />
<br />
...<br />
<br />
MainFrm.ADOTableAcc.Filtered:=True;<br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> ListBoxRefresh(); // Урок 44</span><br />
<span style="color: orange;"><br /></span><br />
end;<br />
<br />
В инспекторе объектов установите свойства DragMode для DbGridEh2 и ListBox1 в dmAutomatic.<br />
<br />
Чтобы описываемый механизм Drag & Drop заработал, нужно написать обработчики двух событий для получателя, т.е. для .DBGridEh2 - сетки, отображающей участников группы:<br />
<br />
1. onDragOver,<br />
2. onDragDrop<br />
<br />
С первым все довольно просто:<br />
<br />
<br />
<span style="color: orange;">procedure TGroupsFrm.DBGridEh2DragOver(Sender, Source: TObject; X, Y: Integer;</span><br />
<span style="color: orange;"> State: TDragState; var Accept: Boolean);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"> Accept := Source = ListBox1;</span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<br />
<div>
- иными словами - назначается источник данных ListBox1 для сетки DBGridEh2, когда курсор будет находиться над последней.</div>
<div>
<br /></div>
<div>
Для второго события давайте ограничимся пока только сообщением:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.DBGridEh2DragDrop(Sender, Source: TObject; X, Y: Integer);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> Showmessage('Обработать перетаскивание');</span></div>
<div>
<span style="color: orange;">end;</span></div>
</div>
<div>
<br /></div>
<div>
И посмотрим, как это все работает.</div>
<div>
Если прижать мышкой один из пунктов в списке и потащить его на сетку (2), то курсор над сеткой изменится. Рядом с ним появится прямоугольник, что и будет означать, что получатель готов принять данные из источника в результате Drag & Drop. Отпустив кнопку мышки, получим сообщение на экран:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE00Ze3sgsNfDWPzV1nl_-HkxdSuJCxrhF2Oo57fvuNpzhYhsZkNIKCf6tjkxlqpa8IQ_E2Duj3qglLZuxzNGHSo-r49v9q-KdGe-TbXDzGKUbLMjq0uLwPkTjDgKm7kpT7Emrnu3zw6im/s1600/44_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE00Ze3sgsNfDWPzV1nl_-HkxdSuJCxrhF2Oo57fvuNpzhYhsZkNIKCf6tjkxlqpa8IQ_E2Duj3qglLZuxzNGHSo-r49v9q-KdGe-TbXDzGKUbLMjq0uLwPkTjDgKm7kpT7Emrnu3zw6im/s640/44_03.png" width="640" /></a></div>
<div>
<br /></div>
<div>
как результат обработки события DragDrop.</div>
<div>
<br /></div>
<div>
Значит, именно в обработчик этого события и нужно встроить механизм добавления нового участника группы.</div>
<div>
<br /></div>
<div>
Если Вы помните, то процедура добавления называется MyAdd. Может быть, вписать ее в обработчик, и - дело с концом? Не получится. Дело в том, что пока у нас была сетка на месте списка, мы были уверены в том, какой ID у выбранного в ней счета. В списке же присутствуют лишь названия счетов. Беда...</div>
<div>
<br /></div>
<div>
Как и всегда, для решения задачи есть несколько способов. Можно создать массив и наполнять его ID тех счетов, что ложатся в ListBox, "отгадывая" на обратном пути по позиции в списке ID счета в массиве.</div>
<div>
<br /></div>
<div>
Но я добавлю на форму компонент TADOQuery, назвав его TempQuery. И перепишу процедуру MyAdd:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.MyAdd();</span></div>
<div>
<span style="color: orange;">Var</span></div>
<div>
<span style="color: orange;"> MyStr: String;</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Найти счет по его названию // Урок 44</span></div>
<div>
<span style="color: orange;"> TempQuery.active:=False;</span></div>
<div>
<span style="color: orange;"> TempQuery.SQL.Clear;</span></div>
<div>
<span style="color: orange;"> TempQuery.Parameters.Clear;</span></div>
<div>
<span style="color: orange;"> MyStr:='SELECT Accounts.ID, Accounts.Groups ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'FROM Accounts ';</span></div>
<div>
<span style="color: orange;"> MyStr:=MyStr + 'WHERE (((Accounts.Name)='''+ListBox1.Items[ListBox1.ItemIndex]+'''))';</span></div>
<div>
<span style="color: orange;"> TempQuery.SQL.Add(MyStr);</span></div>
<div>
<span style="color: orange;"> TempQuery.Active:=True;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> If TempQuery.RecordCount>0</span></div>
<div>
<span style="color: orange;"> then</span></div>
<div>
<span style="color: orange;"> begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Добавление счета в группу</span></div>
<div>
<span style="color: orange;"> With ADOQueryMembers Do // Работаем с запросом</span></div>
<div>
<span style="color: orange;"> Begin</span></div>
<div>
<span style="color: orange;"> Insert; // Добавление новой записи</span></div>
<div>
<span style="color: orange;"> Try</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Присвоение значений полям</span></div>
<div>
<span style="color: orange;"> FieldByName('IDGroup').Value:=ADOTableGroups.FieldByName('ID').Value;</span></div>
<div>
<span style="color: orange;"> FieldByName('IDAcc').Value:=TempQuery.FieldByName('ID').Value;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Запись в таблицу-источник</span></div>
<div>
<span style="color: orange;"> Post;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Фиксирование признака в кодификаторе счетов (через временный запрос!)</span></div>
<div>
<span style="color: orange;"> TempQuery.Edit;</span></div>
<div>
<span style="color: orange;"> TempQuery.FieldByName('Groups').Value:=True;</span></div>
<div>
<span style="color: orange;"> TempQuery.Post;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Обновление данных</span></div>
<div>
<span style="color: orange;"> Requery();</span></div>
<div>
<span style="color: orange;"> finally</span></div>
<div>
<span style="color: orange;"> ListBoxRefresh; // Ранее здесь располагался оператор, обновляющий таблицу счетов</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;"> end;</span></div>
</div>
<div>
<br /></div>
<div>
Как говорится: "Найдите 10 отличий" :-)</div>
<div>
<br /></div>
<div>
Осталась самая малость: при исключении счета из группы - обновить список (справа), для чего достаточно в процедуру MyDelete вписать одну строку:</div>
<div>
<br /></div>
<div>
<div>
finally</div>
<div>
ADOQueryMembers.Requery();</div>
<div>
<span style="color: orange;"> ListBoxRefresh(); </span></div>
<div>
end;</div>
</div>
<div>
<br /></div>
<div>
Ну, а тем, кому не нравится таскать элементы списка, не полюбился им интерфейс на основе технологии Drag & Drop, мы обязаны (ВСЕГДА ПОМНИ О ПОЛЬЗОВАТЕЛЕ!) дать возможность добавлять счета в группу по двойному щелчку на элементе списка:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.ListBox1DblClick(Sender: TObject);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyAdd;</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-5590734990657400372012-05-10T16:58:00.001+04:002012-05-11T14:28:04.784+04:00Урок 43. Группировка затратОчевидно, что быстро получить картинку для оценки, например, всех коммунальных платежей за определенный период не сложно. Но будет ли информативна детализированная картинка?<br />
<br />
Чтобы было проще анализировать затраты и делать какие-то выводы, очень часто прибегают к группировке затрат (в бухгалтерском учете для этого служит механизм синтетических и аналитических счетов). Я сознательно не стал следовать этой логике, чтобы на первых порах непосвященным в учет пользователям было не страшно и понятно.<br />
<br />
Но теперь настало время объединить счета по какому-то признаку в группы, чтобы в дальнейшем давать обобщенное представление группы затрат.<br />
<br />
<a name='more'></a><br /><br />
Напомню, что <a href="http://pro-delphi.blogspot.com/2011/09/18.html">при создании базы данных</a> я заготовил пару таблиц:<br />
ExpenseGroup
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh471rBXOvYQMCjz-oulDEqA6-kJ5I_l02LJGPYqIa55FRqUU6zRSKCcGyZNKYujjnoB7PCUaZIKPx6bk5amPsgqU788HjCjVKct-7XOmEa0XalKk5mB1IavXvx5kMabyYbSted5dcxRNDx/s1600/43_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh471rBXOvYQMCjz-oulDEqA6-kJ5I_l02LJGPYqIa55FRqUU6zRSKCcGyZNKYujjnoB7PCUaZIKPx6bk5amPsgqU788HjCjVKct-7XOmEa0XalKk5mB1IavXvx5kMabyYbSted5dcxRNDx/s400/43_01.png" width="400" /></a></div>
<br />
и ExpenseAcc<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPUiKf4z_w7Se9MlT2jH-EBLUH6DvZm7TBok5wdj0JA5hpVpGVexu3VdPEi9DFkO8WfSI3XpX7IxbXBDntEeKXIGWDL-oaF-V96FkaiX7bDJ0Cod0kcLIxcNTZ1Sd5XLlErbZbu4gYhKB/s1600/43_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPUiKf4z_w7Se9MlT2jH-EBLUH6DvZm7TBok5wdj0JA5hpVpGVexu3VdPEi9DFkO8WfSI3XpX7IxbXBDntEeKXIGWDL-oaF-V96FkaiX7bDJ0Cod0kcLIxcNTZ1Sd5XLlErbZbu4gYhKB/s400/43_02.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
С первой таблицей - все просто: это - классический кодификатор (список, перечень) названий будущих групп. Ее можно сразу же предварительно заполнить для наглядности (мне в голову пришли вот такие группы, но у Вас могут быть иные):</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGQPI8VPq0qt9go4RcV9LahjvMI7ihOEFJwIb-XRILOIze0nmHvlnsLzAn52Kb0WdyM5OPo4cn0QZ4FGhs7jZo3FzPC406YzE-KyVgKGP0902wZoshAuHy3s9RqWtZElFrMYf3B3gVS635/s1600/43_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGQPI8VPq0qt9go4RcV9LahjvMI7ihOEFJwIb-XRILOIze0nmHvlnsLzAn52Kb0WdyM5OPo4cn0QZ4FGhs7jZo3FzPC406YzE-KyVgKGP0902wZoshAuHy3s9RqWtZElFrMYf3B3gVS635/s320/43_03.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Вторая таблица называется корреляционной. Чтобы понять, в чем ее суть, нужно вернуться к схеме данных:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigWESEThIqpKC8V6e5MIDA5Wm9PUXtPuVJsWYv4SFKYc53g9e-gfa7fvo6l-Ma42D2Vk4ngXZSJM_EhqPICsKzSKN77-ISyqPfDFCPLUDj9oTm916qhvhBuSd-7lpCYMeDllxdlTCLzpMB/s1600/43_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigWESEThIqpKC8V6e5MIDA5Wm9PUXtPuVJsWYv4SFKYc53g9e-gfa7fvo6l-Ma42D2Vk4ngXZSJM_EhqPICsKzSKN77-ISyqPfDFCPLUDj9oTm916qhvhBuSd-7lpCYMeDllxdlTCLzpMB/s400/43_04.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
На этом фрагменте схемы данных изображены три связанные между собой таблицы. Две из них - кодификаторы (Accounts и ExpenseGroup), содержащие перечень счетов и перечень названий групп.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Третья таблица - связывает (через ID) счета с названиями групп, т.е. в ней хранится ответ на вопрос:</div>
<div class="separator" style="clear: both; text-align: left;">
"Какие счета содержит та или иная группа?" или "В какую группу входит тот или иной счет?"</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Например (я сейчас покажу картинку, которой у Вас пока быть не может, пока мы находимся на пути к созданию соответствующего интерфейса, это будет просто иллюстрация того, как устроена корреляция):</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMsBqNSuSZDA07c8L3-3r3wTOlzeX3GUMpRafoAZ4CQuASld6clQDgZYG3WMfFrk78gWsiDAfCI9_iHuy2005Jvil24n4sj2luDKPOtP3Q_hMt2o93U9FrqrhTXOr_LMyacUsjQ0UzGYgc/s1600/43_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMsBqNSuSZDA07c8L3-3r3wTOlzeX3GUMpRafoAZ4CQuASld6clQDgZYG3WMfFrk78gWsiDAfCI9_iHuy2005Jvil24n4sj2luDKPOtP3Q_hMt2o93U9FrqrhTXOr_LMyacUsjQ0UzGYgc/s640/43_05.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Раскрыв в списке групп строку с ID=6 (Дом), видно, что в связанной с ней корреляционной таблице существует несколько строк, т.е. в эту группу включены счета с их ID: 36, 44, 24, 38 и 28. По таблице счетов видно, что все эти счета так или иначе связаны с расходами по содержанию квартиры (дома).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Обратите внимание, что эти счета отмечены в поле Groups таблицы Accounts. Это - важно.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Надеюсь, что идея ясна. Пора приступать к реализации интерфейса.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Общий<a href="http://pro-delphi.blogspot.com/2012/03/32.html"> алгоритм добавления формы в проект</a> уже пройден несколько раз.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Добавьте в проект форму GroupsFrm вот такого вида:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVryXHVuVax7jnxAl64oOCxpOXTvrfqPtrb4L9zyYHIIxHZSZ7AulxdZBOd0j7DwzCKjQcgQboJ9JZ-7pBLsyN71Cw9tEw0CzFdWGwSLJG1Q38_MEjAjLdaK3WqihbaJdm3GAnOoYjO8l/s1600/43_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="467" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVryXHVuVax7jnxAl64oOCxpOXTvrfqPtrb4L9zyYHIIxHZSZ7AulxdZBOd0j7DwzCKjQcgQboJ9JZ-7pBLsyN71Cw9tEw0CzFdWGwSLJG1Q38_MEjAjLdaK3WqihbaJdm3GAnOoYjO8l/s640/43_06.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Несколько слов о компонентах этой формы.</div>
<div class="separator" style="clear: both; text-align: left;">
Компонент TADOTable, </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiA0qLRT1rmvEQJEIl_Vh7008RhgiURjTjZnb-yN3a9D_rH3htA-jkX3-JsFS0kNYMPwTtn5ujhZ0wDJPTTsw8rCIbz9fBd1iIlDBTsDsu6pvuR3vmukRpWy-XUcSwKilMKsze8E79sGAs/s1600/43_07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiA0qLRT1rmvEQJEIl_Vh7008RhgiURjTjZnb-yN3a9D_rH3htA-jkX3-JsFS0kNYMPwTtn5ujhZ0wDJPTTsw8rCIbz9fBd1iIlDBTsDsu6pvuR3vmukRpWy-XUcSwKilMKsze8E79sGAs/s400/43_07.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
с которым через TDataSource</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrVk7w8S6X5qk5iLTj4fC5bIFC9jg1KkzHOUMIlwZb96oQ7tWAZn5nsURvzvgGJUfSv-ORDZZdRy5b8DlCu_ZUJlbmxV-upu_gZr-_FWh8Q3zPmVYZ0peEdRqlMKvjghAj4csWlTRqq6t-/s1600/43_08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrVk7w8S6X5qk5iLTj4fC5bIFC9jg1KkzHOUMIlwZb96oQ7tWAZn5nsURvzvgGJUfSv-ORDZZdRy5b8DlCu_ZUJlbmxV-upu_gZr-_FWh8Q3zPmVYZ0peEdRqlMKvjghAj4csWlTRqq6t-/s400/43_08.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
связана верхняя сетка:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga5TtLBhgExCF0MikMI8XyJcyjyv8wy6EYHxnO7DQGofB8gETEbSWTssonSoiant82VhDk4GsXWMsVmoR2jLPcmdzpXmQPiCBXygblQGl62dzHxcWwGkidtSbPhUrb0RO3fr2kmQ6qB2O-/s1600/43_09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga5TtLBhgExCF0MikMI8XyJcyjyv8wy6EYHxnO7DQGofB8gETEbSWTssonSoiant82VhDk4GsXWMsVmoR2jLPcmdzpXmQPiCBXygblQGl62dzHxcWwGkidtSbPhUrb0RO3fr2kmQ6qB2O-/s400/43_09.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Эта форма должна позволять наполнять и редактировать список групп, поэтому на ней размещен<a href="http://pro-delphi.blogspot.com/2011/10/blog-post.html"> навигатор собственного производства</a>, который так же связан с источником ADOTableGroups.</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Следующие компоненты: запрос TADOQuery, источник данных и Grid слева внизу связаны между собой аналогичным образом:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY-xEwp_hVAXItk-aAqX3w94qGht5oKo7wwtwndXAVBoG8tFWXZyi9bgyadgn14YNbge6LtP46NLhTyGicv869yxG0PyYtxdnPRVzIWHPOsBvzTuAy_HSS7cgRjip97vasoLOTW3CiVywd/s1600/43_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="387" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY-xEwp_hVAXItk-aAqX3w94qGht5oKo7wwtwndXAVBoG8tFWXZyi9bgyadgn14YNbge6LtP46NLhTyGicv869yxG0PyYtxdnPRVzIWHPOsBvzTuAy_HSS7cgRjip97vasoLOTW3CiVywd/s400/43_10.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Grid справа внизу связана посредством своего DataSource с таблицей, расположенной на главной форме:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjux7_nhB3csxRYpC9VxvbXT14BVHc9pI_gGZ4ymc2m_lI95jBG3veap-1tYKKChGpxkm6dv2a69vOo9sp-wRWC9T6dWKNowzxWZ8a5il7cEHp3F6luin36wZFPbK_NlZEejZiU9Kut6iR9/s1600/43_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjux7_nhB3csxRYpC9VxvbXT14BVHc9pI_gGZ4ymc2m_lI95jBG3veap-1tYKKChGpxkm6dv2a69vOo9sp-wRWC9T6dWKNowzxWZ8a5il7cEHp3F6luin36wZFPbK_NlZEejZiU9Kut6iR9/s640/43_11.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
ActionList имеет одну строку, о которой тоже говорилось ранее:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwdy-Ivfk3-oAmVpwdrwXdDzi2bdo2njO2MsXgTKXSrVUYAg1NPZ4qYSF2YQgCgVI_JU1L4QO-HA1N0b6Y8ifCxlCNEjMf_xLIRJvEvKd9rVnFhs2Z_YnKsvlUi_wh7Sz41rfoyUmx1qnZ/s1600/43_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwdy-Ivfk3-oAmVpwdrwXdDzi2bdo2njO2MsXgTKXSrVUYAg1NPZ4qYSF2YQgCgVI_JU1L4QO-HA1N0b6Y8ifCxlCNEjMf_xLIRJvEvKd9rVnFhs2Z_YnKsvlUi_wh7Sz41rfoyUmx1qnZ/s640/43_12.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Компонент, о котором<a href="http://pro-delphi.blogspot.com/2011/12/26.html"> так же говорилось ранее - TADOCommand</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkqbgtqvcyISlOaK-tqaF1a_lV9eVwViBwICinh4WyVI0RVjqIqoCFHnjBgkwhHFbtPfzFrKJYz1ufLQabTJgx09P2vjfDT3CMXoKKlgu39ImE4U5BpA2I-clPeHrQ3ujQgbLvuUm70b-7/s1600/43_14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkqbgtqvcyISlOaK-tqaF1a_lV9eVwViBwICinh4WyVI0RVjqIqoCFHnjBgkwhHFbtPfzFrKJYz1ufLQabTJgx09P2vjfDT3CMXoKKlgu39ImE4U5BpA2I-clPeHrQ3ujQgbLvuUm70b-7/s400/43_14.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Остались две кнопки со стрелками, которые и будут определять основную логику работы формы: выбрал справа счет, нажал кнопочку "<<", счет включился в выбранную в верхней табличке группу. Кнопка ">>" будет исключать счет из группы.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Теперь займемся кодом.</div>
<div class="separator" style="clear: both; text-align: left;">
В главной форме припишите к соответствующему пункту меню обработчик события:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TMainFrm.N_ExpGrClick(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Application.CreateForm(TGroupsFrm, GroupsFrm);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> GroupsFrm.ShowMoDal;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> GroupsFrm.Free;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Весь следующий текст будет касаться модуля Groups формы GroupsFRM.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Среди переменных общего пользования, нужно объявить одну - для хранения значения фильтра:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">var</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> GroupsFrm: TGroupsFrm;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> LastFilter: String; // Понадобится запоминать значение фильтра</span></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Чтобы можно было обращаться к главной форме, использовать ее общие компоненты и переменные и к форме Accounts:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">implementation</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">Uses Main</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> , Accounts</span><span style="color: orange;">;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
Далее - в привычном порядке, сначала об открытии и закрытии формы, а потом - по сути алгоритма.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Процедура создания формы:</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TGroupsFrm.FormCreate(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">Var MyStr: String;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Подготовка таблицы - кодификатора групп</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableGroups.Connection:=MainFrm.ADOConnection1;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableGroups.Filter:='ID>1'; // Первая строка, в которой обычно пишется</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableGroups.Filtered:=True; // что-то типа "Значение не задано"</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // отфильтровывается</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableGroups.Active:=True;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Наполняется значениями запрос ADOQueryMembers</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.Connection:=MainFrm.ADOConnection1;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.Active:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.SQL.Clear;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:='SELECT Accounts.Name, ExpenseAcc.IDGroup, ExpenseAcc.IDAcc, ExpenseAcc.ID ';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:=MyStr + 'FROM Accounts INNER JOIN ExpenseAcc ON Accounts.ID = ExpenseAcc.IDAcc ';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.SQL.Add(MyStr);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.Active:=True;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOCommand1.Connection:=MainFrm.ADOConnection1;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Запоминается фильтр, наложенный на таблицу ранее (другим интерфейсом)</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> LastFilter:= MainFrm.ADOTableAcc.Filter;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // С помощью нового фильтра выбираются счета с признаком Analiz, относящиеся к определенной валюте</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // и не включенные в группу</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MainFrm.ADOTableAcc.Filter:='(Analiz=True) AND (Val='+IntToStr(Main.MySelect.MySel_IDVal)+') AND Groups=0';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MainFrm.ADOTableAcc.Filtered:=True;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<br /></div>
<br />
<div>
и процедура закрытия формы:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.FormClose(Sender: TObject; var Action: TCloseAction);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // При закрытии формы - вернуть таблице счетов прежний фильтр</span></div>
<div>
<span style="color: orange;"> MainFrm.ADOTableAcc.Filter:=LastFilter;</span></div>
<div>
<span style="color: orange;"> MainFrm.ADOTableAcc.Filtered:=True;</span></div>
<div>
<span style="color: orange;"> Action:= caFree;</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Код для обработки единственного Action:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TGroupsFrm.BottonsClicksExecute(Sender: TObject);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Если таблица ADOTableGroups находится в режиме редактирования</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if ADOTableGroups.Modified</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Try</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableGroups.Post; // то - запись в источник</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> finally</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Если пользователь не завершил редактирование запроса</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if ADOQueryMembers.Modified</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Try</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOQueryMembers.Post; // то - запись в источник</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> finally</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> case ModalResult of // Обработка нажатия кнопок OK и Cancel</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> 1:</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyClose;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> 2:</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyClose;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<br /></div>
<br />
где процедура MyClose имеет следующее содержание:<br />
<br />
<br />
<span style="color: orange;">procedure TGroupsFrm.MyClose();</span><br />
<span style="color: orange;">Begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Отключение таблицы</span><br />
<span style="color: orange;"> ADOTableGroups.Active:=False;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Закрытие формы</span><br />
<span style="color: orange;"> Close;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<div>
<br /></div>
<br />
Несколько вспомогательных процедур.<br />
Объявите приватную процедуру MyRefresh и напишите ее в следующем виде:<br />
<br />
<br />
<span style="color: orange;">procedure TGroupsFrm.MyRefresh();</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Чтобы избежать сбоя на пустой таблице</span><br />
<span style="color: orange;"> if ADOTableGroups.FieldByName('ID').Value>0</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> ADOQueryMembers.Filter:='IDGroup='+IntToStr(ADOTableGroups.FieldByName('ID').Value);</span><br />
<span style="color: orange;"> ADOQueryMembers.Filtered:=True;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;">end;</span><br />
<div>
<br /></div>
<div>
Она обновляет набор содержащихся в группе счетов. Набор должен обновляться, когда пользователь осуществляет скролинг - переход по записям в таблице Групп или, когда он закончил ее редактирование:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.ADOTableGroupsAfterScroll(DataSet: TDataSet);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyRefresh();</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">procedure TGroupsFrm.ADOTableGroupsAfterPost(DataSet: TDataSet);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyRefresh();</span></div>
<div>
<span style="color: orange;">end;</span></div>
</div>
<div>
<br /></div>
<div>
Добавьте еще две Private процедуры, одна из которых будет добавлять счет в группу, а вторая - удалять:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;"></span><br />
<div>
<span style="color: orange;">procedure TGroupsFrm.MyAdd();</span></div>
<span style="color: orange;">
<div>
begin</div>
<div>
<br /></div>
<div>
// Добавление счета в группу</div>
<div>
With ADOQueryMembers Do // Работаем с запросом</div>
<div>
Begin</div>
<div>
Insert; // Добавление новой записи</div>
<div>
Try</div>
<div>
<br /></div>
<div>
// Присвоение значений полям</div>
<div>
FieldByName('IDGroup').Value:=ADOTableGroups.FieldByName('ID').Value;</div>
<div>
FieldByName('IDAcc').Value:=MainFrm.ADOTableAcc.FieldByName('ID').Value;</div>
<div>
<br /></div>
<div>
// Запись в таблицу-источник</div>
<div>
Post;</div>
<div>
<br /></div>
<div>
// Фиксирование признака в кодификаторе счетов</div>
<div>
MainFrm.ADOTableAcc.Edit;</div>
<div>
MainFrm.ADOTableAcc.FieldByName('Groups').Value:=True;</div>
<div>
MainFrm.ADOTableAcc.Post;</div>
<div>
<br /></div>
<div>
// Обновление данных</div>
<div>
Requery();</div>
<div>
finally</div>
<div>
MainFrm.ADOTableAcc.Requery();</div>
<div>
end;</div>
<div>
end;</div>
<div>
end;</div>
<div>
<br /></div>
</span></div>
</div>
<div>
<div>
<span style="color: orange;">Procedure TGroupsFrm.MyDelete();</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> Try</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Найти счет и пометить его, что он больше не используется в группах</span></div>
<div>
<span style="color: orange;"> ADOCommand1.CommandText:='UPDATE Accounts SET Accounts.Groups = False WHERE (((Accounts.ID)='+IntToStr(ADOQueryMembers.FieldByName('IDAcc').Value)+'))';</span></div>
<div>
<span style="color: orange;"> ADOCommand1.Execute;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Обновить кодификатор счетов</span></div>
<div>
<span style="color: orange;"> MainFrm.ADOTableAcc.Requery();</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> // Удалить строку из корреляционной таблицы</span></div>
<div>
<span style="color: orange;"> ADOCommand1.CommandText:='DELETE ExpenseAcc.ID FROM ExpenseAcc WHERE (((ExpenseAcc.ID)='+IntToStr(ADOQueryMembers.FieldByName('ID').Value)+')) ';</span></div>
<div>
<span style="color: orange;"> ADOCommand1.Execute;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> finally</span></div>
<div>
<span style="color: orange;"> ADOQueryMembers.Requery();</span></div>
<div>
<span style="color: orange;"> end;</span></div>
<div>
<span style="color: orange;">end;</span></div>
</div>
<div>
<br /></div>
<div>
Теперь осталось назначить обработчики событий нажатия кнопок со стрелками и для удобства - двойных кликов по соответствующим сеткам:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.Button1Click(Sender: TObject);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyAdd();</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">procedure TGroupsFrm.DBGridEh3DblClick(Sender: TObject);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyAdd();</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">procedure TGroupsFrm.Button2Click(Sender: TObject);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyDelete;</span></div>
<div>
<span style="color: orange;">end;</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">procedure TGroupsFrm.DBGridEh2DblClick(Sender: TObject);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"> MyDelete();</span></div>
<div>
<span style="color: orange;">end;</span></div>
</div>
<div>
<br /></div>
<div>
Для любителей пользоваться клавиатурой можно запрограммировать под аналогичные действия нажатия кнопок:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">procedure TGroupsFrm.FormKeyDown(Sender: TObject; var Key: Word;</span></div>
<div>
<span style="color: orange;"> Shift: TShiftState);</span></div>
<div>
<span style="color: orange;">begin</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> case Key of // Start Case</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> VK_INSERT:</span></div>
<div>
<span style="color: orange;"> MyAdd();</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> VK_DELETE:</span></div>
<div>
<span style="color: orange;"> MyDelete();</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> else</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"> End; // End case</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">end;</span></div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqbLyGcrm1CP5sLtTRfPNRauxxeg6BDweErs9X-Rgy6A0VmgDsl3UxLiNiGWUZtH9ORog02yDGwe2DO67Bm2trKEMK3eDL0KRDONqsEq6BBMRtCem155RWzlFB5So4a4mS5zznRPIjCA5P/s1600/43_15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqbLyGcrm1CP5sLtTRfPNRauxxeg6BDweErs9X-Rgy6A0VmgDsl3UxLiNiGWUZtH9ORog02yDGwe2DO67Bm2trKEMK3eDL0KRDONqsEq6BBMRtCem155RWzlFB5So4a4mS5zznRPIjCA5P/s400/43_15.png" width="400" /></a></div>
<div>
<br /></div>
<div>
С точки зрения программирования, я не рассказал ничего нового, но... в следующем уроке я планирую переделать интерфейс данной формы для использования технологии Drag & Drop при формировании списка счетов, включаемых в группу затрат.</div>
<div>
<br /></div>
<div>
<br /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-7481896147655466572012-05-04T11:44:00.000+04:002012-05-11T14:28:27.225+04:00Урок 42. Обороты по счетуДавайте дадим пользователю (едва не сказал привычное "бухгалтеру") еще одну возможность поиска, сопоставления, проверки... назовите это как угодно - еще один инструмент.<br />
<br />
Этот инструмент позволит ответить на вопрос:<br />
<br />
<b>А из чего складывается тот или иной оборот по конкретному счету за выбранный период?</b><br />
<b><br /></b><br />
Ну, например: в <a href="http://pro-delphi.blogspot.com/2012/03/33-excel.html">оборотной ведомости</a> за январь (YYYY года) есть расход в строке со счетом "Коммунальные платежи", но сейчас, в мае, вы нашли под кроватью квитанцию за январь, и не помните, вносили Вы эту сумму в январе или нет. Да и вообще, из чего складывается общая цифра коммунальных платежей за январь, из каких сумм и кому заплаченных?<br />
<br />
<a name='more'></a><br /><br />
Добавим в проект новую форму (я так легко это говорю, потому что уже несколько раз подробно рассказывал <a href="http://pro-delphi.blogspot.com/2012/04/41.html">ранее</a>, как это сделать)<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8xKkdOsyzbWkPhdQIwJLj8ODTt-BY5vV-rjzxXFbKdRVIMAWxxoE1k3-uEBSa9ZU0zXcd1qI4smOXoSMD8vt-6dD71MuvL7_rq9JJueEHFf0cv4EljSgHRQJCOyvm8HlpBNPSNjPO3S2u/s1600/42-00.png" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8xKkdOsyzbWkPhdQIwJLj8ODTt-BY5vV-rjzxXFbKdRVIMAWxxoE1k3-uEBSa9ZU0zXcd1qI4smOXoSMD8vt-6dD71MuvL7_rq9JJueEHFf0cv4EljSgHRQJCOyvm8HlpBNPSNjPO3S2u/s640/42-00.png" width="640" /></a><br />
<br />
Для вызова этой формы подготовлен пункт меню в главной форме, осталось только прописать обработчик события:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtTvN_lH0CTi8LYidcWIBaLv1bDmoaDNnc3tpvqh_o4L5o_TwBP4f2u-_ikPUci0mZdRJlIQBo6Lj5x5vYc9bNwBwmjrle3BamOQeQQWD5fDTNx8bt72uJHhwdvlDBEJSQ3a-FITnfzgiI/s1600/42-01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtTvN_lH0CTi8LYidcWIBaLv1bDmoaDNnc3tpvqh_o4L5o_TwBP4f2u-_ikPUci0mZdRJlIQBo6Lj5x5vYc9bNwBwmjrle3BamOQeQQWD5fDTNx8bt72uJHhwdvlDBEJSQ3a-FITnfzgiI/s400/42-01.png" width="400" /></a></div>
<br />
<br />
<span style="color: orange;">procedure TMainFrm.N4Click(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Сначала нужно дать возможность выбрать счет</span><br />
<span style="color: orange;"> MySelect.MySel_IDAcc:=0;</span><br />
<span style="color: orange;"> MySelect.MySel_AccName:='';</span><br />
<span style="color: orange;"> ShowAccounts;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Открыть форму</span><br />
<span style="color: orange;"> Application.CreateForm(TAccOborRfm, AccOborRfm);</span><br />
<span style="color: orange;"> AccOborRfm.ShowModal;</span><br />
<span style="color: orange;"> AccOborRfm.Free;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br />
После этого в модуле AccOborot формы AccOborRfm нужно написать несколько стандартных на мой взгляд процедур, обрабатывающих процесс создания и закрытия формы, а также - нажатия клавиш:<br />
<br />
<br />
<span style="color: orange;">implementation</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">Uses Main;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">{$R *.dfm}</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">procedure TAccOborRfm.FormCreate(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // В момент создания формы присвоить стартовые значения датам</span><br />
<span style="color: orange;"> Date_N.Value:=Now();</span><br />
<span style="color: orange;"> Date_K.Value:=Now()+1;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Назначение коннекции компоненту - запросу</span><br />
<span style="color: orange;"> ADOQuery1.Connection:=MainFrm.ADOConnection1;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">procedure TAccOborRfm.FormClose(Sender: TObject; var Action: TCloseAction);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"> Action:= caFree;</span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">procedure TAccOborRfm.FormKeyDown(Sender: TObject; var Key: Word;</span><br />
<span style="color: orange;"> Shift: TShiftState);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Стандартная процедура обработки нажатия клавишей в форме</span><br />
<span style="color: orange;"> case Key of</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> VK_ESCAPE: // Обработка нажатия Excape = закрытие формы</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> MyClose;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> else</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> End;</span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">procedure TAccOborRfm.MyClose();</span><br />
<span style="color: orange;">Begin</span><br />
<span style="color: orange;"> Close;</span><br />
<span style="color: orange;">end;</span><br />
<br />
<br />
<span style="color: orange;">procedure TAccOborRfm.ButtonsClickExecute(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Обработчик нажатия стандартных кнопок (ОК и Cancel)</span><br />
<span style="color: orange;"> if (ModalResult=1) OR (ModalResult=2)</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> Begin</span><br />
<span style="color: orange;"> MyClose;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br />
Аналогичные действия мы уже проделывали.<br />
<br />
<br />
<br />
<br />
Теперь перейдем к самому нужному, к обработчику события нажатия кнопки "Показать".<br />
Но прежде нужно воспользоваться <a href="http://pro-delphi.blogspot.com/2012/04/41.html">уже описанным мною приемом</a>, чтобы составить SQL-строку запроса, которая потом "вкладывается" в переменную MyStr по частям:<br />
<br />
<br />
<span style="color: orange;">procedure TAccOborRfm.Button1Click(Sender: TObject);</span><br />
<span style="color: orange;">Var MyStr: String;</span><br />
<span style="color: orange;"> s: String;</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Обработка нажатия кнопки Показать</span><br />
<span style="color: orange;"> // Запомнить в переменную идентификатор выбранного счета, хранящийся в записи </span><span style="color: orange;">MySelect.MySel_IDAcc</span><br />
<span style="color: orange;"> s:=IntToStr(MySelect.MySel_IDAcc);</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Подготовка строки запроса</span><br />
<span style="color: orange;"> ADOQuery1.Active:=False;</span><br />
<span style="color: orange;"> ADOQuery1.SQL.Clear;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Создание строки запроса</span><br />
<span style="color: orange;"> MyStr:='SELECT Main.MyDate, MOs.Name, Accounts.Name, Accounts_1.Name, IIf([D]='+s+',[Summa],0) AS Поступило, IIf([K]='+s+',[Summa],0) AS Списано, Main.Rem ';</span><br />
<span style="color: orange;"> MyStr:=MyStr+'FROM Accounts AS Accounts_1 INNER JOIN (MOs INNER JOIN (Accounts INNER JOIN Main ON Accounts.ID = Main.D) ON MOs.ID = Main.MO) ON Accounts_1.ID = Main.K ';</span><br />
<span style="color: orange;"> MyStr:=MyStr+'WHERE (((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#) AND ((Main.D)='+s+')) OR (((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#) AND ((Main.K)='+s+'))';</span><br />
<span style="color: orange;"> MyStr:=MyStr+'ORDER BY Main.MyDate DESC';</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> ADOQuery1.SQL.Add(MyStr);</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Включение запроса</span><br />
<span style="color: orange;"> ADOQuery1.Active:=True;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<div>
<span style="color: orange;"><br /></span></div>
<br />
Собственно, на этом можно было бы поставить точку.<br />
<br />
Но, где-то не так давно мной была подготовлена замечательная функция вывода содержимого грида в электронную таблицу. Будет не плохо, если в соответствующем пункте контекстного меню организовать вызов этой функции:<br />
<br />
<br />
<span style="color: orange;">procedure TAccOborRfm.N_ExportClick(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Экспорт в Эксель</span><br />
<span style="color: orange;"> MainFrm.ExportTo(PCHAR(MySelect.MySel_AccName), DBGridEh1, MainFrm.XLApp, PCHAR('Движение по счету'), PCHAR('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br />
<br />
Результат работы виден на следующих двух иллюстрациях:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjduCMpWa081IfW2de2k1CS8Rj8WX9hOJql7xTX5erP_goecAFFOVnHXcLKIl_ZtL8LxR1YjBFdGQG0ms2rgqDbX_3QIph8JARiJTsjIGHsld4Iy9q84NENxqYZDNf-3JnmTkWFaGZwhGTG/s1600/42-02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjduCMpWa081IfW2de2k1CS8Rj8WX9hOJql7xTX5erP_goecAFFOVnHXcLKIl_ZtL8LxR1YjBFdGQG0ms2rgqDbX_3QIph8JARiJTsjIGHsld4Iy9q84NENxqYZDNf-3JnmTkWFaGZwhGTG/s400/42-02.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKdcgQi1OHOGDwTQHUcGYgyrM49GR0_kILwwvAH8Wx3d2nuxlhUvN603_QYttFfVkzeiQx-P8b9R3_vtMvm91KF03lBLIlAH7s5vUAinZbF3FgGiyJAh_0ApafcsDN68RGq_X_FNKoo9yA/s1600/42-03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKdcgQi1OHOGDwTQHUcGYgyrM49GR0_kILwwvAH8Wx3d2nuxlhUvN603_QYttFfVkzeiQx-P8b9R3_vtMvm91KF03lBLIlAH7s5vUAinZbF3FgGiyJAh_0ApafcsDN68RGq_X_FNKoo9yA/s400/42-03.png" width="400" /></a></div>
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-14237579284964189632012-04-27T15:46:00.002+04:002012-04-27T15:54:21.202+04:00Еще один большой привет программистам МТС!<h2>
Какие НЕ нужно писать программы</h2>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Меня <a href="http://pro-delphi.blogspot.com/2012/04/blog-post_06.html">уже удивляли программисты, работающие на МТС</a>, но сегодня коллекция моих удивлений пополнилась еще одним экспонатом.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
При попытке изменить набор услуг с помощью Интернет-помощника, а точнее - отключить услугу "БИТ 2011", мне было выдано сообщение:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: orange;">"Запрос не выполнен. На номере телефона имеются незавершенные операции..."</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_b4UXgP_uXiTGLkfZB3jk6Ximi-ju0kksTwWpMGTNTtVVURQBM9_C83F-a5A8RNEakHmB0ZB1G5MxWztRQeTqxUbD816Jt_EYftlow0ABCsFAYwBnJXPdA-XKu71SUSOfaYPPsXUwiu_3/s1600/Image+3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="64" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_b4UXgP_uXiTGLkfZB3jk6Ximi-ju0kksTwWpMGTNTtVVURQBM9_C83F-a5A8RNEakHmB0ZB1G5MxWztRQeTqxUbD816Jt_EYftlow0ABCsFAYwBnJXPdA-XKu71SUSOfaYPPsXUwiu_3/s640/Image+3.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Никаких кнопочек и списков незавершенных операций интерфейс не предложил, хотя по логике вещей нужно было бы мне, как пользователю, дать возможность посмотреть на источник проблемы.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Начинаю долгий поиск по меню, отыскивая возможность посмотреть, чем я так провинился перед МТС.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
После полуторачасовых изысканий, к которым был привлечен и мой коллега, удалось найти вот такую незавершенную операцию:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivCaxZ_0lTXgKprK51ggoNML6Z7ghhdquvpz_HWTl0giQ3tl2BZmy7jfQEopvTVtOKkSIdgzMQC-cyfvmOPDPyu0L2Q5Yq8UycSSbQIXfX-axd7MXy683K0fE551QIl8bNaeB7c08PPp5L/s1600/Image+2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivCaxZ_0lTXgKprK51ggoNML6Z7ghhdquvpz_HWTl0giQ3tl2BZmy7jfQEopvTVtOKkSIdgzMQC-cyfvmOPDPyu0L2Q5Yq8UycSSbQIXfX-axd7MXy683K0fE551QIl8bNaeB7c08PPp5L/s640/Image+2.png" width="640" /></a></div>
<br />
Обратите внимание: программа сообщает мне о невыполненном переходе на тариф "MAXI", показывая справа одновременно, что моему номеру сопоставлен именно этот тариф.<br />
<br />
И еще очень "хорошо", что случилось это совсем недавно - 25 октября прошлого 2011 года, т.е. 5 месяцев назад!!!<br />
<br />
Молодцы, коллеги из МТС! Так держать!!!<br />
<br />
Зачем озадачиваться такими мелкими проблемами, как написание программ, способных анализировать ошибки, ляпы, результаты сбоев, повисалок и других непоняток?<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com1tag:blogger.com,1999:blog-8494755139146574371.post-65044463384534011442012-04-26T13:34:00.002+04:002012-05-31T13:47:51.318+04:00Урок 41. Графическое представление информацииВ этом уроке мне хочется начать тему, которой я не касался ранее, а именно: рассказать о графическом представлении информации.<br />
<br />
Любой бухгалтер скажет: "Мне это зачем? Мне Журнал хозяйственных операций дай и Главную книгу".<br />
<br />
Но, во-первых, мы пишем не бухгалтерскую, а очень очень похожую программу.<br />
Во-вторых, у нас уже есть нечто, отдаленно напоминающее ЖХО. Не хватает отчета в удобной форме - сделаем. У нас есть замечательная оборотка, из которой только ленивый не построит Главную книгу.<br />
В-третьих, графическое представление информации удобно в тех случаях, когда нужно быстро проанализировать огромный массив данных, чтобы принять какое-то конструктивное решение.<br />
В-четвертых, интереснее рассказывать о чем-то, о чем еще не рассказывал...<br />
<br />
Надеюсь, что я привел убедительные доводы в поддержку своих же намерений :-)<br />
<br />
<a name='more'></a><br />
<br />
Добавляем в проект новую форму (имя формы AnalizFrm), проделывая все те необходимые действия, которые описаны в<a href="http://pro-delphi.blogspot.com/2012/04/40.html"> предыдущем уроке</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSDCsG-JvzCxuWmgMW6ARlHyXBz5lALI8_CZgckwFe3sDEM7bFnWvoVbf5sTVKvE8k5ii6hXiHypbDpVQ8evS2TKq5PkElJRDzTcWNGigkBfkm4Cx0ZZEko_4-vWeFM8rPBPTF6piVguF-/s1600/41_01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSDCsG-JvzCxuWmgMW6ARlHyXBz5lALI8_CZgckwFe3sDEM7bFnWvoVbf5sTVKvE8k5ii6hXiHypbDpVQ8evS2TKq5PkElJRDzTcWNGigkBfkm4Cx0ZZEko_4-vWeFM8rPBPTF6piVguF-/s320/41_01.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1qm9Ca_Ydn8OZn_3n_paOXL7_Z8a-bxPK5sMWEK9PkLl3gxEWyVw0PG0wMIbjuBhvrjDHFD_kYvl__PiL7X6w5Hj-V0oqzQJASbjGleoiAFFzk5K68HIs6TKCIbowIriKME2pAl-tlbPl/s1600/41_02.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1qm9Ca_Ydn8OZn_3n_paOXL7_Z8a-bxPK5sMWEK9PkLl3gxEWyVw0PG0wMIbjuBhvrjDHFD_kYvl__PiL7X6w5Hj-V0oqzQJASbjGleoiAFFzk5K68HIs6TKCIbowIriKME2pAl-tlbPl/s320/41_02.JPG" width="320" /></a></div>
<br />
Немного слов о том, какие компоненты должны присутствовать на форме:<br />
<br />
<ul>
<li>TPopupMenu - понадобится как минимум экспортировать данные,</li>
<li>TActionList - коллекция действий (в основном - нажатия кнопок),</li>
<li>TPrDOkButton - кнопка из коллекции Pro-Delphi Lib,</li>
<li>TPageControl с двумя вкладками, изображенными на рисунках выше,</li>
<li>Два элемента управления для ввода дат начала и окончания периода из библиотеки EhLib,</li>
<li>TButton - вычислить и показать результат,</li>
<li>TADOQuery - обратиться к базе данных с запросом (:-)),</li>
<li>TDataSource - связать запрос и отображающий его результат элемент управления на форме, которым является:</li>
<li>TDBGridEh - сетка,</li>
<li>и наконец - TChart (с вкладки Additional) - компонент, способный отображать графики.</li>
</ul>
<div>
Для подготовки TChart к работе, нужно щелкнуть по нему два раза:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj828JIUm99gdluoS8amK53dgqySuYp9tE44cNaJUH9j-3-4cGwqjtaQdvQOGrUM4oKyqRlAYZNPl00FVjtOZMnSBK84OPrfof4e9FUvSpAy08EZwHxatLS7jK-2nqQkLRHe47gFgjAUlXd/s1600/41_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj828JIUm99gdluoS8amK53dgqySuYp9tE44cNaJUH9j-3-4cGwqjtaQdvQOGrUM4oKyqRlAYZNPl00FVjtOZMnSBK84OPrfof4e9FUvSpAy08EZwHxatLS7jK-2nqQkLRHe47gFgjAUlXd/s320/41_03.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqHK1r2FwRrFXpqowHbyPRsMzZikm663XHo7NgTqgDYAvhDM2wkqK5ij1XyoVGckLEmZ8mPmg_tiKK24mQxFm8tn_Ps1TUwQayvZblSOXFY6pbK3qdcVjpQDdAo-Yjb_exDyEdwdQ_49xJ/s1600/41_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqHK1r2FwRrFXpqowHbyPRsMzZikm663XHo7NgTqgDYAvhDM2wkqK5ij1XyoVGckLEmZ8mPmg_tiKK24mQxFm8tn_Ps1TUwQayvZblSOXFY6pbK3qdcVjpQDdAo-Yjb_exDyEdwdQ_49xJ/s320/41_04.png" width="320" /></a></div>
<div>
<br /></div>
<div>
и нажать кнопку "Add", чтобы добавить новую серию. Я выбрал обычную столбчатую диаграмму. Обратите внимание, что отметка 3D снята (ОК).</div>
<div>
<br /></div>
<div>
Заголовок - title - задайте на одноименной вкладке.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS_eHOGwQzuccs95owT7SL9Q6jir9yh1vlLKqjHhfQayesJD0bIqt_pCUmFNH_Xn7ewUTLXC0oiAyvWwDnl1ZIgfJw5y_mW91eP4I2jIEeOsOUFmPlaH4M2q37lkGEspBk3SA50olsSk65/s1600/41_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS_eHOGwQzuccs95owT7SL9Q6jir9yh1vlLKqjHhfQayesJD0bIqt_pCUmFNH_Xn7ewUTLXC0oiAyvWwDnl1ZIgfJw5y_mW91eP4I2jIEeOsOUFmPlaH4M2q37lkGEspBk3SA50olsSk65/s320/41_05.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
На этом, собственно, предварительная настройка закончена.</div>
<div>
<br /></div>
<div>
Приступим к наполнению кода формы.</div>
<div>
<br /></div>
<div>
Первое, что нам понадобится - массив с константами цветов</div>
<div>
<br /></div>
<div>
<div>
<span style="color: orange;">var</span></div>
<div>
<span style="color: orange;"> AnalizFrm: TAnalizFrm;</span></div>
<div>
<span style="color: orange;"> MyColor: array[1..16] of TColor = (</span></div>
<div>
<span style="color: orange;"> clMaroon</span></div>
<div>
<span style="color: orange;"> ,clGreen</span></div>
<div>
<span style="color: orange;"> ,clYellow</span></div>
<div>
<span style="color: orange;"> ,clOlive</span></div>
<div>
<span style="color: orange;"> ,clNavy</span></div>
<div>
<span style="color: orange;"> ,clPurple</span></div>
<div>
<span style="color: orange;"> ,clTeal</span></div>
<div>
<span style="color: orange;"> ,clLime</span></div>
<div>
<span style="color: orange;"> ,ClGray</span></div>
<div>
<span style="color: orange;"> ,clRed</span></div>
<div>
<span style="color: orange;"> ,clSilver</span></div>
<div>
<span style="color: orange;"> ,clBlue</span></div>
<div>
<span style="color: orange;"> ,ClFuchsia</span></div>
<div>
<span style="color: orange;"> ,clAqua</span></div>
<div>
<span style="color: orange;"> ,clMoneyGreen</span></div>
<div>
<span style="color: orange;"> ,clSkyBlue</span></div>
<div>
<span style="color: orange;"> );</span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;"><br /></span></div>
<div>
<span style="color: orange;">implementation</span></div>
</div>
<div>
<br /></div>
<br />
Я уже<a href="http://pro-delphi.blogspot.com/2012/04/39-insert.html"> говорил раньше о массивах</a>, но здесь я объявляю его иначе, используя возможность его инициализации при объявлении (т.е. присваиваю значения элементам массива, зная их заранее).<br />
<br />
При старте формы логично сделать следующие действия:<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizFrm.FormCreate(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // При создании формы задать значения датам</span><br />
<span style="color: orange;"> Date_N.Value:=Now()-365; // На год назад</span><br />
<span style="color: orange;"> Date_K.Value:=Now()+1; // По сегодня включительно</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Назначить запросу способ подключения</span><br />
<span style="color: orange;"> ADOQuery1.Connection:=MainFrm.ADOConnection1;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br />
<br />
При выключении формы - почистить за собой памятийку:<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizFrm.FormClose(Sender: TObject; var Action: TCloseAction);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"> Action:= caFree;</span><br />
<span style="color: orange;">end;</span><br />
<br />
Нажатие кнопок (в частности Escape) обработаем следующими двумя процедурами (это - стандартный подход):<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizFrm.FormKeyDown(Sender: TObject; var Key: Word;</span><br />
<span style="color: orange;"> Shift: TShiftState);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"> case Key of // Start Case</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> VK_ESCAPE:</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> MyClose;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> else</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> End; // End case</span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">procedure TAnalizFrm.MyClose();</span><br />
<span style="color: orange;">Begin</span><br />
<span style="color: orange;"> Close;</span><br />
<span style="color: orange;">end;</span><br />
<br />
<br />
<br />
Экшен, подложенный под кнопку "OK":<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizFrm.ButtonClickExecuteExecute(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> if (ModalResult=1) OR (ModalResult=2)</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> Begin</span><br />
<span style="color: orange;"> MyClose;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br />
<br />
А теперь - самое главное - обработчик нажатия кнопки "Показать"<br />
<br />
<br />
<span style="color: orange;">procedure TAnalizFrm.Button1Click(Sender: TObject);</span><br />
<span style="color: orange;">Var MyStr: String;</span><br />
<span style="color: orange;"> j: Integer;</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Подготовка запроса</span><br />
<span style="color: orange;"> ADOQuery1.Active:=False;</span><br />
<span style="color: orange;"> ADOQuery1.SQL.Clear;</span><br />
<span style="color: orange;"> MyStr:='SELECT Accounts.ID, Accounts.Name, Sum(Main.Summa) AS MySum ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'FROM Accounts INNER JOIN Main ON Accounts.ID = Main.D ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'WHERE (((Accounts.Val)='+IntToStr(MySelect.MySel_IDVal)+') AND ((Accounts.Analiz)=True) ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'AND ((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#)) ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'GROUP BY Accounts.ID, Accounts.Name ';</span><br />
<span style="color: orange;"> MyStr:=MyStr + 'ORDER BY Sum(Main.Summa) DESC';</span><br />
<span style="color: orange;"> ADOQuery1.SQL.Add(MyStr);</span><br />
<span style="color: orange;"> ADOQuery1.Active:=True;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Настройка графика</span><br />
<span style="color: orange;"> j:=1;</span><br />
<span style="color: orange;"> With Series1 do</span><br />
<span style="color: orange;"> begin</span><br />
<span style="color: orange;"> Clear;</span><br />
<span style="color: orange;"> while (Not ADOQuery1.Eof) do</span><br />
<span style="color: orange;"> Begin</span><br />
<span style="color: orange;"> if j>16 // Если количество столбцов в графике больше 16, то цвета будут повторяться</span><br />
<span style="color: orange;"> then</span><br />
<span style="color: orange;"> j:=1</span><br />
<span style="color: orange;"> else</span><br />
<span style="color: orange;"> j:=j+1;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Следующей строкой задается отображение очередного столбца</span><br />
<span style="color: orange;"> // Сумма и название (счета) - из запроса</span><br />
<span style="color: orange;"> // Цвет - из массива</span><br />
<span style="color: orange;"> Add(ADOQuery1.FieldByName('MySum').Value, ADOQuery1.FieldByName('Name').Text, MyColor[j]);</span><br />
<span style="color: orange;"> ADOQuery1.Next;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"> Active:=True;</span><br />
<span style="color: orange;"> end;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<span style="color: orange;"><br /></span><br />
<strike>Секрет</strike> <span style="color: red;"><b>Полезный совет:</b></span><br />
<br />
если Вы думаете, что я написал все, что вталкивается в переменную MyStr, своими ручками от начала и до конца, то Вы оооооччччееееннньььь ошибаетесь.<br />
<br />
Откройте оболочку Access и создайте запрос в режиме конструктора<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp8HDlR-XuTK8tDgvuU91CsAhv9CRTk6aJLmW4hlOBZVXg1s1DhEb2ShBWSh4s5lSNkMUJt5pfNRuH4Y8z4ZqCMrkDsr83dhHS4BnzxY1pxw306jxSZUP_NmAhiur0nfCtPM3QcoKgpVLX/s1600/41_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="157" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp8HDlR-XuTK8tDgvuU91CsAhv9CRTk6aJLmW4hlOBZVXg1s1DhEb2ShBWSh4s5lSNkMUJt5pfNRuH4Y8z4ZqCMrkDsr83dhHS4BnzxY1pxw306jxSZUP_NmAhiur0nfCtPM3QcoKgpVLX/s400/41_06.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
примерно такой, какой Вам понадобится в программе</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUlAG3ymKaG0E4C_wks17R3kGtLHOtxmvv4lu-p9uKLi2qA6XQO4w2lGDwmb7hCrlSqGozjrLkysipTuQgbR31F8pdxMR3nMepBJuwj_fg0VmY5V0hezcPlOiv4j0JEGcWsZVEFY_9x7b4/s1600/41_07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUlAG3ymKaG0E4C_wks17R3kGtLHOtxmvv4lu-p9uKLi2qA6XQO4w2lGDwmb7hCrlSqGozjrLkysipTuQgbR31F8pdxMR3nMepBJuwj_fg0VmY5V0hezcPlOiv4j0JEGcWsZVEFY_9x7b4/s640/41_07.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Мне понадобится групповая функция (суммирование), выборка из двух связанных таблиц (таблица Accounts даст названия вместо ID), графики я буду строить только по счетам, которые отмечены ИСТИНА в поле Analiz (действительно, зачем мне анализировать затраты, например по перекладываю денег из кошелька в чулок или кубышку?!) и ориентировочно я указал даты (примерно за год).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если все сделано правильно, то запрос при выполнении отобразит набор записей:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKj6NUoOhyphenhyphenEbtdyXWY27OVwDqJyVpK776g-lhg9ZXYinxWCge_JPYRfC3ZaIYvxhDtrnJqviebyYCBXKGAvktIzqgJIUSUV0ubsNraYMdtEEwoiJXP-KZIokU74TONXxHALy21Tg38XCJj/s1600/41_08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKj6NUoOhyphenhyphenEbtdyXWY27OVwDqJyVpK776g-lhg9ZXYinxWCge_JPYRfC3ZaIYvxhDtrnJqviebyYCBXKGAvktIzqgJIUSUV0ubsNraYMdtEEwoiJXP-KZIokU74TONXxHALy21Tg38XCJj/s320/41_08.png" width="312" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
(цифры здесь учебные, не имеющие отношения к реальной жизни :-) )</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
А теперь - переведите запрос в режим SQL, нажатием кнопки слева вверху:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1Z1auEc2IWXpDIwBLa3-djig1XoaT0eMzy5wc6PnJJcPkbQW8pymW9huZLCYJ_tp4Cc3PtgTUEdKx8rNQ4niPy7iFExGeHzfEW4OEfBZO3rSc8wYeY7GgJhxPzlMfTEV9SrDkxoLaU2af/s1600/41_09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1Z1auEc2IWXpDIwBLa3-djig1XoaT0eMzy5wc6PnJJcPkbQW8pymW9huZLCYJ_tp4Cc3PtgTUEdKx8rNQ4niPy7iFExGeHzfEW4OEfBZO3rSc8wYeY7GgJhxPzlMfTEV9SrDkxoLaU2af/s640/41_09.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
- вот он текст нужного запроса! Теперь простым копированием и вставкой (Ctrl-C и Ctrl-V) размещаем его текст в модуле формы, добавляем MyStr, немного функций, которые преобразуют значения из элементов управления (даты) и переменной (MySelect.MySel_IDVal - код валюты) в удобоваримые для Delphi и все.</div>
<br />
<br />
<br />
<span style="color: red;"><b>Обращаю Ваше внимание</b></span> на то, как я обошелся с датами в запросе:<br />
Access "любит" дату в запросе вот в таком виде<br />
<br />
<div style="text-align: center;">
#mm/dd/yyyy#</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Если Вы будете использовать базу данных на основе SQL Server, то диезы Вам точно не понадобятся. Но, поскольку я здесь использую БД Access, нужно привыкнуть к этому формату. Кроме того, настоятельно рекомендую изменить системные настройки, указав в качестве разделителя в дате "/" вместо установленной по умолчанию точки. Мой многолетний опыт общения с оболочкой Access настаивает на том, что не все и не всегда запросы к базе данных в среде Access возвращают корректный (правильный) набор данных при использовании в качестве разделителя даты точки!<br />
<br />
<div style="text-align: center;">
* * *</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Пункт выпадающего меню "Экспорт". Прежде нужно назначить компоненту TChart свойство PopupMenu=PopupMenu1, а затем написать обработчик выбора пункта меню:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
</div>
<span style="color: orange;">procedure TAnalizFrm.N_ExportClick(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Для вывода в Excel используется имеющаяся в модуле главной формы процедура</span><br />
<span style="color: orange;"> MainFrm.ExportTo(PChar('Лист 1'), DBGridEh1, MainFrm.XLApp, PChar('Затраты'), PChar('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<div>
<br /></div>
<div>
В результате работы получим вот такую табличку:</div>
<br />
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh11qVQS1817a-5puF7r213ZPmjiQhyrcZNV5RHyACMPyXG0_00Ml0gkuKRQwLSLzPmKWrGhQCQjTQMtBbuetuyb91gxF7_-FY-KKSnHMSot3zBxnKy-yaJAsqxK7Hzz9pH49tvAn4vj7ct/s1600/41_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh11qVQS1817a-5puF7r213ZPmjiQhyrcZNV5RHyACMPyXG0_00Ml0gkuKRQwLSLzPmKWrGhQCQjTQMtBbuetuyb91gxF7_-FY-KKSnHMSot3zBxnKy-yaJAsqxK7Hzz9pH49tvAn4vj7ct/s320/41_11.png" width="320" /></a></div>
<div style="text-align: left;">
<br /></div>
<br />
<div style="text-align: center;">
* * *</div>
<br />
В главной форме необходимо реализовать вывод формы "Анализ затрат" на экран по выбору пункта Меню - Отчетные формы - Анализ затрат (все)<br />
<br />
<br />
<span style="color: orange;">procedure TMainFrm.N_AnalizClick(Sender: TObject);</span><br />
<span style="color: orange;">begin</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;"> // Анализ затрат</span><br />
<span style="color: orange;"> Application.CreateForm(TAnalizFrm, AnalizFrm);</span><br />
<span style="color: orange;"> AnalizFrm.ShowModal;</span><br />
<span style="color: orange;"> AnalizFrm.Free;</span><br />
<span style="color: orange;"><br /></span><br />
<span style="color: orange;">end;</span><br />
<br /></div>
чтобы получить в итоге вот такую картинку:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjepuBNahYpfwKrUS-mBYF-I2mDR5ovgcGxprFjx-c2gxrSGJArMjoGx24E2-11YayZg5XHMsYLodaaPvjegPfmrf7qes5baYbtyOrWAXstIUJqd4QzhUbnUMuBTDOqLu-Vx-6JugoDaB0/s1600/41_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjepuBNahYpfwKrUS-mBYF-I2mDR5ovgcGxprFjx-c2gxrSGJArMjoGx24E2-11YayZg5XHMsYLodaaPvjegPfmrf7qes5baYbtyOrWAXstIUJqd4QzhUbnUMuBTDOqLu-Vx-6JugoDaB0/s320/41_10.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
глянув на которую, можно впасть в кому... :-)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-72119758840756116372012-04-25T11:32:00.002+04:002012-05-11T14:29:34.045+04:00Урок 40. КодификаторыСоздавать первые базы данных приходилось в условиях полного отсутствия литературы. Я уже не говорю про переведенные на русский язык книги... Вообще не было никаких. Я помню, как писал запрос в представительство Майкрософта: посодействуйте в получении руководства по MS Access...<br />
<br />
Теперь книг много разных. Но и в хороших книгах, которые встречаются не часто, по прежнему не просто найти ответ на вопрос "когда же достаточно электронной таблицы типа Excel, а в каком случае удобно использовать базу данных?"<br />
<br />
И вывел я для себя вот такую формулу много лет назад:<br />
<br />
<b>все, из чего можно составить список и пронумеровать - есть содержимое для отдельной таблицы базы данных.</b><br />
<b></b><br />
<a name='more'></a><b><br /></b><br />
Если вернуться на <a href="http://pro-delphi.blogspot.com/2011/09/18.html">пару десятков уроков назад</a>, то в структуре созданной нами для реализации функционала программы "Расходы" присутствует ряд таких таблиц:<br />
<ul>
<li>Перечень валют</li>
<li>Перечень счетов</li>
<li>Перечень мемориальных ордеров</li>
</ul>
<div>
На них же ссылаются пункты меню:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwqOcjDwkyjHiHR1ii9ZwPXucUnhSnMTnrr6wu2MUqymjPMe1pSyMHzpyEaEQdbULIQi88tBBXdfrOJWVt3gdiEwZ8W1yfJeWkHhTa92StJnyPzK22sL5LDESw5uF_OdoNz0101Xwi_fPk/s1600/40_01.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwqOcjDwkyjHiHR1ii9ZwPXucUnhSnMTnrr6wu2MUqymjPMe1pSyMHzpyEaEQdbULIQi88tBBXdfrOJWVt3gdiEwZ8W1yfJeWkHhTa92StJnyPzK22sL5LDESw5uF_OdoNz0101Xwi_fPk/s400/40_01.JPG" width="400" /></a></div>
<div>
<br /></div>
В этом уроке я расскажу, как наполнить программу возможностью обрабатывать различные справочники (кодификаторы).<br />
<br />
Сразу хотелось бы предупредить, что вряд ли я сообщу что-то новое в дополнение к тому, что уже было сказано в предыдущих уроках.<br />
<br />
<br />
Итак, напомню общий алгоритм:<br />
<br />
1. Добавить форму в проект<br />
2. Прописать ссылку на модуль формы в Uses вызывающей формы<br />
3. Исключить из автоматически запускаемых<br />
4. Добавить процедуру (или несколько) для вызова новой формы<br />
<br />
1. Форма для работы со списком счетов будет выглядеть так:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY2LZ1YDykLSXBiQfYhao0y3OAZYnkoeH9KTginomu8O0CGTzMqoNTuK2Z3CIio-giT5n9k_Y4-WkeTtFrGzlAAXUHYB3VDmrzed4vsBLlJ4Skp6v85ezv3an9uLjsT7tm45nLnXJwaDb8/s1600/40_02.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY2LZ1YDykLSXBiQfYhao0y3OAZYnkoeH9KTginomu8O0CGTzMqoNTuK2Z3CIio-giT5n9k_Y4-WkeTtFrGzlAAXUHYB3VDmrzed4vsBLlJ4Skp6v85ezv3an9uLjsT7tm45nLnXJwaDb8/s640/40_02.JPG" width="640" /></a></div>
<br />
Последняя колонка должна быть недоступной для редактирования, так как значение для нее будет задаваться как значение по умолчанию, а для его изменения мы позже создадим инструмент (форму).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
2. Укажите ссылку в разделе:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: #ffd966;">implementation</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: #ffd966;"> Uses Main;</span></div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
С учетом этого, источником данных для этой формы может вполне служить источник данных, расположенный на главной форме. Установите в свойствах: DataSource=MainFrm.DataSourceAcc.</div>
<br />
<br />
<br />
3. Напомню: Меню-Project-Options:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2m7L2EZMt2DUTR6h9R7JKgs-FLrspVgSIMtFL5MN3RCT6T-QkvLWiKw0lrWfb8woKPZF8CZLw6bQaQ4hQGM_d_Qs6IdLzHFvsT5F7zxBXt0ylqvgOKHm7NX5ZqrxhM-NNsqT4Rbex__NP/s1600/40_03.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="440" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2m7L2EZMt2DUTR6h9R7JKgs-FLrspVgSIMtFL5MN3RCT6T-QkvLWiKw0lrWfb8woKPZF8CZLw6bQaQ4hQGM_d_Qs6IdLzHFvsT5F7zxBXt0ylqvgOKHm7NX5ZqrxhM-NNsqT4Rbex__NP/s640/40_03.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4. В описание класса главной формы:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;">type</span></div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;"> TMainFrm = class(TForm)</span></div>
<div>
...</div>
<div>
в секцию нужно добавить описание новой подпрограммы:</div>
<div>
<div>
<span style="color: #ffd966;"> private</span></div>
<div>
<span style="color: #ffd966;"> { Private declarations }</span></div>
<div>
<span style="color: #ffd966;"> procedure ShowAccounts();</span></div>
</div>
<div>
<br /></div>
<div>
<div>
А затем в секции реализации (implementation) </div>
<div>
<br /></div>
<div>
дополнить ссылки на другие модули еще одной</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #ffd966;">implementation</span></div>
<div>
<span style="color: #ffd966;">Uses</span></div>
<div>
<span style="color: #ffd966;"> MOs</span></div>
<div>
<span style="color: #ffd966;">, Oborot</span></div>
<div>
<span style="color: #ffd966;">, Accounts</span></div>
<div>
<span style="color: #ffd966;">;</span></div>
</div>
<div>
<br /></div>
<div>
ну, и написать, собственно, код этой процедуры:</div>
</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #ffd966;">procedure TMainFrm.ShowAccounts();</span></div>
<div>
<span style="color: #ffd966;">Begin</span></div>
<div>
<span style="color: #ffd966;"> Application.CreateForm(TAccountsFrm, AccountsFrm);</span></div>
<div>
<span style="color: #ffd966;"> AccountsFrm.ShowMoDal;</span></div>
<div>
<span style="color: #ffd966;"> AccountsFrm.Free;</span></div>
<div>
<span style="color: #ffd966;"> StatusBarUpdate;</span></div>
<div>
<span style="color: #ffd966;">end;</span></div>
<div>
<br /></div>
</div>
<div>
Эти операторы я не случайно выделил в отдельную процедуру. Просто эта форма будет вызываться в разных местах программы, чтобы не повторялся код.</div>
<div>
<br /></div>
<div>
И последнее - создать Action или напрямую - обработчик выбора пункта меню "Кодификаторы - Счета"</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #ffd966;">procedure TMainFrm.N1Click(Sender: TObject);</span></div>
<div>
<span style="color: #ffd966;">begin</span></div>
<div>
<span style="color: #ffd966;"> MySelect.MySel_IDAcc:=0;</span></div>
<div>
<span style="color: #ffd966;"> MySelect.MySel_AccName:='';</span></div>
<div>
<span style="color: #ffd966;"> ShowAccounts;</span></div>
<div>
<span style="color: #ffd966;">end;</span></div>
</div>
<div>
<br /></div>
<div>
Теперь стоит задуматься: базу данных мы спроектировали надежную (это я про то, что после компиляции программы "Расходы" мне удалось добавить новую запись в список (кодификатор) счетов, и ничего не рухнуло): при добавлении новой записи подставились какие-то значения по-умолчанию.</div>
<div>
<br /></div>
<div>
Но, может быть, удобнее задать иные? Переделать базу данных можно, пока она у Вас одна, задачка локальная и Вы - сам себе командир. Но, если Вы работаете над большим и сложным проектом, то это не всегда бывает возможно. Бывает даже так: кто-то разрабатывает интерфейсы, а совсем другие люди разрабатывают или уже разработали базы данных.</div>
<div>
<br /></div>
<div>
Поэтому, я предлагаю написать еще одну процедуру, которая будет подставлять нужные нам значения по умолчанию в только что добавленную новую запись (для события AfterInsert компонента ADOTableAcc, расположенного на главной форме):</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #ffd966;">procedure TMainFrm.ADOTableAccAfterInsert(DataSet: TDataSet);</span></div>
<div>
<span style="color: #ffd966;">begin</span></div>
<div>
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Val').Value:=MySelect.MySel_IDVal;</span></div>
<div>
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Ost_D').Value:=0;</span></div>
<div>
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Ost_K').Value:=0;</span></div>
<div>
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Analiz').Value:=True;</span></div>
<div>
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Groups').Value:=False;</span></div>
<div>
<span style="color: #ffd966;">end;</span></div>
<div>
<br /></div>
</div>
<div>
Обращаю Ваше внимание, что последний оператор задает значение, отличное от значения по умолчанию, установленное в конструкторе таблицы базы данных:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglnOKRJ7YRqtUOtSVS7Vp8uIKvupzdFOU4MC2DN0MUStPXd_kB-wBM0WlUA2-L6UcFLpAG7CPdzr2SRXbuMd7yxVT7Xy3W_lDfXiYbzbNAz3G4qdm3zhSpfBw08cZoeeKAZPBmVyPniacg/s1600/40_04.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglnOKRJ7YRqtUOtSVS7Vp8uIKvupzdFOU4MC2DN0MUStPXd_kB-wBM0WlUA2-L6UcFLpAG7CPdzr2SRXbuMd7yxVT7Xy3W_lDfXiYbzbNAz3G4qdm3zhSpfBw08cZoeeKAZPBmVyPniacg/s640/40_04.JPG" width="640" /></a></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Еще один момент:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
для того же компонента ADOTableAcc нужен обработчик события BeforeEdit (в момент начала редактирования необходимо запомнить ID строки, соответствующей редактируемому счету)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;">procedure TMainFrm.ADOTableAccBeforeEdit(DataSet: TDataSet);</span></div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;"> p_ID:= ADOTableAcc.FieldByName('ID').value;</span></div>
<div class="separator" style="clear: both;">
<span style="color: #ffd966;">end;</span></div>
<div class="separator" style="clear: both;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
И последнее:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
без проверки введенных значений возможна ситуация задваивания значений:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi86Qxl5QxQfDJ2Mha72fbh2BO5k9oqcIFUNt-ytysJSEFGb2kHJq5_QNZb8IrYmNeQSWZXF4BKQORXZQtR0PW5XV0oZg9r-bv9UQlNpRCEDI1d6MzejDYvD79On_ar9HbbcnYYGkbqa8Gh/s1600/40_05.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi86Qxl5QxQfDJ2Mha72fbh2BO5k9oqcIFUNt-ytysJSEFGb2kHJq5_QNZb8IrYmNeQSWZXF4BKQORXZQtR0PW5XV0oZg9r-bv9UQlNpRCEDI1d6MzejDYvD79On_ar9HbbcnYYGkbqa8Gh/s640/40_05.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Такое положение в учете не допустимо.<br />
Поэтому, прежде, чем сохранить новое или отредактированное значение счета, нужно учинить ему очень строгую проверку по событию BeforePost:<br />
<br />
<br />
<span style="color: #ffd966;">procedure TMainFrm.ADOTableAccBeforePost(DataSet: TDataSet);</span><br />
<span style="color: #ffd966;">Var MyStr: String;</span><br />
<span style="color: #ffd966;">begin</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;"> MyStr:= ADOTableAcc.FieldByName('Name').Text;</span><br />
<span style="color: #ffd966;"> if (MyStr='')</span><br />
<span style="color: #ffd966;"> then</span><br />
<span style="color: #ffd966;"> begin</span><br />
<span style="color: #ffd966;"> MyMessenger.TitleString:='Ошибка';</span><br />
<span style="color: #ffd966;"> MyMessenger.MessageString:='Пустые значения не допустимы';</span><br />
<span style="color: #ffd966;"> MyMessenger.Buttons:=[mbOK];</span><br />
<span style="color: #ffd966;"> MyMessenger.ShowMessage;</span><br />
<span style="color: #ffd966;"> abort;</span><br />
<span style="color: #ffd966;"> exit;</span><br />
<span style="color: #ffd966;"> end;</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;"> TempQuery.Active:=False;</span><br />
<span style="color: #ffd966;"> TempQuery.Connection:=ADOConnection1;</span><br />
<span style="color: #ffd966;"> TempQuery.SQL.Clear;</span><br />
<span style="color: #ffd966;"> TempQuery.SQL.Add('SELECT * FROM Accounts WHERE (Name='''+MyStr+''') AND (ID<>'+IntToStr(p_ID)+')');</span><br />
<span style="color: #ffd966;"> TempQuery.Active:=True;</span><br />
<span style="color: #ffd966;"> If not TempQuery.Eof</span><br />
<span style="color: #ffd966;"> Then</span><br />
<span style="color: #ffd966;"> begin</span><br />
<span style="color: #ffd966;"> MyMessenger.TitleString:='Ошибка';</span><br />
<span style="color: #ffd966;"> MyMessenger.MessageString:='Счет '''+MyStr+''' уже есть.';</span><br />
<span style="color: #ffd966;"> MyMessenger.Buttons:=[mbOK];</span><br />
<span style="color: #ffd966;"> MyMessenger.ShowMessage;</span><br />
<span style="color: #ffd966;"> ADOTableAcc.FieldByName('Name').Text:='';</span><br />
<span style="color: #ffd966;"> Abort;</span><br />
<span style="color: #ffd966;"> end;</span><br />
<span style="color: #ffd966;"> TempQuery.Active:=False;</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;">end;</span><br />
<div>
<span style="color: #ffd966;"><br /></span></div>
<br />
В результате срабатывания этой процедуры возможны предупреждения о повторяющемся или пустом значении:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDIYXLoWTk0vvL7g1JpE0wxnUB0oP6tFEnw-7vYZ01tcL1NuP0p0Q-NkCDGELX_Rn_IqcVZu5iHy0I0zbMUKVuYSYkKrR3OnehGQmyKFlMYo7p6RX3zp09wAwWYxrt4NLb80jdbETVmxqN/s1600/40_06.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDIYXLoWTk0vvL7g1JpE0wxnUB0oP6tFEnw-7vYZ01tcL1NuP0p0Q-NkCDGELX_Rn_IqcVZu5iHy0I0zbMUKVuYSYkKrR3OnehGQmyKFlMYo7p6RX3zp09wAwWYxrt4NLb80jdbETVmxqN/s640/40_06.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX51myWV_9Cejr0r6USNxtejQwXni9H5EE0aUprYLsH9kw_-0qM7wO1bNEPPmdrx5aI_Vf0uHcagdQ7uj__SbuxEa2mPjuDwUhckL1PmgChXFdMs5ibnzoATgPqbkeD_AUBhW7Jico1n8B/s1600/40_07.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX51myWV_9Cejr0r6USNxtejQwXni9H5EE0aUprYLsH9kw_-0qM7wO1bNEPPmdrx5aI_Vf0uHcagdQ7uj__SbuxEa2mPjuDwUhckL1PmgChXFdMs5ibnzoATgPqbkeD_AUBhW7Jico1n8B/s640/40_07.JPG" width="640" /></a></div>
<br />
Аналогичные (но, спешу успокоить: чуть более простые) нужно проделать для других кодификаторов (Мемориальные ордера и Валюты).<br />
<br />
<br />
<span style="color: #ffd966;">procedure TMainFrm.N2Click(Sender: TObject);</span><br />
<span style="color: #ffd966;">begin</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;"> // Обработка пункта меню Кодификаторы-Мемориальные ордера</span><br />
<span style="color: #ffd966;"> ShowMOs;</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;">end;</span><br />
<br />
- кодификатор мемориальных ордеров у нас уже имеется, остается только выполнить обработку пункта меню.<br />
<br />
Для кодификатора валют понадобится добавить на главную форму пару компонентов (таблицу и источник данных: TADOTable и TDataSource), назначить их свойства, как уже это делали не однократно, не забыть добавить активацию этой таблицы в соответствующей процедуре и написать вызов формы:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi32F3bqPdKB7pxzrx1kAfWFcY1Ul_mbkmukuCMrYmqxyUsu5kOOXoboNWw4qIh2rohINRSo2SGiaHPuA8KHVMt-ExNCU1pliZOO2KGHPCx9VZqSYtOf4yIXuxCSPbNFe-okFphKNWD-OcH/s1600/40_08.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi32F3bqPdKB7pxzrx1kAfWFcY1Ul_mbkmukuCMrYmqxyUsu5kOOXoboNWw4qIh2rohINRSo2SGiaHPuA8KHVMt-ExNCU1pliZOO2KGHPCx9VZqSYtOf4yIXuxCSPbNFe-okFphKNWD-OcH/s400/40_08.JPG" width="400" /></a></div>
<br />
<br />
<br />
<span style="color: #ffd966;">procedure TMainFrm.N_ValClick(Sender: TObject);</span><br />
<span style="color: #ffd966;">begin</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;"> // Вызов справочника валют</span><br />
<span style="color: #ffd966;"> Application.CreateForm(TValFrm, ValFrm);</span><br />
<span style="color: #ffd966;"> ValFrm.ShowModal;</span><br />
<span style="color: #ffd966;"> ValFrm.Free;</span><br />
<span style="color: #ffd966;"> StatusBarUpdate;</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;"> // Фильтр по счетам одной валюты</span><br />
<span style="color: #ffd966;"> ADOTableAcc.Filter:='Val='+IntToStr(MySelect.MySel_IDVal);</span><br />
<span style="color: #ffd966;"> ADOTableAcc.Filtered:=True;</span><br />
<span style="color: #ffd966;"><br /></span><br />
<span style="color: #ffd966;">end;</span><br />
<div>
<br /></div>
<br />
<br />
Еще про один справочник - "Группы затрат" я предполагаю поговорить в одном из ближайших уроков.<br />
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-37602689441651432362012-04-18T11:18:00.000+04:002012-04-18T14:54:51.847+04:00Немного юмора...<br />Сидят два админа, грусные тупо смотрят в монитор,<br /><br />Заходит третий<br /><br />-Чего такие грусные?<br /><br />-Да вчера пиво пили… и пароли меняли…<br /><br /><br />***<br /><br /><br /><br /><br />Ушел сисадмин в отпуск. Через неделю на мобилу звонит начальник отдела:<br /><br />- Андрей извини, что побеспокоили. Срочно надо в компе информацию найти. Скажи пожалуйста пароль...<br /><br />- Как вы меня все з@@бали. Без пробелов и с маленькой буквы.<br /><br /><br />***<br /><br /><br /><br /><br />Рaзговор в чaте:<br /><br />- Помогите, уменяпробелнерaботaет!<br /><br />Ответ:<br /><br />- Нaстоящему_прогрaммисту_пробел_не_нужен!<br /><br /><br />*** <br /><br /><div id="-chrome-auto-translate-plugin-dialog" style="background: transparent !important; border-color: none !important; display: none; left: 0; margin: 0 !important; opacity: 1 !important; overflow: visible !important; padding: 0 !important; position: absolute !important; text-align: left !important; top: 0; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-39802694213792574392012-04-12T11:56:00.001+04:002012-04-12T11:56:14.579+04:00Сам нашел опечатку в заголовке 33 урокаВ заголовке <a href="http://pro-delphi.blogspot.com/2012/03/33-excel.html">33-го урока</a> была допущена досадная опечатка.<br />
Для исправления необходимо поменять слово "импорт" на "экспорт", что я уже и сделал.<br />
<br />
<br />
Приношу свои извинения.<br />
<br class="Apple-interchange-newline" /><br />
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-86185181250923068142012-04-11T14:34:00.002+04:002012-04-11T14:58:20.771+04:00Урок 39. "Товары", сопутствующие InsertНаверное, те, кто пытается следить за ходом моих публикаций, уже имеют более ни менее работоспособную программу "Расходы", но иногда натыкаются на разные неожиданные неприятности, не позволяющие полноценно использовать ее в качестве инструмента учета Например, прошел месяц март, наступил апрель, Вы пытаетесь добавить новую строчку в список мемориальных ордеров, но...<br />
<br />
при попытке сохранения пустой строчки происходит ошибка...
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKw6GK2wVErhVpg_m4M3wsadwUu-WMnr0lEf9gf1zBDBf80lWmwSX9BJ6kVT0gamnY_OdMcr5FpIV6Cb0FXoalAvB3N2zV7A5y2EZedUACNr9dLXLieNG9HSkPrFUsEPwfPzfmLPwR3b1v/s1600/39_01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKw6GK2wVErhVpg_m4M3wsadwUu-WMnr0lEf9gf1zBDBf80lWmwSX9BJ6kVT0gamnY_OdMcr5FpIV6Cb0FXoalAvB3N2zV7A5y2EZedUACNr9dLXLieNG9HSkPrFUsEPwfPzfmLPwR3b1v/s640/39_01.JPG" width="640" /></a></div>
<br />
написали "Апрель", но не ввели номер месяца - другая...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqo4TKqREA6idJtbIGBxZdLxCaVJDRZzCm5j89TlXrM4dAMMvVBK02PBvCIaTVzPLkFV4Ijkl5eXrBv-dzIBxNg4TVpU06q-r99bgwngwxS-wLS2mcWR3-1OVmPnjzxBmtU19qaJr6p8NR/s1600/39_02.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqo4TKqREA6idJtbIGBxZdLxCaVJDRZzCm5j89TlXrM4dAMMvVBK02PBvCIaTVzPLkFV4Ijkl5eXrBv-dzIBxNg4TVpU06q-r99bgwngwxS-wLS2mcWR3-1OVmPnjzxBmtU19qaJr6p8NR/s640/39_02.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если пользователь - Вы сам, то беды большой нет, поскольку Вы знаете в чем тут дело и как поправить. Но я стараюсь как можно чаще давать понять моему читателю, что пугать неподготовленного пользователя служебными сообщениями есть моветон. Как плохой манерой является и исполнение маневров, подобных тем, что <a href="http://pro-delphi.blogspot.com/2012/04/blog-post_06.html">исполняют в МТС</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Чтобы избежать этих мелких неприятностей, нужно в момент добавления записи в соответствующую таблицу, присвоить полям стартовые значения.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Найдите на форме компонент ADOTABLEMOS и напишите обработчик свойства AfterInsert:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TMainFrm.ADOTableMOsAfterInsert(DataSet: TDataSet);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">var</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> year, month, day: Word;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName:array[1..12] of string[8]; // Объявление одномерного массива фиксированного размера</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Присвоение начальных значений элементам массива</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[1]:='Январь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[2]:='Февраль';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[3]:='Март';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[4]:='Апрель';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[5]:='Май';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[6]:='Июнь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[7]:='Июль';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[8]:='Август';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[9]:='Сентябрь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[10]:='Октябрь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[11]:='Ноябрь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> monthName[12]:='Декабрь';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Декодирование текущей даты Date() функцией DecodeDate(). Результат - в переменных year, month, day</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> DecodeDate(Date(), year, month, day);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // Добавление значений по умолчанию в список мемориальных ордеров</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableMOs.FieldByName('Mes').Value:= IntToStr(month);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableMOs.FieldByName('Name').Value:= monthName[month]; // Значение из массива по номеру месяца</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div class="separator" style="clear: both;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Теперь при добавлении новой записи программа поможет оператору:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw2rotScABH0-d5BPHriq_FDiZP65_GLxKxdE71IsKS_bYIKhTvLN6Rzx8xZIbf9mfQGXL_Bf0HdErYNksh2TzH70jbfwyjdKDB4jpCGhXB57rz11bjpv2YCqE9-EXoMhCdrvM0Wj3JblR/s1600/39_03.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw2rotScABH0-d5BPHriq_FDiZP65_GLxKxdE71IsKS_bYIKhTvLN6Rzx8xZIbf9mfQGXL_Bf0HdErYNksh2TzH70jbfwyjdKDB4jpCGhXB57rz11bjpv2YCqE9-EXoMhCdrvM0Wj3JblR/s640/39_03.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Вы можете смело продолжить работу, а я попутно хочу заметить</div>
<div class="separator" style="clear: both; text-align: left;">
1. Массив <span style="color: orange;">monthName </span>можно объявить не в этой процедуре, а выше - на уровне модуля, сделав его не локальным, а глобальным по отношению к данному модулю, если его значения необходимы в других процедурах. Тогда объявление массива можно было бы совместить с присвоением его элементам значений:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span id="internal-source-marker_0.8443231640849262" style="text-align: -webkit-auto;"></span></div>
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 2.25pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 13px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;">monthName: array[1..12] of String[8]=</span><b id="internal-source-marker_0.8443231640849262"></b></div>
<div dir="ltr" style="display: inline !important; margin-bottom: 0pt; margin-left: 2.25pt; margin-top: 0pt;">
<b id="internal-source-marker_0.8443231640849262"><span style="font-family: Arial; font-size: 13px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;">('Январь','Февраль','Март',и т.д. до,'Декабрь');</span></b></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
2. Алгоритм "угадывания" названия месяца по его номеру можно вынести в DLL в виде отдельной функции, так как он может понадобится не только в этой программе, но и в других.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
3. На основе этого несложного алгоритма можно сделать компонент, на входе которого будет номер месяца, а на выходе - его название.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Все хорошо, пока пользователь не стер одно из подставленных данной процедурой значений. </div>
<div class="separator" style="clear: both; text-align: left;">
В такой ситуации ошибки повторятся. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Ладно бы стер... он может нажать кнопку "Добавить" пару раз, и в справочнике легко появятся два, а то и три апреля...</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_MjTJt74Y3JETBl0vLBMmsO4xHsBoJxPLYTf4W6SPbw3rPUZlhhf1PQbgy42Lol-SV14eKJ0phZnJOYLpi1HI-MfEEOwK8zJXfywUb-hrRvNRbHWDdAsITp_RIzEWmycKMOiGhTAKIm3U/s1600/39_04.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_MjTJt74Y3JETBl0vLBMmsO4xHsBoJxPLYTf4W6SPbw3rPUZlhhf1PQbgy42Lol-SV14eKJ0phZnJOYLpi1HI-MfEEOwK8zJXfywUb-hrRvNRbHWDdAsITp_RIzEWmycKMOiGhTAKIm3U/s640/39_04.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Помните, я говорил <a href="http://pro-delphi.blogspot.com/2012/03/38.html">в уроке 38</a>, что обработчик ошибок нужен при выполнении Post? Давайте поправим ситуацию, пока не поздно.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Займемся этим оператором. А точнее - событием, предшествующим сохранению введенных в Grid значений в источнике, под сеткой подложенной таблице. Событие это носит название BeforePost. Именно в этот момент, перед выполнением операции сохранения данных, уместно сделать проверку на предмет: "Подходят ли нам введенные значения?"</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Для этого напишем вот такой обработчик события BeforePost</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;">procedure TMainFrm.ADOTableMOsBeforePost(DataSet: TDataSet);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> function TheTestMos(): Boolean;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> var</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr: String;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p: boolean;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p:= True; // Признак успешности проверки</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:= ADOTableMos.FieldByName('Name').AsString;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if (MyStr='')</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.TitleString:='Ошибка';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.MessageString:='Пустые значения в названии не допустимы';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.Buttons:=[mbOK];</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.ShowMessage;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> abort; // Не показывать пользователю стандартное сообщение об ошибке</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Result:=p;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> If not TheTestMos</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> ADOTableMOs.Cancel;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;">end;</span></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Попутно замечу, что выделив алгоритм проверки в отдельную функцию TheTestMos, я не преследовал никакой иной цели, кроме иллюстрации такой возможности. Такой прием был бы оправдан, если бы вызов функции повторялся в теле процедуры более одного раза.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Но это - так... лирика. Смоделировав некорректный ввод пользователя, мы получим на экран сообщение:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsi4sfnDHx81VIPMSRow5xFS5jqmGmRDQdISI9GSO6R-PHCxNkYMNr599RDR0fHiVrRVZdzP5OZGw_LNrs5EFcM4jqIrbw0m5XxrG9sx3O_DThoVGTcvkIzzThVRVsuoCt25uMaRIKtfGT/s1600/39_05.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsi4sfnDHx81VIPMSRow5xFS5jqmGmRDQdISI9GSO6R-PHCxNkYMNr599RDR0fHiVrRVZdzP5OZGw_LNrs5EFcM4jqIrbw0m5XxrG9sx3O_DThoVGTcvkIzzThVRVsuoCt25uMaRIKtfGT/s400/39_05.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Первая часть проверки (попытка ввести мемориальный ордер без названия) успешно сработала. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Аналогично нужно сделать проверку введенного значения в поле Mes.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
А еще необходимо как-то решить вопрос с двумя апрелями, что на мой взгляд интереснее.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Для этого понадобится запрос TADOQuery, который необходимо разместить на форме. Я назову его TempQuery.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9nYqg0dopeOxDkfhsXbGHgN_lLXHCjw5CA7oB_ujwMl1Z_nV8_X5ftyLtyZj2PF-oKNhq3xAKSmUXiowB_EV83QcTmztPyJVhBxFwFqPQK3bzqAGajItS4g3LXuOpqAB-yzYEAZqG8FuX/s1600/39_06.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9nYqg0dopeOxDkfhsXbGHgN_lLXHCjw5CA7oB_ujwMl1Z_nV8_X5ftyLtyZj2PF-oKNhq3xAKSmUXiowB_EV83QcTmztPyJVhBxFwFqPQK3bzqAGajItS4g3LXuOpqAB-yzYEAZqG8FuX/s400/39_06.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
И дополню функцию проверки: </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // 1-я проверка на отсутствие названия мемориального ордера</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:= ADOTableMos.FieldByName('Name').AsString;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if (MyStr='')</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.TitleString:='Ошибка';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.MessageString:='Пустые значения в названии не допустимы';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.Buttons:=[mbOK];</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.ShowMessage;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> abort; // Не показывать пользователю стандартное сообщение об ошибке</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> // 2-я проверка на отсутствие номера месяца</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:= ADOTableMos.FieldByName('Mes').AsString;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> if (MyStr='')</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.TitleString:='Ошибка';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.MessageString:='Пустые значения в поле Месяц не допустимы';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.Buttons:=[mbOK];</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.ShowMessage;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> abort; // Не показывать пользователю стандартное сообщение об ошибке</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<br />
<div class="separator" style="clear: both;">
<span style="color: orange;"> // 3-я проверка на ввод повторной записи</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> TempQuery.Active:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> TempQuery.SQL.Clear;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyStr:='SELECT * FROM MOs WHERE (Name='''+MyStr+''') AND (Mes='+ADOTableMos.FieldByName('Mes').AsString+')';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> TempQuery.SQL.Add(MyStr);</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> TempQuery.Active:=True;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> If not TempQuery.Eof</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Then</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> p:=False;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.TitleString:='Ошибка';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.MessageString:='Запись с такими значениями уже имеется в базе данных...';</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.Buttons:=[mbOK];</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> MyMessenger.ShowMessage;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> Abort;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: orange;"> TempQuery.Active:=False;</span></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Запустив программу, после нажатия кнопки "Добавить" мемориальный ордер, ничего не меняя нажму "Сохранить" и опять увижу два апреля. Почему?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Вот тут я готов начать разговор о средствах отладки.</div>
<div class="separator" style="clear: both; text-align: left;">
Простейшее из имеющегося богатого набора - это точка останова. Щелкните мышкой на сером поле в строке №967 ( TempQuery.SQL.Add(MyStr);). Появившаяся красная точка - точка, где программа остановится в процессе выполнения.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если теперь навести курсор на переменную MyStr, то в хинте будет выведено значение, которое эта переменная имеет на данный момент:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsfY2CjQggYeKGP8E8ULBYBgeZWlaUjYQUYV4eL_t36KhFm7zO58PKPbhRcG66vWlZzN5riE4Wu06U6bAwJuhOkmXR4k9NutrlVsXwoF8UtAiFTGIehR2VT8z-MfwA1985WJDp_EO8dBHA/s1600/39_08.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="82" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsfY2CjQggYeKGP8E8ULBYBgeZWlaUjYQUYV4eL_t36KhFm7zO58PKPbhRcG66vWlZzN5riE4Wu06U6bAwJuhOkmXR4k9NutrlVsXwoF8UtAiFTGIehR2VT8z-MfwA1985WJDp_EO8dBHA/s640/39_08.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В название месяца из той же переменной MyStr подставляется номер (4), полученный ею на этапе предыдущей проверки. Выход прост: переставьте местами 1-ю и 2-ю проверку:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifdrYlCwHeCaPXdCzp6ldoAKDNWqtQNsghDG3Sn-iMpgMmG1SV9agklOx1LL498pj1t6HxaEqoahy_7GkKjuNz7NCkcJTgS6dT5UikAeR5k5_IuPkk2STm59GgVm3YZ4aGmMsKrwr8j3Ei/s1600/39_07.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="433" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifdrYlCwHeCaPXdCzp6ldoAKDNWqtQNsghDG3Sn-iMpgMmG1SV9agklOx1LL498pj1t6HxaEqoahy_7GkKjuNz7NCkcJTgS6dT5UikAeR5k5_IuPkk2STm59GgVm3YZ4aGmMsKrwr8j3Ei/s640/39_07.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Вот теперь, если оператор будет пытаться сделать некорректные действия, программа постарается его направить в мирное русло:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVp-5ik8fKFE-FhnZPWs-7L-qhFkkgXYlhmkZzqf6SHHiopDreIwRUQPN_tq_UlE-2kfG4cAgpqVk7zpXauiZdbXCQksU1CSjsszsg-9sd08napQp6rlqHXI3Ca_ZTaVDonZKvYHFggkN_/s1600/39_09.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVp-5ik8fKFE-FhnZPWs-7L-qhFkkgXYlhmkZzqf6SHHiopDreIwRUQPN_tq_UlE-2kfG4cAgpqVk7zpXauiZdbXCQksU1CSjsszsg-9sd08napQp6rlqHXI3Ca_ZTaVDonZKvYHFggkN_/s640/39_09.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
PS Точку останова нужно всегда ставить на следующей строчке, чтобы оператор присвоения значения (:=) уже был выполнен.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
PPS Можно ли было вместо запроса использовать Locate? </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-3403735872204364632012-04-06T14:24:00.001+04:002012-04-06T14:28:23.847+04:00Арифметика по МТС-овски<a href="http://goo.gl/photos/h2J3Yw1Z5e" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie0WspdGVzjbo1P4m2hCoraFWeHx2PjcA20MryguWGgmUDW6-aBR55V42d0OEjHJ2NKaBBPcpMezOrA0pH9ZpwfNDP6pCgjGqfnkuFMySSIb_60J2639z9B4V8oEVtjrzt0O_OYn0w39RX/s512/1333706541129.png" /></a><br />
<br />
Просто завидую программистам МТС!!! Пиши что хочешь - ответственности никакой!!!<br />
ПОЗОРИЩЕ!!!<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background: transparent !important; border-color: none !important; display: none; left: 0; margin: 0 !important; opacity: 1 !important; overflow: visible !important; padding: 0 !important; position: absolute !important; text-align: left !important; top: 0; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-5601052151493540732012-04-05T09:09:00.000+04:002012-04-05T09:09:36.041+04:00Приятно, черт возьмиВозникла необходимость яндекс погуглить на тему маски ввода, набираю в строке поиска:<br />
<br />
delphi Ehlib Grid EditMask<br />
<br />
и натыкаюсь на собственную публикацию в третьей позиции...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-cNyzHSPORPY/T30nzbX0bXI/AAAAAAAAGzU/1J69UmMH4_4/s1600/1333602252288.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="385" src="http://1.bp.blogspot.com/-cNyzHSPORPY/T30nzbX0bXI/AAAAAAAAGzU/1J69UmMH4_4/s640/1333602252288.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Читать не стал :-) нет там ответа на мой вопрос :-)</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-24066241204578925832012-03-23T14:35:00.000+04:002012-03-23T14:46:34.065+04:00Урок 38. Обработчик ошибок<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTo1JBmJ5yLpTV4iba-ZbBo3KSUwGoBynJDfbhbzRhQ6H-xDhxUy97epDF_Lje4KHqek52guWlHQWc1IBvmUq0m417Arkq-cY4htUBliYYljualmBcZnnQ1ggT5SX-tNYUloyzN5fYw5nA/s1600/38_01.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="84" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTo1JBmJ5yLpTV4iba-ZbBo3KSUwGoBynJDfbhbzRhQ6H-xDhxUy97epDF_Lje4KHqek52guWlHQWc1IBvmUq0m417Arkq-cY4htUBliYYljualmBcZnnQ1ggT5SX-tNYUloyzN5fYw5nA/s320/38_01.jpg" width="320" /></a></div>
Во <a href="http://pro-delphi.blogspot.com/2012/03/blog-post.html">времена фортрана</a> меня учили обходиться без оператора Goto. Использование оператора безусловного перехода считалось моветоном равным по грешности полному отсутствию комментариев в программе.<br />
<br />
А посему, считаю, что каждый вправе придумать свой алгоритм обработчика ошибок... Я лишь покажу один из возможных вариантов.<br />
<br />
Первый вопрос, который я предвижу от слабо посвященных: "<span style="color: red;">А зачем?</span>"<br />
Действительно, пишешь задачу, как "честная кнопка", пытаешься ничего не упустить, все предусмотреть, собственное творчество, как правило, себе нравится, и не вызывает сомнений правильность его алгоритма... И все же! Если задачка небольшая - все просто и прозрачно. Но, если алгоритм сложен... как говорят "глаз замыливается", перестает находить узкие места. К тому же накладывается человеческий фактор: откуда Вам было знать, что пользователь не введет значение в поле и нажмет "Enter"?.. В этот момент Ваша программа напугает его каким-нибудь англоязычным сообщением да еще и с пиктограммой "Error"... А, <a href="http://pro-delphi.blogspot.com/2011/04/blog-post.html">если Вы помните</a>, я с самого начала просил Вас уважать пользователя и заказчика. Стоит ли доводить ситуацию до общения с плохо вменяемым пиплом?! Если Вы не хотите общаться с человеком, у которого от испуга вытаращены глаза и трясутся руки, нужно научиться предугадывать (перехватывать) ошибки и выдавать на экран сообщения на родном для пользователя языке, желательно с номером Вашего телефона... Это и есть часть понятия "дружественный интерфейс".<br />
<br />
Следующий вопрос, к которому я хочу приблизить тебя, дорогой читатель, это вопрос:<br />
<br />
<span style="color: red;">где и когда нужен обработчик ошибок?</span><br />
<br />
Стоит ли, на эту тему рыться в учебниках? И "да", и "нет". Почему? Программа, о которой в настоящий момент идет речь ("Расходы"), работает с базой данных, а найти в книжках этот материал - ой как не просто, поскольку большую часть книжного пространства авторы отводят, как правило, обучению работе с базой данных (создание, подключение, запросы и т.п.). Можно долго и упорно рыться в интернете, гуглить яндекс и задавать вопросы на форумах - в конце концов, Вы соберете нужную инфу, но упустите время...<br />
<br />
Я же со своей стороны предлагаю почаще спрашивать себя "А вдруг?"<br />
А вдруг сервер не сохранит запись?<br />
А вдруг пользователь не введет допустимое значение и что-нибудь нажмет, закроет окно и т.п.<br />
А вдруг такая запись уже есть в базе данных?<br />
А вдруг...<br />
<br />
Чем большим количеством подобных вопросов Вы себя озадачите, тем меньше вероятность того, что Ваша программа в руках незадачливого пользователя перейдет в состояние "Не отвечает".<br />
<br />
Наиболее общая схема обработчика ошибок выглядит примерно так:<br />
<br />
<ul>
<li>Объявление необходимых переменных и присвоение им стартовых значений.</li>
<li>Выполнение основного алгоритма, в процессе которого проверяются возможные условия возникновения ошибок</li>
<li>Обработка ошибок</li>
<li>Выдача сообщения оператору</li>
</ul>
<div>
Я предлагаю вернуться к <a href="http://pro-delphi.blogspot.com/2012/03/37.html">предыдущему уроку</a> и на примере описанных в нем процедур "сочинить" несложный обработчик ошибок.</div>
<div>
<br /></div>
<div>
Добавьте в объявление переменных в процедуре SetLang() еще парочку:</div>
<div>
<br /></div>
<div>
<div>
Var</div>
<div>
ini: TIniFile;</div>
<div>
<div style="color: #38761d;">
ErrKod: integer;</div>
<div style="color: #38761d;">
ErrMsg: String;</div>
<div style="color: #38761d;">
<br /></div>
<div>
а так же - объявление метки:</div>
</div>
</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #38761d;">Label</span></div>
<div>
<span style="color: #38761d;"> ErrLabel;</span></div>
</div>
<div>
<br /></div>
<div>
и стартовые значения:</div>
<div>
<br /></div>
<br />
<span style="color: #38761d;">begin</span><br />
<div>
<br /></div>
<div>
<span style="color: #38761d;"> ErrKod:=0; // Это значение при отсутствии ошибок</span></div>
<div>
<span style="color: #38761d;"> ErrMsg:= 'Операция завершена успешно';</span></div>
<div>
<br /></div>
Настройте заранее (в начале процедуры) компонент, выдающий сообщения:<br />
<br />
<br />
<span style="color: #38761d;"> MyMessenger.TitleString:='Ошибка...';</span><br />
<span style="color: #38761d;"> MyMessenger.MessageType:=mtError;</span><br />
<span style="color: #38761d;"> MyMessenger.Buttons:=[mbOK];</span><br />
<div>
<br /></div>
<br />
Затем - напишите проверку наличия файла языковой поддержки:<br />
<br />
<br />
<span style="color: #38761d;"> If Not FileExists(GetCurrentDir + '\'+Lang)</span><br />
<span style="color: #38761d;"> then</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> ErrKod:=1;</span><br />
<span style="color: #38761d;"> ErrMsg:='При попытке открытия файла языковой настройки произошла ошибка';</span><br />
<span style="color: #38761d;"> end;</span><br />
<div>
<br /></div>
<br />
Почему именно здесь нужно предусмотреть какие-то действия? А вдруг в файле настроек указан несуществующий файл? Или его кто-то с диска того... нечаянно стер...<br />
<br />
Следом должна идти проверка на наличие ошибок:<br />
<br />
<br />
<span style="color: #38761d;"> if ErrKod>0</span><br />
<span style="color: #38761d;"> then</span><br />
<span style="color: #38761d;"> Goto ErrLabel;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">...</span><br />
<div>
<br /></div>
<br />
Если в результате этой проверки выясняется, что код ошибки стал больше нуля (а проверок может быть несколько и код ошибки может принимать десяток разных значений), то оператор безусловного перехода, минуя основную ветвь алгоритма, отправит нас на метку ErrLabel, после которой и написан нехитрый в данном случае обработчик ошибок:<br />
<br />
<br />
<span style="color: #38761d;">...</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">ErrLabel:</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> MyMessenger.MessageString:=ErrMsg;</span><br />
<span style="color: #38761d;"> MyMessenger.ShowMessage;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">end; // Процедуры</span><br />
<span style="color: #38761d;"><br /></span><br />
Давайте нашалим: переименуем файл Rus.lng, например в Rus1.lng, чтоб программа его уж точно не нашла.<br />
<br />
Тогда при старте Rashod.exe будет произведена попытка настроить интерфейс приложения с помощью указанного в файле настроек Rashod.ini, в секции [Constants], в переменной LangFileName файла Rus.lng, которого в рабочем каталоге нет. Сработает обработчик ошибки, и на экране будет выведено придуманное нами сообщение:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibCairNDtovkY-n552_S7RRMstRK9cEMomrZc751f_-qEnb9Sd9hBda7kaSaUkWQN-_pQgFkWIzqPPtsmyW6o4P7eLZ4Q0jd0cvITcd9wdMdYw8_Rys99SK6ShkYd8KvLD12MdYtkJu-ob/s1600/38_02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibCairNDtovkY-n552_S7RRMstRK9cEMomrZc751f_-qEnb9Sd9hBda7kaSaUkWQN-_pQgFkWIzqPPtsmyW6o4P7eLZ4Q0jd0cvITcd9wdMdYw8_Rys99SK6ShkYd8KvLD12MdYtkJu-ob/s400/38_02.jpg" width="400" /></a></div>
<br />
В данной ситуации больше никаких мер принимать не нужно, так как интерфейс программы получит те надписи и пункты меню, которые были заложены в него при проектировании. Я еще раз подчеркиваю, что я лишь показываю как, а Вам уже думать, где это применять.<br />
<br />
Верните переименованному файлу его законное название и запустите программу еще раз.<br />
Вы получите еще одно сообщение:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwMrT4RvUYBWFQ_J6qZs3rOwVsLzFThueOKGh_OhprTbiFEpIaStAZ7VX0TNmPk4yygFIkVKumgJ5K9YoV2eEveCAoscDM6_mStG9kLsLfs3Sq4yNeeH3IMF9kcxxaWEW5hRQ9-WkRQP52/s1600/38_03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwMrT4RvUYBWFQ_J6qZs3rOwVsLzFThueOKGh_OhprTbiFEpIaStAZ7VX0TNmPk4yygFIkVKumgJ5K9YoV2eEveCAoscDM6_mStG9kLsLfs3Sq4yNeeH3IMF9kcxxaWEW5hRQ9-WkRQP52/s1600/38_03.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
не корректное по оформлению и неуместное по сути (если ошибок нет, нужно ли в данном случае вообще выводить какое-то сообщение?!).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Давайте поправим ситуацию:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;">ErrLabel:</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> Case ErrKod of</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> 0: // Ошибок нет</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> else</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> begin</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> MyMessenger.MessageString:=ErrMsg;</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> MyMessenger.ShowMessage;</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> end;</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"> End;</span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="color: #38761d;">end; // Процедуры</span></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
Теперь в отсутствии ошибок программа загрузится в штатном режиме, т.е. без лишних сообщений.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
В заключение хочу заметить, что обработчики ошибок при работе с базой данных чаще всего нужны при выполнении оператора Post, посылающего данные в источник.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<div>
<br /></div>
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com2tag:blogger.com,1999:blog-8494755139146574371.post-44310086745731712452012-03-23T11:28:00.000+04:002012-03-23T11:28:57.105+04:00А знаете, кто написал первый компьютерный вирус?Ваш покорный слуга.<br />
<br />
Шучу, конечно.<br />
<br />
Дело было во времена фортрана.<br />
<br />
У нас на кафедре было заведено так: сочинил программу к курсовому или еще по какому торжественному случаю - набивай её на перфокартах. Колоду перфокарт упакуй аккуратненько, чтоб не рассыпалась (не приведи Господи!), подпиши разборчиво, положи ее в специальный шкафчик и иди гуляй, потому что когдааа-а-а оператор вычислительного зала возьмет ее своими бесценными ручками и запустит в считыватель M4030, не известно... К тому же, вдруг кто-нибудь совсем безрукий по неосторожности опять паяльник разогретый в процессор уронит... Тогда - совсем плохо...<br />
<br />
Короче: "Приходите завтра" - это не название фильма а ваш девиз с того памятного момента и до бесконечности...<br />
<br />
Многим везло: их бесконечность сокращалась до одного-двух дней, по прошествии которых они находили в другом, расположенном по соседству шкафчике, свою колоду, обернутую в долгожданный листинг...<br />
<br />
И вот пока колода перфокарт лежит в первом шкафчике и ждет прикосновения чудотворящих рук оператора, можно было поупражняться в написании первых вирусов, благо - машинка по набивке перфокарт располагалась тут же, рядом. Спросите любого программиста, какую переменную он чаще всего использует для счетчика, и окажется, что любимая буква программистов "I".<br />
<br />
На это и был основной расчет: в каждой программе переменная I объявлена, значит ей можно пользоваться... вот вам и уязвимость...<br />
<br />
Покоритель вирусов набивал три карточки примерно такого содержания (в синтаксисе языка я могу ошибаться, но не в сути):<br />
<br />
I=0<br />
Label1: I=I+1<br />
GOTO Label1<br />
<br />
и впихивал их незаметно для постороннего глаза в колоду потолще в серединку, в любое место... главное, чтобы подряд... какой-нибудь вредозе...<br />
<br />
Дальше, если вредоза не написала глупостей и мертвых ветвей в ее алгоритме нет, то через какое-то время из машинного зала раздавался мат по поводу переполнения оперативной памяти, зависания процессора и упавшего на ногу кому-то раскаленного паяльника...<br />
<br />
Далеко разносился вопль негодования по гулким коридорам высшей школы и затихал где-то под прокуренной лестницей...<br />
<br />
Значит: сработало...<br />
<br />
А скоро - первое апреля...<br />
<br />
<br />
<br />
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-38076408067393514612012-03-21T11:40:00.000+04:002012-03-21T11:51:05.432+04:00Урок 37. Локализация интерфейсаНаверное, не правильно говорить о переводе всех названий пунктов меню и кнопок на другие языки, если Вы пишете программу для использования в домашнем хозяйстве. Да, это так, если не учитывать, что на страницах этого сайта я преследую несколько иную цель: не дать исходники, а дать "know how" - умения.<br />
<br />
Я уже где-то говорил, и не устану повторять: для решения той или иной задачи существует несколько способов. Вдаваться в полемику в пользу того или иного мне не интересно. Лишь обозначу, что для решения задачи локализации можно использовать библиотеку, т.е. Dll-ку, а можно - файл настроек. Обязательно найдутся охотники по ратовать за использование реестра Windows. Это, еще раз повторю - дело вкуса. В каждом из способов есть свои достоинства и свои недостатки.<br />
<br />
Известно, что файл настроек может иметь вот такую структуру:<br />
<br />
<span style="color: orange;">[Название секции]</span><br />
<span style="color: orange;">Имя переменной1=Значение переменной1</span><br />
<span style="color: orange;">Имя переменной2=Значение переменной2</span><br />
<span style="color: orange;">...</span><br />
<span style="color: orange;">Имя переменнойN=Значение переменнойN</span><br />
<span style="color: orange;"><br /></span><br />
Т.е. в разных файлах можно одной и той же переменной присваивать различные значения. Указав такую переменную в качестве, допустим, надписи на кнопке, мы сможем получить надписи на различных языках, если при загрузке формы брать данные из определенного заранее файла.<br />
<br />
Заниматься переводом подписей на всех без исключения элементах управления я не стану: долго и нудно. Покажу лишь на примере главного меню формы MainFrm, как это реализуется.<br />
<br />
Чтобы файлы языковой поддержки не путались с файлами настроек (ini), предлагаю дать им расширение *.lng.<br />
<br />
Вот примерное содержимое двух файлов для отображения интерфейса программы "Расходы" на русском и английском языках:<br />
<br />
<span style="color: #f1c232;">Rus.lng</span><br />
<br />
<br />
<span style="color: #38761d;">[MainFrm]</span><br />
<span style="color: #38761d;">MainFormCap=Расходы (главная форма)</span><br />
<span style="color: #38761d;">Menu_File=&Файл</span><br />
<span style="color: #38761d;">Menu_File_Exit=&Выход</span><br />
<span style="color: #38761d;">Menu_Data=&Данные</span><br />
<span style="color: #38761d;">Menu_Data_Edit=&Ввести</span><br />
<span style="color: #38761d;">Menu_Data_Insert=&Новая запись</span><br />
<span style="color: #38761d;">Menu_Data_Filter=&Фильтр</span><br />
<span style="color: #38761d;">Menu_Data_Credit=&Кредиты</span><br />
<span style="color: #38761d;">Menu_Data_Export=&Экспорт</span><br />
<span style="color: #38761d;">Menu_Data_Import=&Импорт</span><br />
<span style="color: #38761d;">Menu_Reports=&Отчетные формы</span><br />
<span style="color: #38761d;">Menu_Reports_Reverse_statement=&Оборотная ведомость</span><br />
<span style="color: #38761d;">Menu_Reports_Turnovers_account=&Обороты по счету</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_All=&Анализ затрат (все)</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_Gruops=Анализ затрат (по &группам)</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_Trends=Анализ &тенденций</span><br />
<span style="color: #38761d;">Menu_Codifiers=&Кодификаторы</span><br />
<span style="color: #38761d;">Menu_Codifiers_Accounts=&Счета</span><br />
<span style="color: #38761d;">Menu_Codifiers_Group_costs=&Группы затрат</span><br />
<span style="color: #38761d;">Menu_Codifiers_Memorial_warrants=&Мемориальные ордера</span><br />
<span style="color: #38761d;">Menu_Codifiers_Valuta=&Валюты</span><br />
<span style="color: #38761d;">Menu_Service=&Настройки</span><br />
<span style="color: #38761d;">Menu_Service_SelectDisk=Выбор &диска (пути к базе данных)</span><br />
<span style="color: #38761d;">Menu_Service_Language=&Выбор языка</span><br />
<span style="color: #38761d;">Menu_Service_Clear=&Очистка БД</span><br />
<span style="color: #38761d;">Menu_Help=&Справка</span><br />
<span style="color: #38761d;">Menu_Help_About=&О программе</span><br />
<div>
<br /></div>
<br />
<span style="color: #f1c232;">Eng.lng</span><br />
<br />
<br />
<span style="color: #38761d;">[MainFrm]</span><br />
<span style="color: #38761d;">MainFormCap=Expenses (Main form)</span><br />
<span style="color: #38761d;">Menu_File=&File</span><br />
<span style="color: #38761d;">Menu_File_Exit=&Exit</span><br />
<span style="color: #38761d;">Menu_Data=&Data</span><br />
<span style="color: #38761d;">Menu_Data_Edit=&Edit</span><br />
<span style="color: #38761d;">Menu_Data_Insert=&New Record</span><br />
<span style="color: #38761d;">Menu_Data_Filter=&Filter</span><br />
<span style="color: #38761d;">Menu_Data_Credit=&Credits</span><br />
<span style="color: #38761d;">Menu_Data_Export=&Export</span><br />
<span style="color: #38761d;">Menu_Data_Import=&Import</span><br />
<span style="color: #38761d;">Menu_Reports=&Reports</span><br />
<span style="color: #38761d;">Menu_Reports_Reverse_statement=&Reverse statement</span><br />
<span style="color: #38761d;">Menu_Reports_Turnovers_account=&Turnovers account</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_All=&Cost analysis (All)</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_Gruops=Cost analysis (&gruops)</span><br />
<span style="color: #38761d;">Menu_Reports_Cost_Analysis_Trends=Check &Trends</span><br />
<span style="color: #38761d;">Menu_Codifiers=&Codifiers</span><br />
<span style="color: #38761d;">Menu_Codifiers_Accounts=&Accounts</span><br />
<span style="color: #38761d;">Menu_Codifiers_Group_costs=&Group costs</span><br />
<span style="color: #38761d;">Menu_Codifiers_Memorial_warrants=&Memorial warrants</span><br />
<span style="color: #38761d;">Menu_Codifiers_Valuta=&Valuta</span><br />
<span style="color: #38761d;">Menu_Service=&Service</span><br />
<span style="color: #38761d;">Menu_Service_SelectDisk=&Select path</span><br />
<span style="color: #38761d;">Menu_Service_Language=&Language</span><br />
<span style="color: #38761d;">Menu_Service_Clear=&Clear data</span><br />
<span style="color: #38761d;">Menu_Help=&Help</span><br />
<span style="color: #38761d;">Menu_Help_About=&About prog</span><br />
<div>
<br /></div>
<div>
Файлы эти создаются как и файлы ini в любом текстовом редакторе, например: в блокноте.</div>
<div>
<span style="color: red;">Важно: </span><b>имена </b>переменных в этих файлах и<span style="color: red;"> </span><b>количество </b>строк, а следовательно и количество переменных, в этих файлах должно совпадать.</div>
<div>
<br /></div>
<div>
Кстати, в Rashod.ini должна пополниться секция:</div>
<div>
<div>
<br /></div>
<div>
<span style="color: #38761d;">[Constants]</span></div>
<div>
<span style="color: #38761d;">LangFileName=Rus.lng</span></div>
</div>
<div>
<br /></div>
<div>
- пусть уж программа стартует с привычного нам языка, чтоб самих себя не испугать :-)</div>
<div>
<br /></div>
<div>
На этом предварительные танцы с бубнами и беличьими хвостиками закончены. Открываем проект "Rashod".</div>
<div>
<br /></div>
<div>
И первое, что необходимо сделать - создать процедуру, устанавливающую локализацию, назову ее SetLang (не забудьте декларировать ее в секции private):</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #38761d;">procedure TMainFrm.SetLang();</span></div>
<div>
<span style="color: #38761d;">Var</span></div>
<div>
<span style="color: #38761d;"> ini: TIniFile;</span></div>
<div>
<span style="color: #38761d;">begin</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Настройка интерфейса программы (по выбранному языку)</span></div>
<div>
<span style="color: #38761d;"> ini:=TiniFile.Create(GetCurrentDir + '\'+Lang);</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> MainFrm.Caption:=Ini.ReadString('MainFrm','MainFormCap','');</span></div>
<div>
<span style="color: #38761d;"> N_File.Caption:=Ini.ReadString('MainFrm','Menu_File','');</span></div>
<div>
<span style="color: #38761d;"> N_Exit.Caption:=Ini.ReadString('MainFrm','Menu_File_Exit','');</span></div>
<div>
<span style="color: #38761d;"> N_Data.Caption:=Ini.ReadString('MainFrm','Menu_Data','');</span></div>
<div>
<span style="color: #38761d;"> N_Edit.Caption:=Ini.ReadString('MainFrm','Menu_Data_Edit','');</span></div>
<div>
<span style="color: #38761d;"> N12_Ins.Caption:=Ini.ReadString('MainFrm','Menu_Data_Insert','');</span></div>
<div>
<span style="color: #38761d;"> N10_Filter.Caption:=Ini.ReadString('MainFrm','Menu_Data_Filter','');</span></div>
<div>
<span style="color: #38761d;"> N_Credit.Caption:=Ini.ReadString('MainFrm','Menu_Data_Credit','');</span></div>
<div>
<span style="color: #38761d;"> N_ExportToMDB.Caption:=Ini.ReadString('MainFrm','Menu_Data_Export','');</span></div>
<div>
<span style="color: #38761d;"> N_Import.Caption:=Ini.ReadString('MainFrm','Menu_Data_Import','');</span></div>
<div>
<span style="color: #38761d;"> N_Reports.Caption:=Ini.ReadString('MainFrm','Menu_Reports','');</span></div>
<div>
<span style="color: #38761d;"> N3.Caption:=Ini.ReadString('MainFrm','Menu_Reports_Reverse_statement','');</span></div>
<div>
<span style="color: #38761d;"> N4.Caption:=Ini.ReadString('MainFrm','Menu_Reports_Turnovers_account','');</span></div>
<div>
<span style="color: #38761d;"> N_Analiz.Caption:=Ini.ReadString('MainFrm','Menu_Reports_Cost_Analysis_All','');</span></div>
<div>
<span style="color: #38761d;"> N_AnalizGroup.Caption:=Ini.ReadString('MainFrm','Menu_Reports_Cost_Analysis_Gruops','');</span></div>
<div>
<span style="color: #38761d;"> N_Analiz_Trends.Caption:=Ini.ReadString('MainFrm','Menu_Reports_Cost_Analysis_Trends','');</span></div>
<div>
<span style="color: #38761d;"> N_Kodifikators.Caption:=Ini.ReadString('MainFrm','Menu_Codifiers','');</span></div>
<div>
<span style="color: #38761d;"> N1.Caption:=Ini.ReadString('MainFrm','Menu_Codifiers_Accounts','');</span></div>
<div>
<span style="color: #38761d;"> N_ExpGr.Caption:=Ini.ReadString('MainFrm','Menu_Codifiers_Group_costs','');</span></div>
<div>
<span style="color: #38761d;"> N2.Caption:=Ini.ReadString('MainFrm','Menu_Codifiers_Memorial_warrants','');</span></div>
<div>
<span style="color: #38761d;"> N_Val.Caption:=Ini.ReadString('MainFrm','Menu_Codifiers_Valuta','');</span></div>
<div>
<span style="color: #38761d;"> N_Serv.Caption:=Ini.ReadString('MainFrm','Menu_Service','');</span></div>
<div>
<span style="color: #38761d;"> N7_SelectDisk.Caption:=Ini.ReadString('MainFrm','Menu_Service_SelectDisk','');</span></div>
<div>
<span style="color: #38761d;"> N_Serv_SelLang.Caption:=Ini.ReadString('MainFrm','Menu_Service_Language','');</span></div>
<div>
<span style="color: #38761d;"> N12_ServClear.Caption:=Ini.ReadString('MainFrm','Menu_Service_Clear','');</span></div>
<div>
<span style="color: #38761d;"> N_Help.Caption:=Ini.ReadString('MainFrm','Menu_Help','');</span></div>
<div>
<span style="color: #38761d;"> N_About.Caption:=Ini.ReadString('MainFrm','Menu_Help_About','');</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> ini.Free;</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;">end;</span></div>
<div>
<br /></div>
</div>
<div>
Общий смысл этой процедуры, думаю, не вызывает вопросов, поскольку, о работе с ini фалами я уже <a href="http://pro-delphi.blogspot.com/2011/05/7-ini.html">рассказывал ранее</a>: открыли, считали нужные данные, присвоив их целевым надписям на элементах управления формы, освободились от ini файла.</div>
<div>
<br /></div>
<div>
Необходимая переменная Lang, хранящая имя языкового файла, должна быть объявлена в секции interface модуля формы. А вот значение в нее попадет в момент создания формы (Create), откуда - из Rashod.ini:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #38761d;">procedure TMainFrm.FormCreate(Sender: TObject);</span></div>
<div>
<span style="color: #38761d;">var</span></div>
<div>
<span style="color: #38761d;"> ini: TIniFile;</span></div>
<div>
<span style="color: #38761d;">begin</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Подключение и считывание из файла настроек ini</span></div>
<div>
<span style="color: #38761d;"> ini:=TiniFile.Create(GetCurrentDir + '\Rashod.ini');</span></div>
<div>
<span style="color: #38761d;"> Lang:=Ini.ReadString('Constants','LangFileName','');</span></div>
<div>
<span style="color: #38761d;"> ini.Free;</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> SetLang;</span></div>
</div>
<div>
<span style="color: #38761d;">...</span></div>
<div>
<br /></div>
<div>
- И что? - скажете Вы после компиляции проекта, - никаких изменений нет.</div>
<div>
Видимых изменений нет. Попробуйте поменять в Rashod.ini Rus.lng на Eng.lng и еще раз запустить программу.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgySic7X1jTJWpAJqdQABiZFHQuoMbYRkOLL7XpWop27l92f13I15cWfEb5wOy4YhE6-oG1pEcDZlOXh345Nx4bVtp5kFp93Xl49WcKx5-8yroAoEuJf7B97tN_7jkNCohWQfmch8ZG0ygI/s1600/37_01.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="95" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgySic7X1jTJWpAJqdQABiZFHQuoMbYRkOLL7XpWop27l92f13I15cWfEb5wOy4YhE6-oG1pEcDZlOXh345Nx4bVtp5kFp93Xl49WcKx5-8yroAoEuJf7B97tN_7jkNCohWQfmch8ZG0ygI/s320/37_01.JPG" width="320" /></a></div>
<div>
Можно радоваться? </div>
<div>
Рано.</div>
<div>
<br /></div>
<div>
Хотелось бы, чтобы была возможность менять языковую настройку из самой программы.</div>
<div>
<br /></div>
<div>
Для этого нужно придумать обработку соответствующего пункта меню (Настройки - Выбор языка):</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #38761d;">procedure TMainFrm.N_Serv_SelLangClick(Sender: TObject); </span><span style="color: #38761d;">// Настройка. Выбор языка</span></div>
<div>
<span style="color: #38761d;">var</span></div>
<div>
<span style="color: #38761d;"> ini: TIniFile;</span></div>
<div>
<span style="color: #38761d;">begin</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Настройка фильтра файлов определенного типа в окне диалога</span></div>
<div>
<span style="color: #38761d;"> OpenDialog1.Filter:='Файлы языковой поддержки|*.lng';</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Выбор файла на диске</span></div>
<div>
<span style="color: #38761d;"> If not OpenDialog1.Execute</span></div>
<div>
<span style="color: #38761d;"> then // Отмена выбора</span></div>
<div>
<span style="color: #38761d;"> begin</span></div>
<div>
<span style="color: #38761d;"> exit;</span></div>
<div>
<span style="color: #38761d;"> end;</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Извлекается</span></div>
<div>
<span style="color: #38761d;"> Lang:=OpenDialog1.FileName; // Полный путь</span></div>
<div>
<span style="color: #38761d;"> Lang:=ExtractFileName(Lang); // Только имя файла</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Запись в соответствующую секцию Rashod.ini, чтобы</span></div>
<div>
<span style="color: #38761d;"> // в следующий раз программа стартовала с этими настройками</span></div>
<div>
<span style="color: #38761d;"> ini:=TiniFile.Create(GetCurrentDir + '\Rashod.ini');</span></div>
<div>
<span style="color: #38761d;"> Ini.WriteString('Constants','LangFileName',Lang);</span></div>
<div>
<span style="color: #38761d;"> ini.Free;</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Смена надписей на элементах управления</span></div>
<div>
<span style="color: #38761d;"> SetLang;</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;">end;</span></div>
<div>
<br /></div>
</div>
<div>
В комментариях я постарался дать необходимые пояснения. Вот теперь программа "Rashod" еще больше стала похожа на "взрослую" :-)</div>
<div>
<br /></div>
<div>
Я не затрагиваю так или иначе вопросы оптимизации уже написанного кода - это отдельная непростая история. Но здесь меня просто подмывает сделать оговорку:</div>
<div>
<br /></div>
<div>
вместо двух строк</div>
<div>
<br /></div>
<div>
<span style="color: #f1c232;"> Lang:=OpenDialog1.FileName; // Полный путь</span></div>
<div>
<span style="color: #f1c232;"> Lang:=ExtractFileName(Lang); // Только имя файла</span></div>
<br />
можно написать одну<br />
<br />
<div>
<span style="color: #38761d;"> Lang:=ExtractFileName(OpenDialog1.FileName);</span></div>
<div>
<br /></div>
<div>
Иногда приходится жертвовать красотой ради наглядности :-)</div>
<div>
<br /></div>
<div>
Если остались вопросы - пожалуйте на страницу <a href="http://pro-delphi.blogspot.com/p/blog-page.html">"Обратная связь"</a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com2tag:blogger.com,1999:blog-8494755139146574371.post-46722559117859574702012-03-20T15:38:00.000+04:002012-03-20T15:38:51.662+04:00Урок 36. Продолжаем разговор...Именно так любил приговаривать очаровательный мультяшный герой по имени Карслон, который живет на крыше...<br />
<br />
Прежде, чем углубиться дальше в лес Delphi и не только, я бы хотел оживить некоторые пункты меню проекта "Расходы".<br />
<br />
Шаг 1. Пункт меню <span style="color: red;">"О программе"</span><br />
<span style="color: red;"><br /></span><br />
Когда-то, в <a href="http://pro-delphi.blogspot.com/2011/06/13.html">уроке №13</a>, я рассказал о том, как сделать компонент "О программе". Вам придется его немного подправить :-) и разместить на форме MainFrm, а затем назначить соответствующему пункту меню вот такой простой обработчик:<br />
<br />
<br />
<span style="color: #38761d;">procedure TMainFrm.N_AboutClick(Sender: TObject);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"> PrDAboutBoxDlg1.Execute;</span><br />
<span style="color: #38761d;">end;</span><br />
<span style="color: #38761d;"><br /></span><br />
Наделите компонент следующими свойствами:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCskah_LeUInwLM78JHqYJ0H6Te_b-pi2Vsh1cOD8hlSyTj0PKVOGgcXLJBqR_aytuSxNicy-AJI-iTuCavFb4TkLpLiXLpRdAyohj-Edvj3417jUbd0KzjJgTZsej1kxpEsjYBrQov0e7/s1600/36_01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCskah_LeUInwLM78JHqYJ0H6Te_b-pi2Vsh1cOD8hlSyTj0PKVOGgcXLJBqR_aytuSxNicy-AJI-iTuCavFb4TkLpLiXLpRdAyohj-Edvj3417jUbd0KzjJgTZsej1kxpEsjYBrQov0e7/s640/36_01.JPG" width="640" /></a></div>
<br />
<br />
Щаг 2. Никто не обратил внимания, что<span style="color: red;"> кнопка Cancel</span> (PrDCancelButton1) на верхней панельке осталась без обработчика. Добавьте обработку действий, когда пользователь ничего не ввел в поля новой записи или передумал добавлять новую запись:<br />
<br />
<br />
<span style="color: #38761d;">procedure TMainFrm.PrDCancelButton1Click(Sender: TObject);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Отказ от редактирования</span><br />
<span style="color: #38761d;"> ADOTableMain.Cancel;</span><br />
<span style="color: #38761d;"> DBGridEh1.Enabled:=True; // Переключение грида в режим доступности</span><br />
<span style="color: #38761d;"> Panel3.Visible:=False; // Скрытие верней панели</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">end;</span><br />
<br />
Шаг 3. Новый <span style="color: red;">Action Data_Insert</span>, обрабатывающий процесс добавления новой записи, необходимо добавить в список ActionList и подложить его под соответствующие пункты главного меню и PopupMenu:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPTukLNe8y_I2Y7s1i3HRJkHwFzrL323q9wgbMG-EdN1SBybnwcJq7gEn5QEarF49hCK_1WFNtVuYa4Z9rxxr851NJv4kKLyAxaKYerZ6sBuwYL4okedPci6Thyphenhyphen7ag4fRnBscFKLOrS85j/s1600/36_02.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPTukLNe8y_I2Y7s1i3HRJkHwFzrL323q9wgbMG-EdN1SBybnwcJq7gEn5QEarF49hCK_1WFNtVuYa4Z9rxxr851NJv4kKLyAxaKYerZ6sBuwYL4okedPci6Thyphenhyphen7ag4fRnBscFKLOrS85j/s640/36_02.JPG" width="640" /></a></div>
<br />
Обработчик события выполнения экшена:<br />
<br />
<br />
<span style="color: #38761d;">procedure TMainFrm.Data_InsertExecute(Sender: TObject);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Новая запись</span><br />
<span style="color: #38761d;"> ADOTableMain.Insert;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">end;</span><br />
<span style="color: #38761d;"><br /></span><br />
<br />
Внимание! Не забыть вернуться к процедуре:<br />
<br />
<span style="color: #38761d;">procedure TMainFrm.Data_SelectMOExecute(Sender: TObject); // Соответствует N_EditClick</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;">...</span><br />
<span style="color: #38761d;"> // Сделать доступным именно Action, а пункты меню станут доступными автоматически</span><br />
<span style="color: #38761d;"> Data_Insert.Enabled:=True;</span><br />
<span style="color: #38761d;"><br /></span><br />
Шаг 4. <span style="color: red;">Выбор базы данных</span><br />
<div>
<br /></div>
<div>
Добавьте Action в категорию Service</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhk_zC5WItCbdUukFt0e7L2qnogrdhpyKc3aluYm3OpDOpuFzqA4el3EOzk_wQ-em_yWD_ETxv3BSpSeT7_65ru6bm-KFh4ybLY29Te4Tws-R8PbL8JZ0HD2chlY6YFGITKVfd4PyMNo2D/s1600/36_03.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhk_zC5WItCbdUukFt0e7L2qnogrdhpyKc3aluYm3OpDOpuFzqA4el3EOzk_wQ-em_yWD_ETxv3BSpSeT7_65ru6bm-KFh4ybLY29Te4Tws-R8PbL8JZ0HD2chlY6YFGITKVfd4PyMNo2D/s640/36_03.JPG" width="640" /></a></div>
<div>
<br /></div>
<div>
Создайте обработчик Action:</div>
<div>
<br /></div>
<br />
<br />
<br />
<span style="color: #38761d;">procedure TMainFrm.Service_Select_DiskExecute(Sender: TObject);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Выбор диска с базой данных</span><br />
<span style="color: #38761d;"> SetDisk;</span><br />
<span style="color: #38761d;"> MainConnecting;</span><br />
<span style="color: #38761d;"> TableActive(True);</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Инфо на статусбаре</span><br />
<span style="color: #38761d;"> StatusBarUpdate;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">end;</span><br />
<br />
Установите соответствие пункта меню и нового действия.<br />
Данный пункт меню позволит Вам выбрать для просмотра и работы другую базу данных (например, по прошествии года, после архивации базы данных, сохранения ее в другом каталоге).<br />
<br />
На этом пока все.<br />
В следующем уроке я предполагаю показать как "перевести" интерфейс программы на другой язык.<br />
<br />
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-57131689339514903862012-03-19T17:29:00.001+04:002012-03-19T17:29:23.874+04:00Урок 35. Оборотная ведомость. Печать отчетаЕсли Вы, изучив <a href="http://pro-delphi.blogspot.com/2012/03/34-dll.html">предыдущие уроки</a>, получили в свое распоряжение файл Excel, Вам не составит труда вывести его на печать. Но, не всегда такой вариант получения отчета приемлем.<br />
<br />
Для конструирования отчетов существует ряд средств. Я не берусь здесь обсуждать их достоинства и недостатки. Так исторически сложилось, что я пользуюсь платной версией Fast Report.<br />
<br />
Но, для того, чтобы попробовать, можно найти на <a href="http://www.fast-report.com/ru/download/free-report-download.html">сайте производителя</a> бесплатные или демо версии, а так же очень подробную документацию.<br />
<br />
Почему именно FastReport? Посмотрите <a href="http://www.fast-report.com/ru/contacts.html">здесь</a>. Не только из гордости за отечественного производителя, еще и за практически безграничные возможности.<br />
<br />
Установка компонентов FastReport не должна вызвать никаких трудностей. После установки, на Tool Palette появится ряд вкладок.<br />
<br />
Разместите на форме два компонента, с вкладки FastReport:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeVyaOsf78OuB92h_WqUmXyJbfggnnQFWhukupequmri90B5qpvwVJuCe7gDgfwlaNVX94VAWvpLZg5ikAJHzgXRLqyJkhBraE40QKIwn5frqpFReWtPIRmqNdFIadSNBONRKEb029gFU4/s1600/35_01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="321" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeVyaOsf78OuB92h_WqUmXyJbfggnnQFWhukupequmri90B5qpvwVJuCe7gDgfwlaNVX94VAWvpLZg5ikAJHzgXRLqyJkhBraE40QKIwn5frqpFReWtPIRmqNdFIadSNBONRKEb029gFU4/s640/35_01.JPG" width="640" /></a></div>
TfrxDBDataset - источник данных для отчета, TfrxReport - конструктор отчета.<br />
<br />
Теперь необходимо немного подготовиться и временно включить:<br />
<br />
1. Форма MainFrm: ADOConnection - Connected = True (если не задана строка подключения, задать ее).<br />
2. Форма OborotFrm, компонент CDS - свойство Connection = MainFrm.ADOConnection1 (т.е. связать этот компонент с ADOConnection на главной форме) и указать свойство TableName = Oborot. Собственно, это все проделывается программно, но нам нужно временно для создания отчета.<br />
<br />
Не забудьте по окончании создания отчета очистить значения этих свойств.<br />
<br />
Настройте компонент TfrxDBDataset, указав его свойство DataSet:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0AbDkBBB8a7yRbAa8y_d19jzh1Np462BX-BmhDHlCuHTaDU_vi0YalFns6FRDzv_QZSn4hI_R9fDqV5leaUz2JvHouQd4SM4G2cQaFtNNeE0jvHLLkJgeKpQqqUuQvpAEWjI39IDYhWyj/s1600/35_02.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0AbDkBBB8a7yRbAa8y_d19jzh1Np462BX-BmhDHlCuHTaDU_vi0YalFns6FRDzv_QZSn4hI_R9fDqV5leaUz2JvHouQd4SM4G2cQaFtNNeE0jvHLLkJgeKpQqqUuQvpAEWjI39IDYhWyj/s400/35_02.JPG" width="400" /></a></div>
А затем два раза щелкните по компоненту TfrxReport, чтобы перейти в конструктор отчета.<br />
Первое, что необходимо сделать - выбрать меню Report - Data и назначить источник данных для отчета, как показано на рисунке:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1c3kQwBbNvS92gqSzyX_6AuBStPb6IojncrHjtptrp1j7xiIeFY6ZUZNOiQxdTsAMRNNTLmAgSbjI6I_jWe34k73BRMyIK4B0m-k3ZveJ-7AA8NI9IHso7lmzp6_Xymff9llO1_6wdFpn/s1600/35_03.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1c3kQwBbNvS92gqSzyX_6AuBStPb6IojncrHjtptrp1j7xiIeFY6ZUZNOiQxdTsAMRNNTLmAgSbjI6I_jWe34k73BRMyIK4B0m-k3ZveJ-7AA8NI9IHso7lmzp6_Xymff9llO1_6wdFpn/s1600/35_03.JPG" /></a></div>
<br />
Затем - развернуть страницу на Landscape (альбомную) в меню File - Page Settings, т.к. отчет наш "широкий".<br />
<br />
Добавить "бэнды" - так называются области для размещения в них различных данных и группировке этих данных, как минимум - два - ReportTitle (заголовок отчета) и MasterData (мастер - для вывода данных отчета), связав последний с источником данных.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCSlzlLruSJQ9O487U8mD75RQbo4R5xuiZcKhbfEueaarYqvgm1FvSgxj7kyR9IchqPcxjAYPVMs_TAWLqreHLOumikbKhJZwN5JZLNkIEXjOSpzhdr3fGs50vjfLDdu4eQsSMyxwV0yBU/s1600/35_04.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="483" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCSlzlLruSJQ9O487U8mD75RQbo4R5xuiZcKhbfEueaarYqvgm1FvSgxj7kyR9IchqPcxjAYPVMs_TAWLqreHLOumikbKhJZwN5JZLNkIEXjOSpzhdr3fGs50vjfLDdu4eQsSMyxwV0yBU/s640/35_04.JPG" width="640" /></a></div>
<br />
Сохраните свой макет под именем Oborot.fr3.<br />
<br />
Теперь настало время дать отчету заголовок, нажав на пиктограмму "ab":<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbLuAUnPWkqUlz6cX-Fr-491C7i-f2uk8w__LqcE9QgL_7aRGq41S66-_Ox7IFf4yHYAQELL9yzDVcBB0oX-FZz767VeHomf5quC16JIrKYOos7rhopdWCnSyeOvT1RJrBagz9Idmi5xaF/s1600/35_05.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbLuAUnPWkqUlz6cX-Fr-491C7i-f2uk8w__LqcE9QgL_7aRGq41S66-_Ox7IFf4yHYAQELL9yzDVcBB0oX-FZz767VeHomf5quC16JIrKYOos7rhopdWCnSyeOvT1RJrBagz9Idmi5xaF/s320/35_05.JPG" width="320" /></a></div>
<br />
<br />
Форматируйте надпись подобно тому, как Вы это делали в MS WORD, здесь инструменты очень похожи:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7zgrjNmQX-TtbB8Fnd0qyaMRtUSobSJ3kk_eNN4GCUaaXQxWSRnKwPzRFsuSjw4pLeMgT9WTPwB73R8OVmpdGfYad7o5e9St9MiVuJX0nxbKyQwDvBAWXy7JWXiDlPT7OObnOtOmk3jr0/s1600/35_06.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7zgrjNmQX-TtbB8Fnd0qyaMRtUSobSJ3kk_eNN4GCUaaXQxWSRnKwPzRFsuSjw4pLeMgT9WTPwB73R8OVmpdGfYad7o5e9St9MiVuJX0nxbKyQwDvBAWXy7JWXiDlPT7OObnOtOmk3jr0/s400/35_06.JPG" width="400" /></a></div>
<br />
Перетащите одно поле для начала на MasterData (можно добавить еще заголовок страницы (PageHeader), где разместить заголовки колонок отчета):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3CbztmBEdZ_UmdjNKsbPx9dvPymhmNXpBChz2xunwbTD0oYwcJkpvcIcVIdLalfx0ciorqfXEAbB3_AvYvzMcfhZnGlvpHL4nm7Lfnf-YzFAmpymbunU87zp4RnYWsBY0D3PWgcS4grwn/s1600/35_07.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="603" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3CbztmBEdZ_UmdjNKsbPx9dvPymhmNXpBChz2xunwbTD0oYwcJkpvcIcVIdLalfx0ciorqfXEAbB3_AvYvzMcfhZnGlvpHL4nm7Lfnf-YzFAmpymbunU87zp4RnYWsBY0D3PWgcS4grwn/s640/35_07.JPG" width="640" /></a></div>
<br />
Опция Create caption удобна, но не в нашей языковой зоне: подписи = имена полей на латинице, так что подписи придется сделать ручками.<br />
<br />
Сохраните и закройте конструктор. Теперь нужно в Popup меню формы добавить новый пункт, по которому будет вызываться отчет:<br />
<br />
<br />
<span style="color: #38761d;">procedure TOborotFrm.N2Click(Sender: TObject);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"> // Вывод предварительного просмотра отчета</span><br />
<span style="color: #38761d;"> frxReport1.ShowReport(True);</span><br />
<span style="color: #38761d;">end;</span><br />
<br />
Если все сделано правильно, на этом этапе Вы получите список счетов с заголовком "Оборотная ведомость".<br />
<br />
Лично я предпочитаю табличное оформление (с рамочками), чему и Вы быстро научитесь, поскольку самое главное я уже рассказал:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEUNYuEjvpS3lsKxeuCpCVFdn0AP0KrKFZo75oRqYN3fZexgqhv6V5CAXWxbuwgspvEgKKXUOUZg5i9gf4JCv-pSLURztLU9OIOod-C7t-u_IJbRJ3Wt51qM2_DXmo3tBa5YfVzff6-P-m/s1600/35_08.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEUNYuEjvpS3lsKxeuCpCVFdn0AP0KrKFZo75oRqYN3fZexgqhv6V5CAXWxbuwgspvEgKKXUOUZg5i9gf4JCv-pSLURztLU9OIOod-C7t-u_IJbRJ3Wt51qM2_DXmo3tBa5YfVzff6-P-m/s640/35_08.JPG" width="640" /></a></div>
<br />
Главное рассказал, а важное и нужное - еще впереди.<br />
Мой дорогой читатель, наверное уже догадался, что в документе не хватает подзаголовка, т.е. периода, за который он составлен.<br />
<br />
Далее я покажу один из способов передачи данных посредством переменных в отчет.<br />
<br />
Добавьте перед строкой <span style="color: #38761d;"> </span>frxReport1.ShowReport(True) ровно такую же строку, какой задавался период при импорте отчета в Excel:<br />
<br />
<span id="internal-source-marker_0.7070868897717446"><span style="font-family: Arial; font-size: x-small;"><span style="white-space: pre-wrap;"><span style="color: #38761d;"> frxReport1.Script.Variables['Period']:='Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value);</span>
</span></span><span style="font-family: Arial; font-size: 13px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></span><br />
здесь Period - имя переменной, которую нужно разместить в конструкторе отчета в текстовом поле (memo) в квадратных скобках:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA5_ojPu7aOdbzQ1UoT4vmUvn15rJmCFpi5iRcheFKQ-A0gNf9GYuqmgB_lHQAdAi648XBLTLZksZxrHM6AF5A4oO9kjqsaqxZvTI8iM9Mipcb6bbwVVgroO5bRuweb7X5eYDsc_0ssDxp/s1600/35_09.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA5_ojPu7aOdbzQ1UoT4vmUvn15rJmCFpi5iRcheFKQ-A0gNf9GYuqmgB_lHQAdAi648XBLTLZksZxrHM6AF5A4oO9kjqsaqxZvTI8iM9Mipcb6bbwVVgroO5bRuweb7X5eYDsc_0ssDxp/s640/35_09.JPG" width="640" /></a></div>
<br />
Результат, прямо скажем еще далек от совершенства:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5yEBtL3ZMSImCczKu_BoRnEf9ZpINBvUHFZ7Ms25qeFGrpUl6OKYKEey4WWMf2yFRdOaLTMuSypwaWrpOgDItnluFbRbWs2aa3uNpl_ph86wBAhuAQN9A6YCjkcsx3L11o9serq4nNUFk/s1600/35_10.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5yEBtL3ZMSImCczKu_BoRnEf9ZpINBvUHFZ7Ms25qeFGrpUl6OKYKEey4WWMf2yFRdOaLTMuSypwaWrpOgDItnluFbRbWs2aa3uNpl_ph86wBAhuAQN9A6YCjkcsx3L11o9serq4nNUFk/s640/35_10.JPG" width="640" /></a></div>
<br />
числа нужно сдвинуть вправо, сделать их красивыми с помощью DisplayFormat (два знака после запятой) и подсчитать итоги по страницам (добавить пару бэндов)...<br />
<br />
Если не сможете разобраться - пишите (координаты Вы найдете через страницу <a href="http://pro-delphi.blogspot.com/p/blog-page.html">"Обо мне"</a>), и тогда будем разбираться вместе.<br />
<br />
А.В.<br />
<br />
<br />
<br />
<br />
<br />
<br />Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-85774942837036880902012-03-16T14:02:00.002+04:002012-03-16T14:20:46.890+04:00Урок 34. Создание библиотеки (Dll)<div style="text-align: right;">
<i>"...когда-то давно, когда наша Земля была еще маленькая </i></div>
<div style="text-align: right;">
<i>и тепленькая, и по ней бегали такие ма-а-а-аленькие...</i></div>
<div style="text-align: right;">
<i>и с тех пор пошло и пошло, пошло и пошло..."</i></div>
<br />
Мой отец коллекционировал записи А.Райкина, Р.Карцева и В.Ильченко, М.Мироновой и А.Менакера и других... Я любил слушать их вместе с ним, поэтому помню многое наизусть...<br />
<br />
Так вот, с тех пор как появилась вычислительная техника в виде камушков (первые счеты - абак) и пошло, и пошло, и пошло... Вот только задачи усложнялись временем... и повторялись...<br />
<br />
К чему я это все? Да к тому, что застав в своем развитии вычислительную машину ДВК-2М, я приобрел привычку экономно относиться к памяти. Кто из Вас сейчас, владеющих гигабайтными дисками, способен представить себе пятидюймовую дискету стандартным объемом 360 килобайт? При особом искусстве разметить (форматировать) эту дискету можно было на 720кБ. И, о счастье!, в ДВК было целых два дисковода! Значит, в распоряжении программиста - аж целых 1440 килобайт! Не тут-то было! А операционная система? Значит, на пространстве немногим более одного (!) мегабайта нужно было исхитриться и прожить. Но эта трудность была даже не главной. А крошечное ОЗУ? Вот где была настоящая засада! Вот куда нужно было умудриться запихнуть еще что-то помимо операционной системы! Собственно от этого и пошло то, о чем я сегодня поведу речь...<br />
<br />
Небольшие объемы оперативной памяти заставляли программистов делить задачу на кусочки и размещать в памяти только нужный фрагмент, именно тот, который сейчас будет использован в вычислениях, выбрасывая из памяти отработавший свою функцию кусок. Мало кто из современных авторов почитаемых мною сайтов, посвященных программированию, может припомнить BASICD и его замечательный оператор COMMON, дающий возможность загружать из библиотеки необходимую подпрограмму...<br />
<br />
Когда читаю на различных сайтах доводы в пользу Dll, у меня невольно они вызывают улыбку:<br />
при современных объемах оперативной памяти нет необходимости задумываться программисту об ее экономии. В принципе, программист может весь код забабахать в один модуль, получить на выходе огромного объема exe-к и радоваться. А что Вы говорите: пользователь будет долго ждать, пока этот exe-к загрузится? Пусть купит себе комп по мощнее...<br />
<br />
Так что с точки зрения программиста я особых удовольствий от использования библиотек не вижу. Тем более их нет, если Вы пишете одну программу, чтобы сдать, наконец тот самый ненавистный курсовой...<br />
<br />
Совсем другое дело, если у Вас много наработок. Тем более, если десяток программ используют одни и те же функции. Привести пример? Легко: перевод числа в строку прописью, подсчет доходности по ценным бумагам... в нашем случае - экспорт отчета в Excel.<br />
<br />
Да-да, именно этот функционал я и предлагаю перетащить в библиотеку, вдруг где-то еще понадобится?<br />
<br />
Начать следует с создания модуля библиотеки:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0qLWp2gM-VxLUMb35-C6kp6MjtMQ8ue8N86wC9mnroVwf8rRmdl6EMrwua8MR1yM1lOh3v-397p_8hp_Vc6MAl1K6tVcXiODkLUQJeR53v1SSU3sgEpYnWJ5UqzSZwSDITTrrcW9zUPlo/s1600/34_01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0qLWp2gM-VxLUMb35-C6kp6MjtMQ8ue8N86wC9mnroVwf8rRmdl6EMrwua8MR1yM1lOh3v-397p_8hp_Vc6MAl1K6tVcXiODkLUQJeR53v1SSU3sgEpYnWJ5UqzSZwSDITTrrcW9zUPlo/s400/34_01.JPG" width="400" /></a></div>
Много вопросов визард не задаст, но сгенерирует вот такое предупреждение:<br />
<br />
<br />
<span style="color: #38761d;">library Project1;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">{ Important note about DLL memory management: ShareMem must be the</span><br />
<span style="color: #38761d;"> first unit in your library's USES clause AND your project's (select</span><br />
<span style="color: #38761d;"> Project-View Source) USES clause if your DLL exports any procedures or</span><br />
<span style="color: #38761d;"> functions that pass strings as parameters or function results. This</span><br />
<span style="color: #38761d;"> applies to all strings passed to and from your DLL--even those that</span><br />
<span style="color: #38761d;"> are nested in records and classes. ShareMem is the interface unit to</span><br />
<span style="color: #38761d;"> the BORLNDMM.DLL shared memory manager, which must be deployed along</span><br />
<span style="color: #38761d;"> with your DLL. To avoid using BORLNDMM.DLL, pass string information</span><br />
<span style="color: #38761d;"> using PChar or ShortString parameters. }</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">uses</span><br />
<span style="color: #38761d;"> SysUtils,</span><br />
<span style="color: #38761d;"> Classes;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">{$R *.res}</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;">end.</span><br />
<span style="color: #38761d;"><br /></span><br />
В двух словах: если функции Вашей библиотеки будут передавать или получать строковые значения, то нужно в Uses на первом месте иметь ссылку на ShareMem, соответственно, в системе должна присутствовать библиотека <span style="color: #38761d;">BORLNDMM.DLL. </span><br />
<br />
Если же, использование этой библиотеки по каким-то причинам невозможно (а такое бывает!), то передаваемые параметры должны быть типов <span style="color: #38761d;">PChar or ShortString.</span><br />
<span style="color: #38761d;"><br /></span><br />
Способов подключений библиотек два. У каждого есть свои преимущества и недостатки, но этой информации много в сети, не буду на ней останавливаться, оговорюсь лишь, что я буду использовать способ привязки DLL к программе. Моя задача иная: я хочу проиллюстрировать, как из готовой программы извлечь фрагмент и разместить его в библиотеке.<br />
<br />
Сохраним проект под именем ProDelphiLyb.<br />
<br />
Добавим в Uses ссылки на следующие модули:<br />
<br />
<span style="color: #38761d;"> </span><span style="color: #38761d;">ShareMem, // Нас предупреждали!!!</span><br />
<br />
<span style="color: #38761d;"> DBGridEh, // Для работы с сеткой</span><br />
<span style="color: #38761d;"> ExcelXP, // Для работы с приложением Excel</span><br />
<span style="color: #38761d;"> DB, // Для работы с закладкой</span><br />
<div>
<br /></div>
<br />
и далее - текст процедуры, практически полностью совпадающий с аналогичной процедурой из <a href="http://pro-delphi.blogspot.com/2012/03/33-excel.html">предыдущего урока</a>:<br />
<br />
<br />
<span style="color: #38761d;">Procedure MyExportToExcel(WorkSheetName: String; PGridEh: TDBGridEh; XLApp: TExcelApplication; RepName: String; RepPeriod: String); stdcall;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">// Вывод данных из источника объекта DBGridEh в Excel</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">var</span><br />
<span style="color: #38761d;"> WorkBk: _WorkBook; // определяем WorkBook</span><br />
<span style="color: #38761d;"> WorkSheet: _WorkSheet; // определяем WorkSheet</span><br />
<span style="color: #38761d;"> I, J: Integer;</span><br />
<span style="color: #38761d;"> SavePlace: TBookmark;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">Try</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Установка закладки</span><br />
<span style="color: #38761d;"> SavePlace := PGridEh.DataSource.DataSet.GetBookmark;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Соединяемся с сервером TExcelApplication</span><br />
<span style="color: #38761d;"> XLApp.Connect;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Добавляем WorkBooks в ExcelApplication</span><br />
<span style="color: #38761d;"> XLApp.WorkBooks.Add(xlWBatWorkSheet, 0);</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Выбираем первую WorkBook</span><br />
<span style="color: #38761d;"> WorkBk := XLApp.WorkBooks.Item[1];</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Определяем первый WorkSheet</span><br />
<span style="color: #38761d;"> WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Заполняем свойства WorkSheet</span><br />
<span style="color: #38761d;"> WorkSheet.Name := WorkSheetName;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Заголовок отчета</span><br />
<span style="color: #38761d;"> J := 1;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Value:= RepName;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Font.Bold := True;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Font.size := 16;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Указание периода</span><br />
<span style="color: #38761d;"> J := 2;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Value:= RepPeriod;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Font.Italic := True;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Заголовки колонок</span><br />
<span style="color: #38761d;"> J := 3;</span><br />
<span style="color: #38761d;"> PGridEh.DataSource.DataSet.First;</span><br />
<span style="color: #38761d;"> with PGridEh.Columns do</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> for i := 1 to Count do</span><br />
<span style="color: #38761d;"> if Items[I-1].Visible then</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,I].Value:= Items[I-1].Title.Caption;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,I].Font.Bold := True;</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,I].HorizontalAlignment := xlCenter;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Собственно вывод данных из источника под сеткой в Excel</span><br />
<span style="color: #38761d;"> J := 4;</span><br />
<span style="color: #38761d;"> with PGridEh.DataSource.DataSet do</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> First;</span><br />
<span style="color: #38761d;"> while not Eof do</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> with PGridEh.Columns do</span><br />
<span style="color: #38761d;"> begin</span><br />
<span style="color: #38761d;"> for I := 1 to Count do</span><br />
<span style="color: #38761d;"> if Items[I-1].Visible then</span><br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,I].Value:=FieldByName(Items[I-1].FieldName).AsVariant;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"> Inc(J, 1);</span><br />
<span style="color: #38761d;"> next;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> WorkSheet.Columns.ColumnWidth := 25;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Показываем Excel</span><br />
<span style="color: #38761d;"> XLApp.Visible[0] := True;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Разрываем связь с сервером</span><br />
<span style="color: #38761d;"> XLApp.Disconnect;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Возврат на закладку</span><br />
<span style="color: #38761d;"> PGridEh.DataSource.DataSet.GotoBookmark(SavePlace);</span><br />
<span style="color: #38761d;"> PGridEh.DataSource.DataSet.FreeBookmark(SavePlace);</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">Finally</span><br />
<span style="color: #38761d;">End;</span><br />
<span style="color: #38761d;">end;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">exports</span><br />
<span style="color: #38761d;">MyExportToExcel</span><span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;">end. // NB точка в конце</span><br />
<br />
<div>
Для экспорта процедур и функций из DLL, необходимо использовать ключевое слово export, после которого перечисляются процедуры.</div>
<br />
Выполните Compile и Build проекта. В результате последнего действия, в каталоге с проектом появится файл: ProDelphiLyb.dll<br />
<br />
Теперь - самое время вернуться к проекту "Расходы".<br />
<br />
<div>
<br /></div>
<br />
Найдите в модуле главной формы процедуру ExportTo и замените все ее содержимое (которое переехало в модуль library ProDelphiLyb)<span style="color: #38761d;"> </span> вот на это:<br />
<br />
<br />
<span style="color: #38761d;">Procedure TMainFrm.ExportTo(p_WorkSheetName: String; p_PGridEh: TDBGridEh; p_XLApp: TExcelApplication;</span><br />
<span style="color: #38761d;"> p_RepName: String; p_RepSubTitle: String);</span><br />
<span style="color: #38761d;">begin</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;"> // Экспорт в Эксель</span><br />
<span style="color: #38761d;"> Try</span><br />
<span style="color: #38761d;"> MyExportToExcel(p_WorkSheetName, p_PGridEh, p_XLApp, p_RepName, p_RepSubTitle);</span><br />
<span style="color: #38761d;"> Except</span><br />
<span style="color: #38761d;"> MyMessenger.TitleString:='Проблема';</span><br />
<span style="color: #38761d;"> MyMessenger.MessageString:='Возможно, в Вашем компьютере не установлен MS Excel';</span><br />
<span style="color: #38761d;"> MyMessenger.Buttons:=[mbOk];</span><br />
<span style="color: #38761d;"> MyMessenger.ShowMessage;</span><br />
<span style="color: #38761d;"> end;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">end;</span><br />
<br />
<br />
А теперь - напишите оператор, подгружающий процедуру <span style="color: #38761d;">MyExportToExcel </span>из вновь созданной библиотеки:<br />
<br />
<br />
<span style="color: #38761d;">implementation</span><br />
<span style="color: #38761d;">Uses MOs, Oborot;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">{$R *.dfm}</span><br />
<span style="color: #38761d;"><br /></span><br />
<b><span style="color: #38761d;">Procedure MyExportToExcel(WorkSheetName: String; PGridEh: TDBGridEh; XLApp: TExcelApplication;</span></b><br />
<b><span style="color: #38761d;"> RepName: String; RepPeriod: String); stdcall; external 'ProDelphiLyb.dll';</span></b><br />
<div>
<br /></div>
<br />
<br />
Если все сделано правильно, то работа программы "Расходы" внешне ни чем не будет отличаться от того, как она работала до сего момента. Но, если Вы попробуете установить эту программу на другой компьютер, у Вас, вполне вероятно, будут неприятности, связанные с использованием BORLNDMM.DLL, точнее - с отсутствием этой библиотеки в компьютере.<br />
<br />
Предлагаю воспользоваться предупреждением и избавиться от строковых параметров.<br />
<br />
начать нужно с модуля библиотеки, убрав из Uses Sharemem и изменив тип принимаемых параметров со String на PChar:<br />
<br />
<br />
<span style="color: #38761d;">library ProDelphiLyb;</span><br />
<span style="color: #38761d;">uses</span><br />
<b><span style="color: red;">// ShareMem,</span></b><br />
<span style="color: #38761d;"> DBGridEh, // Для работы с сеткой</span><br />
<span style="color: #38761d;"> ExcelXP, // Для работы с приложением Excel</span><br />
<span style="color: #38761d;"> DB, // Для работы с закладкой</span><br />
<span style="color: #38761d;"> SysUtils,</span><br />
<span style="color: #38761d;"> Classes;</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">{$R *.res}</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">Procedure MyExportToExcel(WorkSheetName: </span><b><span style="color: red;">PChar</span></b><span style="color: #38761d;">; PGridEh: TDBGridEh; XLApp: TExcelApplication; RepName: </span><b><span style="color: red;">PChar</span></b><span style="color: #38761d;">; RepPeriod: </span><b><span style="color: red;">PChar</span></b><span style="color: #38761d;">); stdcall;</span><br />
<div>
<br /></div>
<br />
далее - в теле самой процедуры выполнить преобразование типов, поскольку ячейки Excel, в которые вписываются заголовок отчета и подзаголовок (период) не могут принять значения типа PChar, им - строки подавай:<br />
<br />
<br />
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Value:= </span><b><span style="color: red;">StrPas</span></b><span style="color: #38761d;">(RepName);</span><br />
<div>
и</div>
<div>
<div>
<span style="color: #38761d;"> Worksheet.Cells.Item[J,1].Value:= </span><b><span style="color: red;">StrPas</span></b><span style="color: #38761d;">(RepPeriod);</span></div>
</div>
<div>
<br /></div>
<br />
Save, compile, build.<br />
<br />
В модуле main проекта "Расходы" в объявлениях процедур тоже внести необходимые поправки:<br />
<br />
<br />
<span style="color: #38761d;"> { Public declarations }</span><br />
<span style="color: #38761d;"> Procedure ExportTo(p_WorkSheetName: </span><span style="color: red;">PChar</span><span style="color: #38761d;">; p_PGridEh: TDBGridEh; p_XLApp: TExcelApplication;</span><span style="color: #38761d;"> p_RepName: </span><span style="color: red;">PChar</span><span style="color: #38761d;">; p_RepSubTitle: </span><span style="color: red;">PChar</span><span style="color: #38761d;">);</span><br />
<span style="color: #38761d;"><br /></span><br />
(не забудьте внести аналогичные поправки и в декларации этой процедуры в разделе implementation !!!)<br />
<br />
и<br />
<br />
<br />
<span style="color: #38761d;">{$R *.dfm}</span><br />
<span style="color: #38761d;"><br /></span><br />
<span style="color: #38761d;">Procedure MyExportToExcel(WorkSheetName: </span><span style="color: red;">PChar</span><span style="color: #38761d;">; PGridEh: TDBGridEh; XLApp: TExcelApplication;</span><span style="color: #38761d;"> RepName: </span><span style="color: red;">PChar</span><span style="color: #38761d;">; RepPeriod: </span><span style="color: red;">PChar</span><span style="color: #38761d;">); stdcall; external 'ProDelphiLyb.dll';</span><br />
<div>
<br /></div>
<br />
<div>
И последнее, в модуле Oborot выполнить преобразование передаваемых параметров из строковых в PChar:</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #38761d;">procedure TOborotFrm.N_ExportClick(Sender: TObject);</span></div>
<div>
<span style="color: #38761d;">begin</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;"> // Экспорт в Эксель</span></div>
<div>
<span style="color: #38761d;"> MainFrm.ExportTo(</span><span style="color: red;">PChar</span><span style="color: #38761d;">('ОВ'), DBGridEh1, MainFrm.XLApp, </span><span style="color: red;">PChar</span><span style="color: #38761d;">('Оборотная ведомость'), </span><span style="color: red;">PChar</span><span style="color: #38761d;">('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));</span></div>
<div>
<span style="color: #38761d;"><br /></span></div>
<div>
<span style="color: #38761d;">end;</span></div>
</div>
<div>
<br /></div>
<br />
Трудились долго, нудно, но заметных на первый взгляд отличий не получили...<br />
Смотрите на вопрос ширше или ширее, а лучше - глыбже... :-)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com0tag:blogger.com,1999:blog-8494755139146574371.post-1331286826589569262012-03-14T14:41:00.000+04:002012-04-12T11:52:40.272+04:00Урок 33. Оборотная ведомость - экспорт в Excel<br />
<div>
<span id="internal-source-marker_0.2933943325188011"></span><br />
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<span id="internal-source-marker_0.2933943325188011"><span style="font-family: Arial; font-size: 15px; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Когда-то давно, в самом начале тревожных 90-х, когда я писал свою первую бухгалтерскую настоящую большую программу, постановщик задачи, мой коллега и друг, задал такую идею: хорошо было</span><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"> бы</span><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">, если бы программа могла</span><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"> бы</span><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"> из одних и тех же цифр складывать несколько разных главных книг: одну - для налоговой, одну - для акционеров, одну - самую полную и правильную... и одну - для души...</span></span></div>
<span id="internal-source-marker_0.2933943325188011">
</span><br />
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<span id="internal-source-marker_0.2933943325188011"><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></span></div>
<span id="internal-source-marker_0.2933943325188011">
<div dir="ltr" style="margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Не смотря на то, что потом было еще много "хочу" разной сложности от постановщиков задач, с тех давних пор эта идеология живет вместе со мной.</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Только решать задачку складывания одних и тех же цифр в различные результаты (=отчеты), сейчас стало на много проще. Для этого существуют универсальные программы, например: Excel.</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Итак, в <a href="http://pro-delphi.blogspot.com/2012/03/32.html">предыдущем уроке</a> я показал как составить и вывести на экран оборотную ведомость. В таком виде можно посмотреть только небольшой отчет, пару каких-то конкретных цифр. Работать, а тем более изменять информацию на экране, добавлять оформление и т.п. невозможно. </span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Для того, чтобы экспортировать данные из экранного представления прикладной программы "Расходы", добавьте для начала контекстное меню для формы OborotFrm с одним пунктом "Экспорт":</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div class="separator" style="clear: both; font-weight: bold; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBaJuD1L8xR4HjENULXPDT0uOuOrlCPDKmOQBjw9El1UFyDZ6zHjE34RCa9kOrtBFMcb0MMFkBhBlphecc-78qQrpZMjP_3X4UyR_xPpO5hohwrSvGqGbxWKWLcw3mQtYfG95BffKXuSZR/s1600/33_01.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBaJuD1L8xR4HjENULXPDT0uOuOrlCPDKmOQBjw9El1UFyDZ6zHjE34RCa9kOrtBFMcb0MMFkBhBlphecc-78qQrpZMjP_3X4UyR_xPpO5hohwrSvGqGbxWKWLcw3mQtYfG95BffKXuSZR/s320/33_01.JPG" width="320" /></a></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Подготовьте обработчик события нажатия на этот пункт меню.</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Тут я хочу сделать небольшое отступление, озадачив всех вопросом: где располагать процедуру экспорта: в данной форме или в модуле главной формы? В принципе - решать Вам, но! Если эта процедура будет универсальной, способной выполнять возложенные на нее функции не только для отчета "Оборотная ведомость", то удобнее ее расположить в модуле главной формы. Более того, если эта процедура окажется на столько универсальна и хороша, что сможет обслуживать не только эту программу, но и многие другие, тогда ей место - в отдельно лежащей библиотеке, например: в файле Dll, но об этом - несколько позже. </span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">А пока - добавьте в форме OborotFRM Вот такой обработчик:</span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;">procedure TOborotFrm.N_ExportClick(Sender: TObject);</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;">begin</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"><br /></span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> // Экспорт в Эксель</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> MainFrm.ExportTo('ОВ', DBGridEh1, MainFrm.XLApp, 'Оборотная ведомость', 'Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value));</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"><br /></span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;">end;</span></span></span><br />
<div style="font-size: 15px; white-space: pre-wrap;">
<span style="font-family: Arial;"><br /></span></div>
</div>
<div dir="ltr" style="margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Что здесь "что", перечислю параметры: название книги Excel, ссылка на GridEh, ссылка на неизвестный нам пока компонент, который еще предстоит расположить в главной форме, заголовок документа, подзаголовок.</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">На этом форму Oborot можно пока закрыть, поскольку все дальнейшие манипуляции будут происходить в форме </span><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">MainFrm.</span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">Для начала расположите на ней экземпляр компонента TExcelApplication c вкладки Servers, дав ему имя XLApp.</span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg85rNJ9zlBTXFixuzGAadyn7wDVYK8-PSXL0pUr-n3dV0tTDhYFw8DL2BieF-iLpswMZqOJFapu-bd0g904klJVIiJwWRHMD1KNlB0bq56Iho-9CvNFA2ZU7fd-jZ1ET8zvUjhY2pkkMPd/s1600/33_02.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg85rNJ9zlBTXFixuzGAadyn7wDVYK8-PSXL0pUr-n3dV0tTDhYFw8DL2BieF-iLpswMZqOJFapu-bd0g904klJVIiJwWRHMD1KNlB0bq56Iho-9CvNFA2ZU7fd-jZ1ET8zvUjhY2pkkMPd/s640/33_02.JPG" width="640" /></a></div>
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">Затем (внимание!) в секции общедоступных объявлений опишите процедуру:</span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span><br />
<span style="font-family: Arial;"></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> <b>public</b></span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> { Public declarations }</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> Procedure ExportTo(p_WorkSheetName: String; p_PGridEh: TDBGridEh; p_XLApp: TExcelApplication;</span></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><span style="color: #38761d;"> p_RepName: String; p_RepSubTitle: String);</span></span></span><br />
<div style="font-size: 15px; white-space: pre-wrap;">
<span style="font-family: Arial;"><br /></span></div>
<br />
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">А теперь - собственно цель урока - процедура вывода данных:</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<span style="color: #38761d;"><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">Procedure TMainFrm.ExportTo(p_WorkSheetName: String; p_PGridEh: TDBGridEh; p_XLApp: TExcelApplication;
p_RepName: String; p_RepSubTitle: String);</span></span></span><br />
<span style="color: #38761d;"><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span></span><br />
<span style="color: #38761d;"><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">
var
WorkBk: _WorkBook; // определяем WorkBook (книгу)
WorkSheet: _WorkSheet; // определяем WorkSheet (лист)
I, J: Integer; // Вспомогательные переменные
SavePlace: TBookmark; // Закладка
begin
// Вывод данных из источника объекта DBGridEh в Excel
try
// Установка закладки (чтобы позже вернуть на нее указатель в сетке)
SavePlace := p_PGridEh.DataSource.DataSet.GetBookmark;
// Соединяемся с сервером TExcelApplication
p_XLApp.Connect;
// Добавляем WorkBooks в ExcelApplication
p_XLApp.WorkBooks.Add(xlWBatWorkSheet, 0);
// Выбираем первую WorkBook
WorkBk := p_XLApp.WorkBooks.Item[1];
// Определяем первый WorkSheet
WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;
// Заполняем свойства WorkSheet
WorkSheet.Name := p_WorkSheetName;
// Заголовок отчета
J := 1;
Worksheet.Cells.Item[J,1].Value:= p_RepName;
Worksheet.Cells.Item[J,1].Font.Bold := True;
Worksheet.Cells.Item[J,1].Font.size := 16;
// Указание периода
J := 2;
Worksheet.Cells.Item[J,1].Value:= p_RepSubTitle;
Worksheet.Cells.Item[J,1].Font.Italic := True;
// Заголовки колонок
J := 3;
p_PGridEh.DataSource.DataSet.First;
with p_PGridEh.Columns do
begin
for i := 1 to Count do
if Items[I-1].Visible then
begin
Worksheet.Cells.Item[J,I].Value:= Items[I-1].Title.Caption;
Worksheet.Cells.Item[J,I].Font.Bold := True;
Worksheet.Cells.Item[J,I].HorizontalAlignment := xlCenter;
end;
end;
// Собственно вывод данных из источника под сеткой в Excel
J := 4;
with p_PGridEh.DataSource.DataSet do
begin
First;
while not Eof do
begin
with p_PGridEh.Columns do
begin
for I := 1 to Count do
if Items[I-1].Visible then
Worksheet.Cells.Item[J,I].Value:=FieldByName(Items[I-1].FieldName).AsVariant;
end;
Inc(J, 1);
next;
end;
end;
WorkSheet.Columns.ColumnWidth := 25;
// Показываем Excel
p_XLApp.Visible[0] := True;
// Разрываем связь с сервером
p_XLApp.Disconnect;
// Возврат на закладку
p_PGridEh.DataSource.DataSet.GotoBookmark(SavePlace);</span></span></span><br />
<span style="color: #38761d;"><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span></span><br />
<span style="color: #38761d;"><span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"> // Удаление закладки
p_PGridEh.DataSource.DataSet.FreeBookmark(SavePlace);
Except
MyMessenger.TitleString:='Проблема';
MyMessenger.MessageString:='Возможно, в Вашем компьютере не установлен MS Excel';
MyMessenger.Buttons:=[mbOk];
MyMessenger.ShowMessage;
end;
end;</span></span><span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">
</span></span><br />
<div>
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;">Как всегда я достаточно много вписал комментариев в текст процедуры, но,если все же у Вас остались вопросы, и Вы не получили XLS файла, похожего на этот:</span></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxYuXrmJqr5Grmdr4HKfVrudieDuQ3fw5SQIorXPZD6A6HU3PRfOwUB6sJiRinxbIHP0sGGeSSRRh2IDAoiTS4qsX1XztY4O4fmbZeyvCd919BT2_Nh2byQhPbc7PNnwQt8U-cs5hoECm/s1600/33_03.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpxYuXrmJqr5Grmdr4HKfVrudieDuQ3fw5SQIorXPZD6A6HU3PRfOwUB6sJiRinxbIHP0sGGeSSRRh2IDAoiTS4qsX1XztY4O4fmbZeyvCd919BT2_Nh2byQhPbc7PNnwQt8U-cs5hoECm/s640/33_03.JPG" width="640" /></a></div>
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">то я, как всегда, жду Ваших вопросов:</span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;"><br /></span></span><br />
<span style="font-family: Arial;"><span style="font-size: 15px; white-space: pre-wrap;">мои координаты Вы найдете <a href="http://pro-delphi.blogspot.com/p/blog-page.html">тут</a>.</span></span><br />
<div style="font-weight: bold;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
</div>
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="font-weight: bold; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-align: left;">
<span style="font-family: Arial; font-size: 15px; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
</span></div>
<br />
<div id="-chrome-auto-translate-plugin-dialog" style="background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;">
<div style="-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;">
<div class="translate">
</div>
<div class="additional">
</div>
</div>
<img onclick="document.location.href='http://translate.google.com/';" src="http://www.google.com/uds/css/small-logo.png" style="-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;" /></div>Александрhttp://www.blogger.com/profile/15672838363195259292noreply@blogger.com1