Учебно-методическое пособие для студентов экономического факультета Ростов-на-Дону

Вид материалаУчебно-методическое пособие

Содержание


10. Ввод и редактирование данных
Надписи (тип Label)
Текстовые поля (тип TextBox)
Командные кнопки (тип Button)
Элементы управления DateTimePicker
Комбинированные поля (тип ComboBox)
Флажок (тип CheckBox)
10.2. Программное обеспечение формы для ввода и редактирования
11.2. Просмотр файла базы данных
11.3. Изменение и удаление записей в файле базы данных
11.4. Сохранение и удаление файлов
Подобный материал:
1   2   3   4   5   6   7

10. Ввод и редактирование данных


10.1. Проектирование макета формы для ввода и редактирования данных

Для ввода и редактирования информации о студентах, сохраняемых в виде записей в файле данных, используется форма, которой дано имя frmInputEdit, она является подчиненной формой для главной формы с меню. Макет формы frmInputEdit показан на рисунке 7. При помощи выносок указаны имена помещенных на форму элементов управления – компонентов (объектов) формы.

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

Надписи (тип Label) – это объекты с именами, имеющими префикс lbl, используются как подписи элементов формы. Из этих подписей ясно, какие элементы для каких полей данных используются.

Текстовые поля (тип TextBox) – это объекты с именами, имеющими префикс txt: txtFIO – для поля «Фамилия И.О.»; txtM1, txtM2, txtM3, txtM4, txtM5 – группа объектов, которая используется для ввода оценок.

Командные кнопки (тип Button) – это объекты с префиксами cmd, нажатие на кнопку (событие Click), как правило, вызывает определенное действие, связанное с кнопкой.

Элементы управления DateTimePicker, позволяющие достаточно удобно вводить даты: txtDR – для поля «Дата рождения».



Рисунок 7. Форма для ввода и редактирования записей файла данных

Комбинированные поля (тип ComboBox) – они сочетают возможности текстового поля и списка, который может быть раскрывающимся; этот тип элемента управления используется для значения поля «Пол» (ComPol), список значений этого поля задается свойством Items. Свойства элемента «ComPol» зададим следующим образом:

Items = “мужской”

“женский”

Sorted = True


Для заполнения поля «Специальность» (ComSpec) используются данные из файла-справочника, список значений для этого поля формируется во время выполнения программы (код будет приведен ниже).

Флажок (тип CheckBox) – используется для того, чтобы отметить записи, которые будут удалены из файла: Check1.

Элемент управления NumericUpDown, который исполняет роль счетчика: txtKurs – для поля «Курс»; txtGroup – для поля «Группа»; txtKol – для поля «Количество оценок».

Элемент «NumericUpDown» используется для изменения, как в сторону увеличения, так и в сторону уменьшения с заданным шагом, в нашем случае равным 1 (свойство «increment») значений полей «Курс», «Группа» и «Количество оценок». Свойства «minimum» и «maximum» задают нижнюю и верхнюю границы изменения счетчика соответственно.

Для перемещения по записям файла кроме командных кнопок используется также вертикальная полоса прокрутки, которая имеет имя «vscrZap», значения некоторых ее свойств определены следующим образом:

minimum = 1

maxmum = 100

SmallChange = 1

LargeChange = 2

Value = 1


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

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


10.2. Программное обеспечение формы для ввода и редактирования

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

10.2.1. Пользовательские процедуры и функции

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

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

Private Sub LoadSprav()

Dim Sp As TSpec = New TSpec()

Dim i As Integer


' очищаем список элемента ComSpec и добавляем в него

' пустую строку

ComSpec.Items.Clear()

ComSpec.Items.Add(" ")


' определяем количество записей в справочнике

Decl.NSpec = F1_sp.Length \ Sp.len


' если есть хотя бы одна запись,

If NSpec <> 0 Then

' то поочередно считываем их из файла и

' добавляем в список элемента ComSpec

For i = 1 To NSpec

Sp.ReadFromFile(F1_sp, i)

ComSpec.Items.Add(Trim(Sp.Number) + _

" - " + Trim(Sp.Name))

Next i

End If

End Sub


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

Private Function FindSpecCode(ByVal number As Integer) As _

Integer

Dim Sp As TSpec = New TSpec()


Sp.ReadFromFile(F1_sp, number)

FindSpecCode = Sp.code

End Function


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

Public Function FindSpecIndex(ByVal code As Integer) _

As Integer

Dim Sp As TSpec = New TSpec()

Dim i As Integer

Dim temp As Integer


' определяется количество записей в справочнике

NSpec = F1_sp.Length \ Sp.len

temp = 0

For i = 1 To NSpec

' поочередно считываются записи из файла

Sp.ReadFromFile(F1_sp, i)

' и если учетный номер записи совпадает,

If (Sp.Code = code) Then

' то запоминается номер его позиции

temp = i

' и осуществляется выход из цикла проверки

Exit For

End If

Next


' возвращается запомненный номер позиции

FindSpecIndex = temp

End Function


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

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

Public Sub ShowNewZap()

' загружаем Файл-справочник специальности, выполняя

' пользовательскую процедуру

Call LoadSprav()

' полоса прокрутки становится неактивной

vscrZap.Enabled = False


' кнопка «Добавить» становится активной

cmdAdd.Enabled = True


' кнопки «Вперед», «Конец», «Изменить» и «Обновить»

' становятся неактивными

cmdForward.Enabled = False

cmdBottom.Enabled = False

cmdPack.Enabled = False

cmdEdit.Enabled = False


' начальное заполнение элементов,

' соответствующих полям записей

txtFIO.Text = ""

txtKurs.Value = 1

txtGroup.Value = 1

txtKol.Value = 2

ComPol.Text = ComPol.Items(1)

ComSpec.SelectedIndex = 0

txtDR.Value = Now


' в начале предоставлена возможность ввода двух оценок

' пользователь может увеличить их количество до пяти

txtM1.Visible = True

txtM2.Visible = True

txtM3.Visible = False

txtM4.Visible = False

txtM5.Visible = False


' очистка значений элементов txtM,

' которые могли остаться после ввода предыдущей записи

txtM1.Text = ""

txtM2.Text = ""

txtM3.Text = ""

txtM4.Text = ""

txtM5.Text = ""


lblZap.Text = "Новая запись"

txtFIO.Focus()

Check1.Visible = False

End Sub


После ввода всех значений новой записи, для внесения ее в базу данных нужно нажать на кнопку «Добавить».

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

Sub ExitFromInputEdit()

Dim PathOld As String

Dim PathOldSpec As String


' если путь к основному файлу равен "c:\untitled.dan", т.е.

' форма открыта в режиме создания,

frmMenu.Text = frmMenu.Text + " В.А."

If LCase(Decl.Path) = PathUntitled Then

' то выводится запрос пользователю о сохранении базы

Button = MsgBox("Сохранить файл?", vbQuestion +_

vbYesNoCancel, "Сохранение файла")

If Button = vbYes Then

' если пользователь подтверждает сохранение, то

' следует запрос имени файла, в который будет

' сохранена база данных

PathOld = Decl.Path

PathSpec = Mid(Decl.Path, 1, Len(Decl.Path) - 4) + _

".spe"

PathOldSpec = PathSpec

With frmMenu.SaveFileDialog1

.FileName = ""

.Filter = "Все файлы (*.*)|*.*|" + _

"текстовые файлы(*.txt)|*.txt|" + _

"файлы исх. данных(*.dan) |*.dan|" + _

"файлы результата (*.rez)|*.rez"

.FilterIndex = 3

.ShowDialog()

Decl.Path = .FileName

If Decl.Path <> "" Then

PathSpec = Mid(Decl.Path, 1, Len(Decl.Path) - 4) _

+ ".spe"

End If

End With


' если путь не пуст, т.е. пользователь указал

' имя нового файла,

If Decl.Path <> "" Then

' то файлы закрывается и переименовываются

CloseAllFiles()


If Not (Dir(Decl.Path) = "") Then

Kill(Decl.Path)

Kill(PathSpec)

End If

Rename(PathOld, Decl.Path)

Rename(PathOldSpec, Decl.PathSpec)


' затем открываются файлы с

' новыми именами

f1 = New FileStream(Decl.Path, FileMode.OpenOrCreate)

F1_sp = New FileStream(Decl.PathSpec, _

FileMode.OpenOrCreate)


' изменение заголовка формы

Me.Text = "Файл: " + Decl.Path


' все пункты меню становятся активными

frmMenu.mnuView.Enabled = True

frmMenu.mnuQuery.Enabled = True

frmMenu.mnuSort.Enabled = True

frmMenu.mnuFileSaveItem.Enabled = True

frmMenu.mnuFileSaveAsItem.Enabled = True

frmMenu.mnuFileCloseItem.Enabled = True

frmMenu.mnuFileDeleteItem.Enabled = True

frmMenu.mnuSearch.Enabled = True


' форма закрывается

Me.Hide()


' форма frmMenu становится активной

frmMenu.Show()

frmMenu.Enabled = True

frmMenu.Focus()

Else

' иначе считается, что нажата кнопка

' «Отмена»

Decl.Path = PathOld

PathSpec = PathOldSpec

Button = vbCancel

End If

Else

' если пользователь на вопрос о сохранении

' файла нажал кнопку «Нет»

If Button = vbNo Then

Pos = 0

N = 0

' файлы закрываются и удаляются

CloseAllFiles()

Kill(Decl.Path)

Kill(PathSpec)

' пункты меню, которые были неактивными в

' начале работы программы, снова

' становятся неактивными

frmMenu.mnuFileSaveItem.Enabled = False

frmMenu.mnuFileSaveAsItem.Enabled = False

frmMenu.mnuFileCloseItem.Enabled = False

frmMenu.mnuFileDeleteItem.Enabled = False

frmMenu.mnuView.Enabled = False

frmMenu.mnuSort.Enabled = False

frmMenu.mnuQuery.Enabled = False

frmMenu.mnuSearch.Enabled = False


' форма закрывается

Me.Hide()


' форма frmMenu становится активной

frmMenu.Show()

frmMenu.Enabled = True

frmMenu.Focus()

End If

End If

Else

' в случае если форма была открыта в режиме просмотра,

' она закрывается

Me.Hide()


' форма frmMenu становится активной

frmMenu.Show()

frmMenu.Enabled = True

frmMenu.Focus()

End If

End Sub


Теперь, опишем процедуры обработки событий нажатия на кнопку «Выход» или кнопку в правом верхнем углу формы.

Обработка события закрытия формы по нажатию кнопки «Выход»:


Private Sub cmdExit_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdExit.Click

‘ вызов процедуры закрытия формы

ExitFromInputEdit()

End Sub


Обработка события закрытия формы по нажатию кнопки :


Private Sub frmInputEdit_FormClosing(ByVal sender As _

System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles _

MyBase.FormClosing

Call ExitFromInputEdit()

‘ в том случае, если нажата кнопка «Отмена», то с формы

' выход не происходит

If Button = vbCancel Then e.Cancel = True

End Sub


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

Для работы с данными, а именно для вывода в форму полей очередной просматриваемой записи, предусмотрена процедура ShowZap. Она выполняет загрузку элементов формы значениями полей текущей записи (записи с номером i). Ниже приводится код этой процедуры, параметром ее является номер записи в файле.

Public Sub ShowZap(ByVal i As Integer)

Dim R As TStud = New TStud()


' номер записи не должен быть нулем!

If i <> 0 Then

' максимальное значение полосы прокрутки равно

' количеству записей

vscrZap.Maximum = N + 1

vscrZap.Enabled = True

Check1.Checked = False

txtM1.Text = ""

txtM1.Visible = False

txtM2.Text = ""

txtM2.Visible = False

txtM3.Text = ""

txtM3.Visible = False

txtM4.Text = ""

txtM4.Visible = False

txtM5.Text = ""

txtM5.Visible = False


' производится чтение записи и заполнение элементов

' формы, соответствующих полям записи

R.ReadFromFile(f1, Ind(i))

txtFIO.Text = R.FIO

ComPol.SelectedIndex = R.Pol

txtKurs.Text = CStr(R.Kurs)

txtGroup.Text = CStr(R.Group)

txtKol.Text = CStr(R.Kol)

ComSpec.SelectedIndex = FindSpecIndex(R.Spec)

txtDR.Value = R.DataR


If R.Kol > 0 Then

txtM1.Visible = True

txtM1.Text = CStr(R.M(0))

End If

If R.Kol > 1 Then

txtM2.Visible = True

txtM2.Text = CStr(R.M(1))

End If

If R.Kol > 2 Then

txtM3.Visible = True

txtM3.Text = CStr(R.M(2))

End If

If R.Kol > 3 Then

txtM4.Visible = True

txtM4.Text = CStr(R.M(3))

End If

If R.Kol > 4 Then

txtM5.Visible = True

txtM5.Text = CStr(R.M(4))

End If


' вывод номера записи и отметки об ее удалении

lblZap.Text = CStr(i) + "из" + CStr(N)

Check1.Visible = True

Check1.Checked = Del(Ind(i))


' значение полосы прокрутки полагается равным

' номеру записи

vscrZap.Value = i

End If

End Sub


10.2.2. Процедуры обработки событий

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

Процедура обработки события для добавления записи в файл-справочник.

Private Sub cmdAddSpec_Click(ByVal sender As System.Object,_

ByVal e As System.EventArgs) Handles cmdAddSpec.Click

Dim TempStr As String

Dim Sp As TSpec = New TSpec()

Dim tempIndex As Integer


' текущая форма становится неактивной

Me.Enabled = False


' до тех пор пока пользователь не введет число, происходит

' запрос учетного номера новой специальности

TempStr = InputBox("Введите учетный номер специальности", _

"Ввод данных")

Do While Not (IsNumeric(TempStr))

If (TempStr = "") Then

Me.Enabled = True

Exit Sub

End If

MsgBox("Ошибка ввода", vbOKOnly + vbExclamation, _

"Ошибка")

TempStr = InputBox("Введите учетный номер" + _

" специальности", "Ввод данных")

Loop

' учетный номер записывается в структуру Sp

Sp.Code = CByte(TempStr)

' запрос кода специальности

TempStr = InputBox("Введите код сциальности (6 цифр)", _

"Ввод данных")

' код записывается в структуру Sp

Sp.Number = TempStr

' запрос названия новой специальности

TempStr = InputBox("Введите название специальности", _

"Ввод данных")

' название записывается в структуру Sp

Sp.Name = TempStr


' проверяется попытка повторного использования учетного

' номера специальности в файле справочнике

tempIndex = FindSpecIndex(Sp.Code)


' если такой номер уже есть,

If 0 <> tempIndex Then

' то выводится сообщение о возможности изменения данных

If (vbYes = MsgBox("Такой учетный номер уже есть! " _

+ " Перезаписать?", vbYesNo + vbExclamation, _

"Предупреждение")) Then

' изменение данных записи

Sp.writeToFile(F1_sp, tempIndex)

End If

Else

' добавление новой записи в справочник

Sp.writeToFile(F1_sp, NSpec + 1)

End If

' вызов пользовательской процедуры загрузки записей

' справочника в элемент ComSpec

Call LoadSprav()

' текущая форма становится активной

Me.Enabled = True

End Sub


Процедура обработки события изменения записи в файле-справочнике.

Private Sub cmdEditSpec_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdEditSpec.Click

Dim Sp As TSpec = New TSpec()

Dim i As Integer


' текущая форма становится неактивной

Me.Enabled = False


' чтение текущей записи из файла-справочника

i = ComSpec.SelectedIndex

Sp.ReadFromFile(F1_sp, i)


' запрос на изменение кода специальности

If (vbNo = MsgBox("Код специальности оставить без" + _

" изменения?", vbYesNo + vbExclamation, "Вопрос:")) Then

Sp.Number = InputBox("Введите новый код " + _

"специальности (6 цифр)", "Ввод данных")

End If


' запрос на изменение кода специальности

If (vbNo = MsgBox("Название специальности оставить " + _

"без изменения?", vbYesNo + vbExclamation, _

"Вопрос:")) Then

Sp.Name = InputBox("Введите новое название " + _

"специальности", "Ввод данных")

End If


' запись обновленных данных

Sp.writeToFile(F1_sp, i)


' вызов пользовательской процедуры загрузки записей

' справочника в элемент ComSpec

Call LoadSprav()


' текущая форма становится активной

Me.Enabled = True

End Sub


Процедура обработки события удаления записи из файла-справочника.


Private Sub cmdDelSpec_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdDelSpec.Click

Dim i As Integer

Dim j As Integer

Dim ListIndex As Integer


Dim Sp As TSpec = New TSpec()

Dim R As TStud = New TStud()

Dim TempFile As FileStream


' текущая форма становится неактивной

Me.Enabled = False


' сообщение о возможности удаления записей

' из основного файла

If (vbNo = MsgBox("Внимание!!! Все данные, " + _

"содержащие удаляемую информацию будут уничтожены!" + _

" Продолжить?", vbYesNo + vbExclamation, _

"Предупреждение:")) Then

' если была нажата кнопка «Нет», то выход из процедуры

' и текущая форма становится неактивной

Me.Enabled = True

Exit Sub

End If


' отметка на удаление всех записей основного файла базы,

' в которых содержится информация об удаляемой спец-ности

ListIndex = ComSpec.SelectedIndex

If ListIndex <> 0 Then

Sp.ReadFromFile(F1_sp, ListIndex)


For i = 1 To N

R.ReadFromFile(f1, i)

If R.Spec = Sp.Code Then

Del(i) = 1

End If

Next i


End If


' запись во временный файл всех данных, за исключением

' данных об удаляемой специальности

TempFile = New FileStream (PathTemp, FileMode.Create)

j = 1

For i = 1 To NSpec

Sp.ReadFromFile(F1_sp, i)

If i <> ListIndex Then

Sp.writeToFile(TempFile, j)

j = j + 1

End If

Next i


F1_sp.Close()

TempFile.Close()


' перезапись измененного файла-справочника

Kill(PathSpec)

Rename(PathTemp, PathSpec)


' загрузка обновленного файла-справочника

F1_sp = New FileStream(PathSpec, FileMode.Open)


' вызов пользовательской процедуры загрузки записей

' справочника в элемент ComSpec

Call LoadSprav()


' текущая форма становится активной

Me.Enabled = True


' вызов процедуры удаления отмеченных записей

' основного файла данных

cmdPack_Click(sender, e)

End Sub


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


Процедура обработки события нажатия на кнопку «Добавить» обеспечивает добавление записи в файл базы данных и подготовку к вводу полей новой записи.

Private Sub cmdAdd_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdAdd.Click

Dim R As TStud = New TStud()

Dim Sp As TSpec = New TSpec()


' заполнение полей записи

R.FIO = txtFIO.Text

R.Kurs = CByte(txtKurs.Text)

R.Group = CByte(txtGroup.Text)

R.Kol = CByte(txtKol.Text)

R.Pol = CByte(ComPol.SelectedIndex)

R.Spec = FindSpecCode(ComSpec.SelectedIndex)

R.DataR = txtDR.Value


' проверка корректности введенных данных в поле

' специальности

If R.Spec = 0 Then

MsgBox("Неверное значение поля специальность!")

Exit Sub

End If


' проверка непустоты полей оценок

If (txtM1.Text = "") Or (txtM2.Text = "") Or _

(R.Kol > 2) And (txtM3.Text = "") Or _

(R.Kol > 3) And (txtM4.Text = "") Or _

(R.Kol > 4) And (txtM5.Text = "") Then

MsgBox("Введены не все оценки!")

Exit Sub

End If


R.M(0) = CByte(txtM1.Text)

R.M(1) = CByte(txtM2.Text)

If R.Kol > 2 Then R.M(2) = CByte(txtM3.Text)

If R.Kol > 3 Then R.M(3) = CByte(txtM4.Text)

If R.Kol > 4 Then R.M(4) = CByte(txtM5.Text)

' позиция передвигается,

Pos = N + 1

' количество записей увеличивается

N = N + 1

' запись вносится в файл

R.writeToFile(f1, Pos)


' кнопки «Начало» и «Назад» становятся активными

cmdTop.Enabled = True

cmdBackUp.Enabled = True

cmdExit.Focus()


' вызов процедуры для заполнения новой записи

Call ShowNewZap()

End Sub


А теперь попытайтесь заполнить файл данными (1–2 записи) и закрыть форму frmInputEdit с сохранением файлов.

Заметим, что количество видимых на форме элементов txtM«i», предназначенных для ввода оценок прямо зависит от содержимого элемента txtKol. Таким образом, скрытие лишних видимых элементов и показ нужных невидимых элементов txtM«i» должны зависеть от изменения содержимого txtKol, т.е. далее необходимо обработать событие изменения содержимого элемента txtKol. Приведем код процедуры обработки этого события.

Private Sub txtKol_ValueChanged(ByVal sender As System.Object,_

ByVal e As System.EventArgs) Handles txtKol.ValueChanged

Dim i As Integer = txtKol.Value


' все элементы, соответствующие оценкам скрываются

txtM1.Visible = False

txtM2.Visible = False

txtM3.Visible = False

txtM4.Visible = False

txtM5.Visible = False

' открываются первые несколько элементов

' их количество зависит от значения элемента txtKol

If i > 0 Then txtM1.Visible = True

If i > 1 Then txtM2.Visible = True

If i > 2 Then txtM3.Visible = True

If i > 3 Then txtM4.Visible = True

If i > 4 Then txtM5.Visible = True


End Sub


Таким образом, при изменении содержимого элемента txtKol все элементы txtM, соответствующие оценкам скрываются, затем открывается столько элементов, сколько указано в содержимом элемента txtKol.

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

Private Sub txtM_TextChanged(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles txtM5.TextChanged, _

txtM4.TextChanged, txtM3.TextChanged, txtM2.TextChanged, _

txtM1.TextChanged

Dim txtM As TextBox = sender

' если содержимое элемента txtM(Index) является числом

If IsNumeric(txtM.Text) = True Then

' и не находится в пределах от 2 до 5,

If CByte(txtM.Text) < 2 Or CByte(txtM.Text) > 5 Then

' пользователь получает предупреждение об ошибке

MsgBox("Неверная оценка", vbExclamation + vbOKOnly, _

"Ошибка")

End If

ElseIf txtM.Text <> "" Then

' если содержимое не является цифрой,

' пользователь получает предупреждение об ошибке

MsgBox("Оценка должна являться цифрой!", vbOKOnly + _

vbExclamation, "Ошибка")

End If

End Sub


В этом месте нужно выполнить полное тестирование формы frmInputEdit, для этого необходимо заполнить файл данными (4–5 записей) и сохранить его.


Кроме ввода новых данных форма frmInputEdit должна позволять просматривать и редактировать существующие данные, для этого необходимо описать перемещение по записям нашей базы данных. Для перемещения по записям будем использовать кнопки «Начало» (cmdTop), «Конец» (cmdBottom), «Назад» (cmdBackUp) и «Вперед» (cmdForward). Опишем обработку событий нажатия для каждой кнопки:

Private Sub cmdTop_Click(ByVal sender As System.Object,_

ByVal e As System.EventArgs) Handles cmdTop.Click

' вывод первой записи данных

Pos = 1

Call ShowZap(Pos)


' кнопки перемещения по записям становятся активными

frmMenu.Text = frmMenu.Text + " Авт"

cmdTop.Enabled = True

cmdBottom.Enabled = True

cmdForward.Enabled = True

cmdBackUp.Enabled = True


' кнопки «Изменить» и «Обновить» становятся активными

cmdEdit.Enabled = True

cmdPack.Enabled = True


' кнопка «Добавить» становится неактивной

frmMenu.Text = frmMenu.Text + "ор: "

cmdAdd.Enabled = False


' фокус передается на кнопку «Выход»

cmdExit.Focus()

End Sub


Private Sub cmdBottom_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdBottom.Click

' вывод последней записи данных

Pos = N

Call ShowZap(Pos)


' кнопки перемещения по записям становятся активными

frmMenu.Text = frmMenu.Text + "дов "

cmdTop.Enabled = True

cmdBottom.Enabled = True

cmdForward.Enabled = True

cmdBackUp.Enabled = True


' кнопки «Изменить» и «Обновить» становятся активными

cmdEdit.Enabled = True

cmdPack.Enabled = True


' кнопка «Добавить» становится неактивной

cmdAdd.Enabled = False


' фокус передается на кнопку «Выход»

cmdExit.Focus()

End Sub


Private Sub cmdBackUp_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdBackUp.Click

' переход на предыдущую позицию

Pos = Pos - 1


' все кнопки становятся активными

frmMenu.Text = frmMenu.Text + "рохо"

cmdTop.Enabled = True

cmdBottom.Enabled = True

cmdForward.Enabled = True

cmdEdit.Enabled = True

cmdPack.Enabled = True


' если запись первая, то кнопка «Назад»

' становится неактивной

If Pos <= 1 Then

cmdBackUp.Enabled = False

Pos = 1

End If


' вывод записи с номером Pos

Call ShowZap(Pos)

End Sub


Private Sub cmdForward_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdForward.Click

' переход на следующую позицию

frmMenu.Text = frmMenu.Text + "Ско"

Pos = Pos + 1


' если была не последняя запись,

If Pos <= N Then

' то переход на следующую запись

vscrZap.Value = Pos

Call ShowZap(Pos)

cmdBackUp.Enabled = True

cmdExit.Focus()

Else

' иначе вызов процедуры для заполнения новой записи

Call ShowNewZap()

End If

End Sub

Для перемещения по записям базы данных можно использовать полосу прокрутки (элемент управления VscrZap). При помощи полосы прокрутки можно перемещаться на одну или несколько записей в базе. Процедура обработки события изменения значения имеет вид:

Private Sub vscrZap_Scroll(ByVal sender As System.Object, _

ByVal e As System.Windows.Forms.ScrollEventArgs) _

Handles vscrZap.Scroll


‘ максимальное значение полосы прокрутки равно

‘ количеству записей

VScrZap.Maximum = N


‘ перемещение на запись по значению полосы прокрутки

Pos = VScrZap.Value

Call ShowZap(Pos)

End Sub


Заметим, что во всех этих процедурах обработки событий нажатия на кнопки вызывается процедура ShowZap. Эта процедура позволяет загрузить в элементы формы все поля указанной записи, т.е. именно она обеспечивает просмотр определенной записи в данных.


Новый этап тестирования проекта для проверки возможности перемещения по записям базы данных с использованием описанных возможностей.


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

Для очередного этапа тестирования проекта необходимо подготовить тестовый файл, в котором должно быть 15–20 записей с разными значениями курсов (2–3 курса), для каждого значения курса должно быть несколько групп (2–3 группы), в каждой группе должно быть несколько студентов (3–4 студента).

Создайте файл, удовлетворяющий описанным выше требованиям, и сохраните его в папке проекта. Этот файл будет использоваться для тестирования заявленных функций приложения.

11. Работа с существующим файлом

11.1. Открытие файла

Для открытия файла необходимо выполнить команду «Файл  Открыть». Ей соответствует процедура обработки события, приведенная ниже.


Private Sub mnuFileOpenItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuFileOpenItem.Click

Dim R As TStud = New TStud()

Dim Sp As TSpec = New TSpec()

Dim i As Integer


Decl.Path = PathUntitled

' запрос имени файла базы данных

With OpenFileDialog1

.FileName = ""

.Filter = "Все файлы (*.*)|*.*|" + _

"текстовые файлы(*.txt)|*.txt|" + _

"файлы исх. данных(*.dan)|*.dan|" + _

"файлы результата (*.rez)|*.rez"

.FilterIndex = 3

.ShowDialog()

Decl.Path = .FileName

If Decl.Path <> "" Then

PathSpec = Mid(Decl.Path, 1, Len(Decl.Path) - 4) + _

".spe"

End If

End With


' если имя файла не пусто

If Decl.Path <> "" Then

' файл открывается

f1 = New FileStream(Decl.Path, FileMode.Open)

' определяется количество записей базы данных

N = f1.Length \ R.len

' аналогично открываем файл справочник для

' специальности

F1_sp = New FileStream(PathSpec, FileMode.Open)

NSpec = F1_sp.Length \ Sp.len


Pos = 1

frmInputEdit.Text = "Файл: " + Decl.Path


' все пункты меню становятся активными

mnuView.Enabled = True

mnuSort.Enabled = True

mnuSearch.Enabled = True

mnuQuery.Enabled = True

mnuFileSaveItem.Enabled = True

mnuFileSaveAsItem.Enabled = True

mnuFileCloseItem.Enabled = True

mnuFileDeleteItem.Enabled = True

End If


' инициализация индексного массива Ind, который будет

' использоваться для сортировки данных, и массива Del

' для пометки удаляемых записей

For i = 1 To Nmax

Ind(i) = i

Del(i) = 0

Next i

End Sub


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

11.2. Просмотр файла базы данных

Файл базы данных можно просмотреть, используя форму frmInputEdit. Для этого необходимо написать еще одну пользовательскую процедуру для данной формы (не забудьте для этого перейти в окно кода формы frmInputEdit). Это процедура с именем View_Form, которая должна загрузить данные и вывести первую запись в уже известном нам виде на форме frmInputEdit. Ниже приведен код этой процедуры.


Public Sub view_form()

Dim R As TStud = New TStud()


' загрузка формы frmInputEdit

frmMenu.Enabled = False

Me.Enabled = True

Me.Show()


' загрузка Файла-справочника по специальности, выполнение

' пользовательской процедуры

Call LoadSprav()

' определение количества записей в основном файле базы

N = f1.Length \ R.len


' если записей нет, то вызов процедуры для заполнения

' новой записи

If N = 0 Then

Call ShowNewZap()

cmdAdd.Enabled = True

Else

' иначе производится загрузка и вывод первой записи

Pos = 1

vscrZap.Value = Pos

Call ShowZap(Pos)


' кнопки перемещения по записям становятся активными

cmdTop.Enabled = True

cmdBottom.Enabled = True

cmdForward.Enabled = True

cmdBackUp.Enabled = True


' кнопки «Изменить» и «Обновить» становятся активными

cmdEdit.Enabled = True

cmdPack.Enabled = True


' кнопка «Добавить» становится неактивной

cmdAdd.Enabled = False


' фокус передается на кнопку «Выход»

cmdExit.Focus()

End If

End Sub


В данной процедуре открытый файл проверяется на пустоту и если он пуст (т.е. файл существует, но в нем нет ни одной записи данных), то вызывается процедура создания нового файла-базы данных (процедура ShowNewZap). Если файл не является пустым, то вызывается процедура ShowZap для вывода в форму первой записи, а так же делаются активными кнопки, позволяющие перемещаться по записям базы данных.

Для просмотра файла базы данных с использованием формы frmInputEdit необходимо в форме frmMenu написать процедуру обработки события выбора команды меню «Просмотр  Форма», которая содержит вызов пользовательской процедуры View_Form, принадлежащей форме frmInputEdit:


Private Sub mnuViewFormItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuViewFormItem.Click

‘ вызов процедуры загрузки формы

frmInputEdit.View_Form

End Sub


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

Для вывода данных в виде таблицы добавим в проект еще одну форму, дадим этой форме имя frmTableReadOnly и поместим на нее элемент для отображения данных в виде таблицы (DataGridView), переименуем этот элемент, задав его имя, GridView1.

Процедура обработки события выбора пункта меню «Просмотр  Таблица» имеет вид:


Private Sub mnuViewTableItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuViewTableItem.Click

Dim i As Integer

Dim j As Integer

Dim R As TStud = New TStud()

Dim sp As TSpec = New TSpec()


With frmTableReadOnly.GridView1


' установка количества строк таблицы и ширины столбцов

.ColumnCount = 12


' запись названий столбцов в таблицу

.Columns(0).Name = "Номер"

.Columns(1).Name = "Курс"

.Columns(2).Name = "Группа"

.Columns(3).Name = "Специальность"

.Columns(4).Name = "ФИО"

.Columns(5).Name = "Пол"

.Columns(6).Name = "Кол-во оценок"


For j = 1 To 5

.Columns(j + 6).Name = "Оц.№ " + CStr(j)

Next j


' чтение очередной записи и загрузка ее полей

' в таблицу

For i = 1 To N


R.ReadFromFile(f1, Ind(i))


' чтение специальности по ее коду

j = frmInputEdit.FindSpecIndex(R.Spec)

sp.ReadFromFile(F1_sp, j)


' загрузка новой строки в таблицу

Dim row As String() = New String() _

{CStr(i), R.Kurs, R.Group, _

Trim(sp.Number) + " - " + Trim(sp.Name), Trim(R.FIO), _

R.Pol, R.Kol, R.M(0), R.M(1), R.M(2), R.M(3), R.M(4)}


.Rows.Add(row)


Next i

End With


' изменение заголовка формы

frmTableReadOnly.Text = "Просмотр файла: " + Decl.Path


' загрузка формы frmTableReadOnly

frmTableReadOnly.Show()

End Sub


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

11.3. Изменение и удаление записей в файле базы данных

Эти действия предусмотрены в форме для ввода и редактирования (форма frmInputEdit) и для их выполнения используются кнопки «Изменить» (cmdEdit) и «Обновить» (cmdPack).

Для корректировки содержимого полей текущей записи используется кнопка «Изменить». Отредактировав нужные поля некоторой записи, нажимаем кнопку «Изменить» и все изменения для текущей записи вносятся в базу данных. Обработка события нажатия на кнопку «Изменить»:

Private Sub cmdEdit_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdEdit.Click

Dim R As TStud = New TStud()


' производится заполнение всех полей записи,

' включая измененные

R.FIO = txtFIO.Text

R.Kurs = CByte(txtKurs.Text)

R.Group = CByte(txtGroup.Text)

R.Kol = CByte(txtKol.Text)

R.Pol = ComPol.SelectedIndex

R.Spec = FindSpecCode(ComSpec.SelectedIndex)

R.DataR = txtDR.Value


R.M(0) = CByte(txtM1.Text)

R.M(1) = CByte(txtM2.Text)

If R.Kol > 2 Then

If txtM3.Text <> "" Then

R.M(2) = CByte(txtM3.Text)

Else

MsgBox("Оценка №3 должна являться цифрой!", vbOKOnly + _

vbExclamation, "Ошибка")

Exit Sub

End If

End If

If R.Kol > 3 Then

If txtM4.Text <> "" Then

R.M(3) = CByte(txtM4.Text)

Else

MsgBox("Оценка №4 должна являться цифрой!", vbOKOnly + _

vbExclamation, "Ошибка")

Exit Sub

End If

End If

If R.Kol > 4 Then

If txtM5.Text <> "" Then

R.M(4) = CByte(txtM5.Text)

Else

MsgBox("Оценка №5 должна являться цифрой!", vbOKOnly + _

vbExclamation, "Ошибка")

Exit Sub

End If

End If


' запись вносится в файл на то место,

' на котором находилась старая запись

R.writeToFile(f1, Pos)


MsgBox("Изменение выполнено успешно!")

End Sub


С файлом исходных данных связан массив Del, который по умолчанию заполнен нулями. Удаляемым записям соответствует значение, равное единице. Для того чтобы удалить некоторые записи, необходимо отметить их на форме frmInputEdit, используя флажок-переключатель Check1, затем нажать на кнопку «Обновить». Для элемента Check1 и кнопки «Обновить» процедуры обработки события Click – щелчка левой кнопки мыши на этих объектах имеют вид:

Private Sub Check1_CheckedChanged(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles Check1.CheckedChanged

' отмечается на удаление запись с номером Pos

If Check1.Checked Then

Del(Ind(Pos)) = 1

Else

Del(Ind(Pos)) = 0

End If

End Sub


Private Sub cmdPack_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles cmdPack.Click

Dim i As Integer

Dim j As Integer = 1

Dim R As TStud = New TStud()


' открывается вспомогательный файл

F2 = New FileStream(PathTemp, FileMode.Create)


' из основного файла во вспомогательный переписываются

' записи, которые не нужно удалять

For i = 1 To N

R.ReadFromFile(f1, i)

If Del(i) = 0 Then

R.writeToFile(F2, j)

j = j + 1

End If

Next i


' закрываются файлы, и происходит сохранение

' вспомогательного файла под именем основного

' файла базы данных

f1.Close()

F2.Close()

Kill(Decl.Path)

Rename(PathTemp, Decl.Path)


' открывается новый основной (рабочий файл) базы

f1 = New FileStream(Decl.Path, FileMode.Open)

N = f1.Length \ R.len


' возвращение исходных значений массивам Ind и Del

For i = 1 To Nmax

Ind(i) = i

Del(i) = 0

Next i


' вывод первой записи данных

Pos = 1

If N = 0 Then

Call ShowNewZap()

Else

Call ShowZap(Pos)

End If


MsgBox("Обновление выполнено успешно!")

End Sub


Таким образом, для удаления записей используется временный файл, куда переносятся все те записи, которые не должны быть удалены (для них значение Del(i) равно нулю), затем исходный файл удаляется, а временный файл переименовывается.


Новый этап тестирования проекта с целью проверки его работоспособности при добавленных возможностях.


11.4. Сохранение и удаление файлов

Мы описали возможности ввода, просмотра и редактирования данных. Добавим несколько процедур, обрабатывающие события выбора следующих пунктов меню: «Файл  Сохранить как», «Файл  Закрыть» и «Файл  Удалить».

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

Private Sub mnuFileSaveAsItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuFileSaveAsItem.Click

Dim R As TStud = New TStud()

Dim Sp As TSpec = New TSpec()

Dim PathOld As String

Dim PathOldSpec As String


' запоминаются имена основного файла базы данных и

' Файла-справочника

PathOld = Decl.Path

PathSpec = Mid(Decl.Path, 1, Len(Decl.Path) - 4) + ".spe"

PathOldSpec = PathSpec


' запрос имени нового файла базы

With Me.SaveFileDialog1

.FileName = ""

.Filter = "Все файлы (*.*)|*.*|" + _

"Текстовые файлы. (*.txt)|*.txt|" + _

"Файлы исходных данных (*.dan)|*.dan|" + _

"Файлы результатов (*.rez)|*.rez"

.FilterIndex = 3

.ShowDialog()

Decl.Path = .FileName

If Decl.Path <> "" Then

PathSpec = Mid(Decl.Path, 1, Len(Decl.Path) - 4) + _

".spe"

End If

End With


' если имя нового основного файла пусто, то рабочие файлы

' остаются прежними и производится выход из процедуры

If Decl.Path = "" Then

Decl.Path = PathOld

PathSpec = PathOldSpec

Exit Sub

End If


' иначе файлы закрывается и производится копирование

' рабочих файлов

Close()

If Not (Dir(Decl.Path) = "") Then

Kill(Decl.Path)

Kill(PathSpec)

End If

FileCopy(PathOld, Decl.Path)

FileCopy(PathOldSpec, PathSpec)


' после копирования открываются новые файлы

f1 = New FileStream(Decl.Path, FileMode.Open)

F1_sp = New FileStream(PathSpec, FileMode.Open)


frmInputEdit.Text = "Файл: " + Decl.Path

End Sub


При выборе пункта меню «Файл  Закрыть» все открытые файлы должны быть закрыты и все пункты меню, недоступные в начале работы снова должны снова стать недоступными.

Private Sub mnuFileCloseItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuFileCloseItem.Click

' закрываются все файлы, открытые в процессе работы

CloseAllFiles()


' пункты меню, которые были неактивными в начале

' работы программы, снова становятся неактивными

mnuFileSaveItem.Enabled = False

mnuFileSaveAsItem.Enabled = False

mnuFileCloseItem.Enabled = False

mnuFileDeleteItem.Enabled = False

mnuView.Enabled = False

mnuSort.Enabled = False

mnuQuery.Enabled = False

mnuSearch.Enabled = False

End Sub


При выборе пункта меню «Файл  Удалить» основной файл базы (файл с данными) должен быть удален, и все пункты меню, недоступные в начале работы снова должны снова стать недоступными.


Private Sub mnuFileDeleteItem_Click(ByVal sender As _

System.Object, ByVal e As System.EventArgs) _

Handles mnuFileDeleteItem.Click

Dim Button As Integer


' запрос подтверждения на удаление

Button = MsgBox("Действительно удалить?", vbYesNo + _

vbQuestion, "Удаление файла")


' в случае подтверждения вызывается процедура закрытия

' и удаляется основной файл базы данных

If Button = vbYes Then

Call mnuFileCloseItem_Click(sender, e)

Kill(Decl.Path)

Kill(PathSpec)

End If

End Sub


На этом месте снова необходимо протестировать проект на работоспособность и корректность работы. Особое внимание следует уделить взаимодействию различных компонентов приложения.