14. ЦиклыVB.В этом разделе Вы узнаете о циклах языка и научитесь с ними работать. Цикл For Each... NextСпособ проверить, не существует ли уже объект коллекции – последовательный перебор всех членов набора и проверка условия.
For Each <член_коллекции> In <коллекция> <некоторые действия> Next <член коллекции>
Для нашего случая это будет выглядеть так: For Each NewSheet In colSheets <некоторые действия> Next NewSheet Преимущество такого подхода – нет нужды знать, сколько именно форм-заметок нами открыто, обработаны будут все. Теперь следует определить, какое условие нам следует проверять для определения существования члена набора.
Вот как это делается: For Each NewSheet In colSheets If NewSheet.Caption = datPrimaryRS.Recordset("Dates") ThenNewSheet.ZOrderExit SubEnd If Next NewSheet Строка Exit Sub – для выхода из процедуры, если существующая форма-страничка выведена на передний план. Если опустить эту строку, то будет создаваться новый экземпляр уже существующей странички, что приведет к ошибке. Остается еще одно ошибочная ситуация, а именно, если мы создаем первую страничку, и в наборе еще ничего нет. Приемлемый здесь способ – игнорирование ошибок. Добавьте код для игнорирования ошибок сами. Теперь обработчик события нажатия на кнопку приобретет вид: Private Sub cmdSheet_Click() On Error Resume NextFor Each NewSheet In colSheetsIf NewSheet.Caption = datPrimaryRS.Recordset("Dates") ThenNewSheet.ZOrderExit SubEnd IfNext NewSheetSet NewSheet = New frmSheetNewSheet.Caption = datPrimaryRS.Recordset("Dates")NewSheet.txtSheet.Text = datPrimaryRS.Recordset("Note")colSheets.Add NewSheet, NewSheet.Caption End Sub Следует пояснить, что же здесь получилось.
If <форма найдена> Then <выход> . . . If <из процедуры не вышли, значит, форма не найдена> Then <продолжаем>
Форма frmDiary готова. Перейдем к форме-страничке. Наша задача сделать так, чтобы при закрытии странички происходило обновление записи в БД, и сохранялись изменения, внесенные нами в текст. Это следует делать в обработчике события выгрузки формы Form_Unload.
Язык VB различает циклы For ... Next (частный случай – цикл For Each) и циклы Do... Loop. Цикл For... Next
For index = 0 to counter <действия в цикле> Next index
ЦиклDo... LoopЕсли же число проходов цикла заранее не известно, предпочтительнее цикл Do... Loop (Делай... Цикл). Общая структура его такова: Do <некие действия> Loop
Разновидности цикла Do... Loop:Do Until <условие> <действия> Loop
Do <действия> Loop Until <условие >
Do While <условие> <действия> Loop
Do <действия> Loop While <условие>
Так вот, для нашей программы следует «пролистать» всю БД от начала до конца. Если помните, у набора записей есть свойство EOF, обозначающее достижение конца набора записей и есть методы для перемещения по набору…
Итак, создайте обработчик события Form_Unload (не забудьте, мы работаем с кодом frmSheet). Чтобы перемещаться до конца набора записей БД, сперва обязательно следует сделать так: <набор_записей>.MoveLast <набор_записей>.MoveFirst То есть, переместиться на последнюю запись, при этом становится известным общее количество записей, а потом вернуться на первую запись для совершения тех или иных действий. Иначе VB не сможет правильно определить достижение конца набора. Добавьте код в обработчик события Form_Unload: frmDiary.datPrimaryRS.Recordset.MoveLast frmDiary.datPrimaryRS.Recordset.MoveFirst А теперь создадим заготовку цикла:
Do Until frmDiary.datPrimaryRS.Recordset.EOF frmDiary.datPrimaryRS.Recordset.MoveNext Loop Метод MoveNext перемещает указатель на следующую позицию набора записей. Без этого цикл станет бесконечным (так как будет постоянно проверяться одна и та же запись) и программа зависнет! В циклах Do... Loop обязательно следует предусматривать условие завершения цикла, иначе цикл может стать бесконечным и программа «зависнет». Обратите внимание: мы явно указываем, на какой форме находится элемент управления данными. Если программа большая, это избавит вас от проблем.
If frmDiary.datPrimaryRS.Recordset(“Dates”) = Me.Caption Then End If
frmDiary.datPrimaryRS.Recordset(“Note”) = Me.txtSheet.Text
Exit Do Код примет вид: Private Sub Form_Unload(Cancel As Integer) frmDiary.datPrimaryRS.Recordset.MoveLastfrmDiary.datPrimaryRS.Recordset.MoveFirstDo Until frmDiary.datPrimaryRS.Recordset.EOFIf frmDiary.datPrimaryRS.Recordset("Dates") = Me.Caption ThenfrmDiary.datPrimaryRS.Recordset("Note") = Me.txtSheet.TextExit DoEnd IffrmDiary.datPrimaryRS.Recordset.MoveNextLoop End Sub Но на этом работа не закончена! Следует правильно удалить текущую страничку из коллекции страничек.
For Each NewSheet In colSheets If NewSheet.Caption = Me.Caption ThencolSheets.Remove Me.CaptionExit ForEnd If Next NewSheet При удалении члена коллекции применяется метод коллекции Remove, параметр метода - тот же, что и при добавлении члена методом Add, т.е. – идентификатор члена коллекции. Код примет вид: Private Sub Form_Unload(Cancel As Integer) frmDiary.datPrimaryRS.Recordset.MoveLastfrmDiary.datPrimaryRS.Recordset.MoveFirstDo Until frmDiary.datPrimaryRS.Recordset.EOFIf frmDiary.datPrimaryRS.Recordset("Dates") = Me.Caption ThenfrmDiary.datPrimaryRS.Recordset("Note") = Me.txtSheet.TextExit DoEnd IffrmDiary.datPrimaryRS.Recordset.MoveNextLoopFor Each NewSheet In colSheetsIf NewSheet.Caption = Me.Caption ThencolSheets.Remove Me.CaptionExit ForEnd IfNext NewSheet End Sub Запустите программу.
Как вы можете убедиться, после закрытия странички указатель перемещается в позицию, соответствующую этой страничке.
Объявите переменную в самом начале процедуры: Dim varPosition
varPosition = frmDiary.datPrimaryRS.Recordset.AbsolutePosition
frmDiary.datPrimaryRS.Recordset.AbsolutePosition = varPosition Код примет вид: Private Sub Form_Unload(Cancel As Integer) Dim varPosition varPosition = frmDiary.datPrimaryRS.Recordset.AbsolutePosition frmDiary.datPrimaryRS.Recordset.MoveLast frmDiary.datPrimaryRS.Recordset.MoveFirst Do Until frmDiary.datPrimaryRS.Recordset.EOF If frmDiary.datPrimaryRS.Recordset("Dates") = Me.Caption ThenfrmDiary.datPrimaryRS.Recordset("Note") = Me.txtSheet.TextfrmDiary.datPrimaryRS.Recordset.AbsolutePosition = varPositionExit DoEnd IffrmDiary.datPrimaryRS.Recordset.MoveNext Loop For Each NewSheet In colSheets If NewSheet.Caption = Me.Caption ThencolSheets.Remove Me.CaptionExit ForEnd If Next NewSheet End Sub Проверьте программу в работе. Наверное, вы уже обратили внимание, что в коде многократно встречается последовательность frmDiary.datPrimaryRS.Recordset. Безусловно, вы можете использовать конструкцию With. Код примет вид: Private Sub Form_Unload(Cancel As Integer) Dim varPosition With frmDiary.datPrimaryRS.Recordset varPosition = .AbsolutePosition.MoveLast.MoveFirstDo Until .EOFIf frmDiary.datPrimaryRS.Recordset ("Dates") = _Me.Caption ThenfrmDiary.datPrimaryRS.Recordset ("Note") = _Me.txtSheet.Text.AbsolutePosition = varPositionExit DoEnd If.MoveNextLoop End With For Each NewSheet In colSheets If NewSheet.Caption = Me.Caption ThencolSheets.Remove Me.CaptionExit ForEnd If Next NewSheet End Sub Как видите, код стал гораздо короче и понятнее. При больших БД такой прием даст вам значительное увеличение скорости работы. На этом можно было бы и закончить, но мы упустили ситуацию, когда мы закрываем страничку, а в наборе почему-то записей нет. Здесь поможет уже известное нам игнорирование ошибок. Внесите строку для игнорирования ошибок. Еще одна ситуация, когда мы закрываем страничку, но изменений в ней не было произведено – и обновлять БД не надо. Для обхода этой ситуации сделаем следующее:
Dim boolChange As Boolean Как помните, переменные логического типа могут принимать только значения True или False. Сделаем так, что после создания формы-странички эта переменная будет иметь значение False, но после внесения изменений в текст ее значение изменится на True. В обработчике события загрузки формы-странички присвойте переменной значение False: Private Sub Form_Load() boolChange = False End Sub У контрола TextBox есть событие Change, которое происходит при любом редактировании текста. В обработчике этого события присвойте переменной значение True: Private Sub txtSheet_Change() boolChange = True End Sub В следующем разделе мы проверим, что получилось. Вопросы
Задания
|