Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual Basic в примерах.docx
Скачиваний:
13
Добавлен:
18.08.2019
Размер:
1.1 Mб
Скачать

О связанных элементах управления Последовательность событий при загрузке формы

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

  1. Первым происходит событие Form_Initialize.

  2. Затем инициализируется событие Form_Load. По этому событию форма за­гружается в память и подготавливается к выводу на экран.

  3. Событие Form_Activate происходит сразу после того, как форма отобразит­ся на экране.

  4. Событие Form_Paint вызывается, когда в форме надо что-то нарисовать.

Наборы записей

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

Вы задали в качестве значения свойства RecordSource таблицу Publishers. В действительности за этим стоит запрос на языке Structured Query Language (SQL - язык структурированных запросов) на извлечение всех записей из табли­цы Publishers. По сути свойство RecordSource - не что иное, как SQL-запрос, определяющий, что необходимо включить в набор записей.

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

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

На практике обычно требуется получить одно поле из таблицы, содержащей множество полей, либо несколько полей из одной таблицы и несколько - из дру­гой. Набор записей содержит только те записи, которые были запрошены. Напри­мер, таблица Titles содержит 8000 записей, а нужны только книги, названия ко­торых начинаются с «А». Следовательно, набор записей может содержать всего, скажем, 100 записей. Предложение на языке SQL описывает запрос на отбор нужной информации. Этот запрос направляется элементу управления данными, который размещает в памяти построенный набор записей, включающий все ука­занные в запросе поля.

Когда вы редактируете поле базы данных посредством связанного элемента, набор записей модифицируется, и изменения записываются обратно в базу дан­ных. Для этого элемент управления данными использует Jet, которое и занимает­ся реальным обновлением таблиц и индексов в базе.

В зависимости от поставленных перед программистом задач можно создавать три разных типа наборов записей, а именно:

Table (Таблица) - это отображение реальной таблицы базы данных, с помо­щью которого можно добавлять, изменять и удалять из нее записи. Если вы работаете с одной таблицей и хотите ее модифицировать, это наиболее эф­фективный способ организации набора записей. Но, к сожалению, указан­ный набор только с одной таблицей и может работать. В наборе записей типа «таблица» все изменения записываются непосредственно в таблицу, на базе которой он построен;

Dynaset (Динамический набор) - это результат запроса, в котором могут быть обновляемые записи. С его помощью допускается добавлять, изменять и удалять записи из одной или нескольких таблиц. Динамический набор мо­жет содержать поля, выбранные более чем из одной таблицы. При модифи­кации записи изменения сохраняются в той таблице или таблицах, на основе которых набор построен. Этот тип набора записей принимается по умолча­нию. Динамический набор - самый мощный и гибкий тип, но, как правило, он уступает табличному набору в скорости обработки данных;

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

Важная информация

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

С элементом управления данными связано понятие текущей записи, то есть записи, доступной в текущий момент работы. В любой момент только одна запись является текущей. Данные именно из этой записи отображаются в связанных эле­ментах управления. При работе с наборами записей всегда надо следить за тем, чтобы текущая запись была действительна. В принципе, можно позиционировать (установить) указатель текущей на удаленную запись или за пределы набора, сде­лав ее тем самым недействительным. Об этом будет рассказано при рассмотрении свойств BOFAction и EOFAction элемента управления данными.

Массивы элементов управления

В рассмотренном примере классного журнала мы воспользовались массивами текстовых полей и меток для заполнения их в цикле именами полей и значениями из базы данных. Многие программисты, только начинающие работать с Visual Basic, стараются избегать таких массивов, посколь­ку не понимают, зачем они нужны. Однако использование массивов элементов управления не только упрощает программирование, но и позволяет оптимизиро­вать код. Некоторые предпочитают написать программу, добиться ее работоспо­собности и только потом заняться оптимизацией. Это абсолютно неправильный подход. Поняв принципы работы Visual Basic, вы сможете сразу создавать уже оптимизированный код. Когда вы слышите, как кто-то говорит, что вернется к оп­тимизации попозже, будьте уверены: этот человек не очень хорошо знаком с язы­ком. В данной книге постоянно отмечается, когда эффективнее использовать тот или иной способ кодирования из всех возможных. Применение массивов элемен­тов управления - пример именно такой ситуации.

Массив элементов управления «напрашивается», когда в форме есть несколь­ко однотипных элементов. Будет логично, если вы решите создать два массива: один - для полей ввода, другой - для меток. Хранение элементов управления в массиве тре­бует меньше ресурсов, чем размещение их в форме по отдельности. Массивы по­лезны и в том случае, когда вы хотите, чтобы несколько элементов имели общий код. Например, если десять нолей ввода помещены в массив, по какому бы из них вы ни щелкнули кнопкой мыши, будет выполнен один и тот же код - в этом пре­имущество массивов элементов управления. Хотя для каждого элемента массива имеется отдельное визуальное представление на экране, процедуры обработки со­бытий являются общими для всех. Чтобы выяснить, какое конкретно поле ввода было выбрано из соответствующего массива, достаточно посмотреть на параметр Index. При добавлении нового поля ввода в массив оно наследует все общие для массива процедуры обработки событий. И, стало быть, код не дублируется, как было бы в случае десяти независимых элементов.

Важная информация

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

При создании массива элементов управления Visual Basic создает параметр Index. Вы можете проверить его, чтобы выяснить, к какому из элементов в масси­ве относится действие, ибо все элементы имеют одну и ту же процедуру обработ­ки событий. Вы лучше поймете, о чем идет речь, когда поработаете с примером, демон­стрирующим возможности массива. Пока взгляните, как именно Visual Basic включа­ет параметр Index. При изменении любого поля ввода, входящего в массив, возникает событие Change и срабатывает процедура:

Private Sub Text1_Change(Index As Integer)

End Sub

. Если бы у вас было два отдельных поля ввода, у каждого была бы своя процедура обработки события Change. А так все десять полей пользуют­ся единственным обработчиком, который идентифицирует источник события по переданному индексу.

Еще одно преимущество массивов элементов управления состоит в том, что в них можно добавлять элементы во время выполнения программы.

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

Внутреннее устройство элемента управления данными

В предыдущем примере вами задавались свойства Align, DatabaseName и RecordSource элемента управления данными (как вы помните, речь шла о добавле­нии связанных полей ввода). Для этого использовалось окно свойств Properties, но с равным успехом перечисленные свойства можно установить и программно.

Набор записей, созданный элементом управления данными - это временная структура в памяти. Доступ к содержимому записей можно получить либо с по­мощью связанных элементов, таких как поля ввода, либо обращаясь напрямую к элементу управления данными. В программе разрешено использовать любое свойство или метод объекта Recordset (Набор записей). В любом случае под на­чалом набора записей понимается его первая запись, а под концом - последняя. Но несмотря на кажущуюся логичность, это не вполне верно. Когда вы достигаете начала набора записей, оказывается, что указатель на начало файла (BOF) установ­лен перед первой записью. Точно также по достижении последней записи указатель на конец файла (EOF) будет установлен за ней. Как вы, наверное, догадались, это может привести к печальным последствиям, поскольку при достижении начала или конца набора исчезает текущая запись. Связанные элементы управления «очищаются» и пользователь не понимает, что случилось. Если, находясь в нача­ле набора, он попытается переместиться дальше. Visual Basic выдаст сообщение об ошибке. А если это произойдет в конце набора, будет добавлена фантомная за­пись, и пользователь, вероятно, будет обескуражен, ведь вряд ли он собирался до­бавить новую запись.

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

Свойство BOFAction

Свойство BOFAction сообщает элементу управления данными, что делать при достижении начала набора записей.

Положение указателя текущей записи в наборе определяет значения свойств ВОF и EOF. Элемент управления данными обращается к этим свойствам, чтобы по­нять, есть ли в данный момент текущая запись или пользователь уже вышел за пределы набора.

С помощью свойства BOFAction можно сообщить элементу управления данны­ми, как действовать в подобных случаях. Если оставить значение по умолчанию (0 -Move First), при выполнении метода Move First ука­затель текущей будет установлен на первую запись, и последующая попытка выполнить метод MovePrevious будет блокирована. Это значение подобно стра­ховочной сетке - пользователю не разрешено выходить за пределы набора.

Другими словами, если любое из свойств BOF или EOF равно True, текущей записи нет. Если сформиро­ванный по вашему запросу набор записей оказался пустым (например, вы ищете авторов по имени Зик (Zeke)), оба свойства BOF и EOF будут равны True. У набора записей есть также свойство RecordCount, показывающее, сколько записей в наборе. В случае пустого набора его значе­ние будет равно 0.

Предположим, что вы искали авторов по имени Джек и нашли одну за­пись. Если набор записей содержит только одну запись, именно она и будет теку­щей. Как BOF, так и EOF равны False и таковыми останутся до тех пор, пока пользователь не выйдет за пределы набора в результате выполнения метода MovePrevious или MoveNext. После этого текущей записи не станет.

Предположим, что вы удалили единственную запись в наборе. В таком случае и BOF, и EOF останутся равными False, пока вы не попытаетесь переместиться на другую запись.

Пользователь может перейти на последнюю запись в наборе - она станет те­кущей. Теперь при попытке выполнить MoveNext, текущая запись окажется недей­ствительной, а свойство EOF примет значение True. Аналогично, если пользова­тель стоит на первой записи и запускает MovePrevious, текущая запись также пропадает, и свойство BOF примет значение True. Так что если необходимо обой­ти все записи набора, обычно метод MoveNext выполняется в цикле до тех пор, пока свойство 30F не станет равным True. Если после этого вызвать MoveNext еше раз, произойдет ошибка.

Свойство EOFAction

Свойство EOFAction сообщает элементу управления данными, что делать при достижении конца набора записей. Имеется три варианта.

Как и в примере с предыдущим свойством, лучше всего оставить значение по умолчанию (0 - Move Last). В этом случае при достижении конца набора указатель переустанавливается на последнюю за­пись, и признак конца файла EOF сбрасывается. Второй вариант (1 - EOF) устанавливает признак конца файла EOF при достижении конца набора за­писей. Последний вариант (2 - Add New) автомати­чески создает и добавляет новую запись при по­пытке пользователя переместиться за последнюю запись набора. Происходящее может вызвать недо­умение пользователя, если он не знает, что должен ввести новую запись. Такое решение не является ин­туитивно очевидным. В этом случае все поля формы очищаются, поскольку элемент управления данными создал пустую запись. Если вы не собираетесь со­здавать программы промышленного уровня, никогда не «разрешайте» пользова­телю добавлять запись случайно. Гораздо лучше, чтобы пользователь явно по­просил добавить запись, щелкнув по кнопке Add New (Добавить новую).

Важная информация

Свойства BOFAction u EOFAction проявляют себя, только если пользователь перемещается по набору записей с помощью на­вигационных кнопок на элементе управления данными. Указан­ные свойства игнорируются, если навигация осуществляется из программы, поскольку в таком случае вы выполняете часть фун­кций элемента управления данными. Элемент управления данны­ми не обновляет значения этих свойств, если он сам не использу­ется для навигации.

Свойство Connect

Как правило, для свойства Connect используется принимаемое по умолчанию значение Access. Однако при необходимости подключиться к другому источнику Данных это свойство можно задать явно в окне Properties или из программы. Обра­тите внимание, что возможные значения свойства Connect представлены в выпада­ющем списке.

Уже отмечалось, что для ADO-элемента управления структура строки Connect несколько сложнее: в ней указывается, какой драйвер использовать, а также место­нахождение и имя базы/источника данных. В случае же стандартного элемента Управления данными достаточно выбрать нужное значение из списка.

Зачем нужен код в обработчике Form_Activate()

При загрузке формы в память последняя переживает ряд событий, которые необходимо понимать каждому программисту (см. «Последовательность событий при загрузке формы» в этой главе).

Прежде всего, происходит событие Initialize, вызывается процедура - обработчик Form_Initialize (). Ее можно использовать для инициализации переменных уровня фор­мы.

Затем срабатывает процедура-обработчик Form_Load (). В ней рисуются визуальные компоненты, такие как поля ввода. Все свой­ства визуальных элементов устанавливаются также здесь. Если вы попытаетесь обратиться к свойствам элемента управления данными Datal до полной инициализации визуальных компонентов, будет выдано сообщение об ошибке 91 (объектная переменная или переменная блока With не установлена).

Ошибка связана с тем, что еще не все визуальные элементы инициализированы. Некоторые программисты стремятся подавить это сообщение, принуди­тельно высвечивая форму путем обращения к методу Me. Show в обработчике со­бытия Load, а уже затем обращаясь к свойствам визуальных элементов. Такой способ допустим, но тем самым программист нарушает естественный «ход собы­тий», заставляя форму появиться до срока. Лучшим местом для доступа к визу­альным элементам в процессе загрузки формы является обработчик события Form_Activate (), который срабатывает, когда форма полностью загружена, инициирована и отображена на экране. В этот момент можно быть уверенным, что все визуальные элементы готовы к работе.

Важная информация

Процедура Form_Activate() вызывается всякий раз, когда форма становится активной. Это значит, что если форма вызы­вается из какой-нибудь другой формы, событие Activate воз­никает каждый раз, когда пользователь щелкает на форме при переходе от формы к форме. Если необходимо, чтобы некоторый код внутри Form_Activate() исполнялся только один раз, надо воспользоваться ста­тической булевской переменной (Boolean), u присваивать ей значение True во время загрузки формы. Далее при любом воз­никновении этого же события переменная проверяется и, по­скольку она уже установлена, защищенный ей код не выполняет­ся.

Событие Reposition элемента управления данными

Как вы помните, процедура-обработчик Form_Activate () вызывается только один раз при загрузке формы (и также в случае, если форма становится неактив­ной, а потом снова активной). Тем не менее, обновлять свойство Datal .Caption необходимо при каждом перемещении пользователя на новую запись. И самое подходящее место для этого - обработчик события Datal_Reposition(). Вставьте в него следующий код:

Private Sub Datal_Reposition()

Datal .Caption = Datal. Recordset .AbsolutePosition + 1 & _ " из " & ITotalRecords

End Sub

Вы просто добавляете 1 к значению свойства AbsolutePosition. Связано это с тем, что для первой записи в наборе указанное свойство рав­но 0, а для последней - числу записей минус 1. Добавляя 1, выделаете нумерацию более привыч­ной для пользователя.

Как уже говорилось, после загрузки набора элементом управления данными первая запись становится текущей. В этот момент происходит событие Reposition. А затем оно возникает, когда пользователь перемещается по набору записей с помощью навигационных кнопок, когда вызывается любой из методов семейства Move (например, MoveNext) или Find (например, FindFirst) и вообще, когда происходит любое действие, изменяющее текущую запись. Это событие возникает уже после того, как запись стала текущей. Если вы хотите про­извести какие-то проверки до перехода к новой записи, можете воспользоваться процедурой Datal_Validate (), которая срабатывает до того, как новая запись станет текущей.

Возможно, вы задаете себе вопрос: раз Datal_Reposition () срабатывает при начальной загрузке, зачем же нужен код в обработчике Form_Activate ()? Дело в том, что достаточно только один раз получить общее число записей в наборе и запомнить его в переменной ITotalRecords. Если бы этот код находился в об­работчике события Reposition, свойство RecordCount считывалось бы при каж­дой смене текущей записи.

Создание привлекательного пользовательского интерфейса

Качественная программа должна предоставлять пользователю как можно боль­ше визуальной информации. И это относится не только к таким вещам, как измене­ние формы курсора на песочные часы во время длительной обработки. Чем больше будет интуитивно понятных визуальных ключей, тем удобнее работать пользовате­лю. Ниже рассказано, как добавить в форму еще один элемент, который вы, воз­можно, сочтете полезным и для своих программ. Объект Datal.Recordset имеет не только свойство AbsolutePosition, но и свойство PercentPosition (Относи­тельная позиция). Вы будете считывать это свойство и отображать его в элементе управления, который называется Progress Bar (Индикатор прогресса). Код будет выглядеть следующим образом:

Private Sub Datal_Reposition()

With Data1.Recordset

Datal .Caption = Datal. Recordset .AbsolutePosition + 1 & _ " из " & ItotalRecords

ProgressBar1.Value = . PercentPosition

End With

End Sub

Одной из удобных особенностей Access является наличие записей, способ­ных изменять свою длину. Поэтому если в некоторой записи поле Company Name пусто, не надо сожалеть о том, что под него отведено 255 пробелов. Его значение останется равным Null до тех пор, пока не будет введено реальное название. Точ­но также, если название составляет 10 символов, то и для хранения отводится все­го 10 символов. В некоторых более старых базах данных для хранения такого поля было бы зарезервировано 255 символов, даже если значение не задано. Напрас­ный расход дискового пространства (на тот случай, если в одной из записей неко­торое поле окажется гораздо длиннее, чем то же поле во всех остальных записях) всегда очень раздражала проектировщиков баз данных. Перед ними стояла дилем­ма: стоит ли предусматривать дополнительное место для хранения «необычных» значений? Если так, то для каждого поля надо отвести столько места, сколько для самого длинного. Или «обрезать» длинные значения и смириться с потерей ин­формации?

Access избавила программистов от мучительных размышлений. Здесь нет лиш­него расхода дискового пространства, связанного с хранением необычно длинных полей.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]