КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Property Variant FieldValues
Это свойство позволяет обращаться к полю через его имя, указываемое как содержимое параметра FieldName, например: Table1->FieldValues["FIO"] = "Иванов"; Поскольку свойство FieldValues принимается для набора данных по умолчанию, его имя при обращении к полю можно опускать: Table1["Name"] = "Иванов"; Более предпочтительным считается обращение к полю через его имя или через метод FieldByName, поскольку в этом случае мы обращаемся к конкретному полю по его имени. Следовательно, к несуществующему полю обратиться нельзя. К значению поля можно обратиться при помощи свойств Value и AsNNN. Свойство __property Variant Value возвращает значения следующих типов: __property Value Variant; // Все компоненты __property String Value; //TStringField, TBIobField __property Longint Value; //TAutoIncField, TIntegerField, TSmallintField,TWordField __property Double Value; //TBCDField, TCurrencyField, TFloatField __property Boolean Value; //TBooleanField __property TDateTime Value; //TDateField, TDateTimeField, TTimeField Это дает возможность пользоваться свойствами приведения типов полей ( AsString, Aslnteger и т.д.) в гораздо меньших масштабах. Тем не менее, обойтись без них удается далеко не всегда. Аналогичные значения возвращает рассмотренное выше свойство набора данных FieldValues. Например, int N; N = TablelNumber->Value; // TablelNumber типа TIntegerField Обращение к значению поля через свойство AsNNN. Существуют следующие свойства приведения типов полей: __property Boolean AsBoolean; __property Currency AsCurrency; __property TDateTime AsDateTime; __property Double AsFloat; __property Integer Aslnteger; __property String AsString; __property Variant AsVariant; Каждое из этих свойств приводит значение поля к соответствующему типу данных, означенному в названии свойства. Например, если Table1Number -компонент TIntegerField (поле, хранящее целочисленные значения), для приведения его к типу String можно воспользоваться свойством Edit1.Text = Table1Number->AsString;
Несомненно, тип поля должен быть совместимым с типом данных, к которому приводится значение поля. Например, если TablelSumma - компонент TFloatField (поле, хранящее вещественные значения), попытка привести его к несовместимому типу Boolean, if (TablelSumma->AsBoolean)... приведет к ошибке компиляции. Рассмотрим свойства семейства AsNNN более подробно: __property Boolean AsBoolean; - числовые значения приводятся к типу Boolean, если содержат 0 (false) или 1 (true). Символьные значения - если содержат в качестве первого символа "Y", "у", "Т" или "t" (или "Yes" или " true "), и false во всех иных случаях. __property TDateTime AsDateTime; - для приведения к типу TDateTime значений TDateField, TDateTimeField и TTimeField, хотя вместо этого лучше использовать свойство Value, а также для приведения к типу TDateTime строковых значений, находящихся в соответствующем формате. __property double AsFloat; - служит для приведения к типу double значений полей TFloatField, TBCDField и TCurrencyField, AsFloat, хотя вместо этого лучше использовать свойство Value. __property longint Aslnteger; - служит для приведения к типу longint полей типа TIntegerField, TSmallintField и TWordField, хотя вместо этого лучше использовать свойство Value. Для полей типа TStringField преобразование к longint выполняется, если оно возможно. __property Currency AsCurrency; - служит для приведения к типу Currency. __property String AsString; - служит для приведения к типу String. __property Variant AsVariant; - служит для приведения к типу Variant.
Теперь перейдем непосредственно к решению поставленной задачи. Для ввода информации в БД предусмотрим в приложении отдельную форму. Добавьте ее к своему проекту как делали это ранее. Исправьте свойство Name с Form2 на FNewInfo и cохраните новую форму под именем UNewInfo.cpp (вместо Unit2.cpp). Теперь надо обеспечить переход со стартовой формы на третью форму. Переключитесь на форму №1 (UDB1.cpp) и добавьте на форму новую кнопку с названием «Ввести информацию»: Для того чтобы можно было обращаться к форме №3 из первой ее надо подключить: выполните Fail | Use unit… и из списка выберите UNewInfo. Теперь дважды щелкните по кнопке и попадете в программный код. Между двумя фигурными скобками напишите текст:
FNewInfo->ShowModal();
Таким образом, мы передаем управление форме №3. Обратите внимание, что форма №3 будет вызвана в модальном режиме, т.е. пока форма №3 не будет закрыта, нельзя работать с формами 1 и 2. Было бы неплохо обеспечить переход на форму №3, не только с формы №1, но и формы №2. Для этого разместите на форме №2 новую кнопку, дайте ей тоже название, что и выше и занесите в обработчик события нажатия код, указанный выше по тексту. Не забудьте к форме №2 подключить юнит третьей формы. Перейдем к проектированию формы №3. В нашей БД 3 таблицы и все 3 таблицы пользователь может заполнять. Поэтому в программе надо предусмотреть возможность ввода информации во все эти таблицы. Можно было бы под каждую таблицу выделить по отдельной форме, но мы в целях экономии ограничимся одной формой. Разделим визуально форму на 3 части, используя компонент TBevel, также как это было сделано на форме №2. Первая часть формы будет предназначаться для ввода нового студента. Чтобы ввести нового студента в БД можно ограничиться двумя компонентами TEdit, для ввода фамилии и имени, одним компонентом TDateTimePicker, для ввода дня рождения и одним компонентом TRadioGroup, для выбора пола студента. Еще, конечно же, понадобится кнопка, которая будет пересылать информацию в БД: Чтобы не путаться в большом количестве однотипных элементов зададим им "говорящие" имена (свойство Name). Пусть компонент TEdit под надписью Фамилия носит имя EFam, а компонент TEdit под надписью Имя – ENam, дату рождения переименуем в DTBirth, а кнопку в BNewStud. Вторая часть формы будет предназначаться для ввода нового предмета. Здесь мы можем ограничиться 1 компонентом TEdit, который назовите EPred, и одной кнопкой, которую назовите BNewPred: Третья часть формы будет предназначаться для ввода новой оценки. В этой части формы уже нельзя давать пользователю свободу ввода информации, т.к. он может ввести несуществующие фамилию, предмет или даже оценку. Поэтому использовать компонент TEdit не будет, а ограничим возможности пользователя выбор из выпадающих списков (компонент TComboBox), которых нам потребуется 3: для фамилий, для предметов и для оценок. Еще нам потребуется компонент TDateTimePicker для указания даты экзамена и естественно кнопка:
Осталось проставить имена компонентов: TComboBox для студентов – CBStudExam, TComboBox для предметов – CBPredExam, TComboBox для оценок – CBOcen, TDateTimePicker для ввода даты экзамена – DTExam, для кнопки – BNewOcen. Общий вид формы №3 должен соответствовать рисунку: Закончить проектирование надо заполнением выпадающих списков. Компонент CBOcen надо заполнить возможными оценками: в свойство Items занесите построчно 2, 3, 4, 5. Компоненты CBStudExam и CBPredExam надо заполнять программно, аналогично второй форме. Для данной формы сделаем это используя пользовательские функции, чтобы при необходимости можно было ее вызвать. Назовем функции LoadStud и LoadPred в соответствии с теми компонентами, к которым они относятся. Т.к. эти функции сугубо для внутренних целей формы №3, то их вполне можно занести в раздел закрытых функций. Откройте файл UNewInfo.h и внесите следующий программный код: private: void LoadStud(); void LoadPred(); теперь откройте файл и напишите определение этих функций, т.е. вставьте в конец файла следующие строки: void TFNewInfo::LoadStud() { FShow->ADOTbFam->Active=false; FShow->ADOTbFam->Active=true; FShow->ADOTbFam->First(); CBStudExam->Items->Clear(); while(!FShow->ADOTbFam->Eof) { CBStudExam->Items->Add(FShow->ADOTbFamfam_student->Value+" "+FShow->ADOTbFamname_student->Value); FShow->ADOTbFam->Next(); } FShow->ADOTbFam->First(); } void TFNewInfo::LoadPred() { FShow->ADOTbPred->Active=false; FShow->ADOTbPred->Active=true; FShow->ADOTbPred->First(); CBPredExam->Items->Clear(); while(!FShow->ADOTbPred->Eof) { CBPredExam->Items->Add(FShow->ADOTbPredname_predmet->Value); FShow->ADOTbPred->Next(); } FShow->ADOTbPred->First(); } Осталось только чтобы при загрузке формы вызывались эти функции. В обработчик события OnShow формы №3 занесите код:
LoadStud(); LoadPred();
Перед тем вводить информацию в БД средствами С++ Builder надо иметь представление о возможных состояниях набора данных (НД). НД могут находиться в одном из 6 состояний:
Рассмотрим методы, которые могут переводить БД из одного состояния в другое.
• Inactive → dsBrowse НД во время выполнения программы можно открыть методами Table->Open(), Query->Open(). Во время разработки и во время выполнения НД можно открыть, установив в true свойства Table->Active и Query->Active. • dsBrowse → Inactive НД во время выполнения программы можно закрыть методами Table->Close(), Query->Close(). Во время разработки и во время выполнения НД можно закрыть, установив в false свойства Table->Active и Query->Active. Заметим, что если какая-либо запись на момент закрытия НД находится в режиме редактирования (dsEdit) или добавления новой записи (dsInsert), применение метода Close не приводит к автоматической выдаче метода Post. Таким образом, НД закрывается, находясь в режимах dsInsert или dsEdit, а не dsBrowse. В этом случае изменения, сделанные в записи, не запоминаются. Для перевода НД из указанных режимов в режим dsBrowse, перед тем как НД закрывается, используйте обработчик события BeforeClose. Заметим, что описанная ситуация будет встречаться в первую очередь для внезапно или принудительно закрываемых НД. • dsBrowse → dsEdit Перевести НД в режим редактирования можно методом Edit(). После этого значения полей текущей записи можно изменять. • dsEdit → dsBrowse Метод Post() приводит к запоминанию измененной записи в НД. Метод Cancel() отменяет изменения, сделанные в полях записи. Запись не запоминается в НД. • dsBrowse → dslnsert Перевести НД в режим вставки можно методами Insert() или Append(), После этого программе становится доступна пустая запись, полям которой нужно присвоить какие-либо значения. Чтобы полям новой записи присвоить умалчиваемые значения, следует воспользоваться обработчиком события OnNewRecord. • dslnsert → dsBrowse Метод Post() добавляет новую запись в НД. Если НД не находится в режиме dsInsert, возбуждается исключительная ситуация. Метод Cancel() отменяет добавление новой записи в НД. Содержимое полей, назначенных новой записи, теряется. • dsBrowse → dsSetKey НД находится в данном состоянии, когда осуществляется поиск записи, удовлетворяющей условию, установленному методом SetKey (и затем, возможно, измененному методом EditKey). Именно эти методы и переводят НД в режим dsBrowse. Поиск записи производится одним из следующих методов: GoToKey, GoToNearest, FindKey, FindNearest. В случае успешного или неуспешного завершения метода поиска, НД переводится в состояние dsBrowse. • dsBrowse → dsFilter НД находится в данном состоянии всякий раз, когда приложение обрабатывает событие OnFilterRecord при фильтрации записей (при свойстве Filtered = True). При этом НД переводится из состояния dsBrowse в состояние dsFilter. Это предотвращает модификацию НД во время фильтрации. После завершения вызова обработчика события OnFilterRecord НД переводится в состояние dsBrowse. Вызов события OnFilterRecord производится для каждой записи НД при установке свойства Filtered в состояние true. Получить текущее состояние НД можно, используя метод State(). Он возвращает следующие константы: dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey, dsCalcFields, dsFilter. Пример if (Table1->State = dsInactive) Table1->Active = true;
Вводить информацию в БД можно только используя НД. Поэтому на форму надо добавить 3 компонента TADOTable для каждой таблицы. Настройте их на соответствующие таблицы и назовите TbNewStud, TbNewPred, TbNewOcen. Обработка нажатия кнопки «Ввести нового студента» должна выглядеть следующим образом:
void __fastcall TFNewInfo::BNewStudClick(TObject *Sender) { TbNewStud->Open(); TbNewStud->Insert(); TbNewStud->FieldByName("fam_student")->AsString=EFam->Text; TbNewStud->FieldByName("name_student")->AsString=ENam->Text; TbNewStud->FieldByName("year_b")->AsDateTime=DateOf(DTBirth->Date); TbNewStud->FieldByName("sex")->AsString=RadioGroup1->ItemIndex==0?"м":"ж"; if((EFam->Text=="")||(ENam->Text=="")||(RadioGroup1->ItemIndex==-1)) { TbNewStud->Cancel(); ShowMessage("Введены не все поля!"); } else { TbNewStud->Post(); ShowMessage("Информация успешно введена!"); LoadStud(); EFam->Text=""; ENam->Text=""; RadioGroup1->ItemIndex=-1; } TbNewStud->Close(); }
В начале НД устанавливается в состояние dsBrowse, потом переводится в состояние dsInsert. После этого новой записи присваиваются значения, введенные пользователем. Если в группе радиокнопок выбран первый элемент, то свойство ItemIndex равно 0, если второй, то равно 1. В 6 строке программного кода используется тернарный оператор. Потом условный оператор проверяет все ли поля заполнил пользователь. Если не все, то ввод новой записи отменяется и выводится соответствующее сообщение. Если же всё нормально, то запись фиксируется в БД, выводится сообщение, все поля очищаются и обновляется список фамилий студентов. По аналогии можно написать программный код для кнопки «Ввести новый предмет»: void __fastcall TFNewInfo::BNewPredClick(TObject *Sender) { TbNewPred->Open(); TbNewPred->Insert(); TbNewPred->FieldByName("name_predmet")->AsString=EPred->Text; if(EPred->Text=="") { TbNewPred->Cancel(); ShowMessage("Введены не все поля!"); } else { TbNewPred->Post(); ShowMessage("Информация успешно введена!"); LoadPred(); EPred->Text=""; } TbNewPred->Close(); }
Ввод информации в таблицу ocenki отличается от других таблиц. Дело в том, что пользователь выбирает из выпадающих списков фамилии и предметы, а в таблицу БД должны заноситься уникальные номера этих фамилий и предметов. Поэтому в программе надо как-то предусмотреть соответствие текстовой информации уникальным номерам. Способов может быть несколько. В данной программе будет предусмотрено 2 способа. Первый подразумевает создание массива «соответствия», второй – использование поиска по набору данных. Первый способ будем использовать для списка студентов, второй – для списка предметов. Создадим в закрытом разделе класса двумерный массив: private: void LoadStud(); void LoadPred(); AnsiString MasStud[50][2]; массив MasStud строкового типа состоит из 50ти строк и двух столбцов. В первый столбец будем заносить фамилию студента, во второй – его уникальный номер. Формировать данный массив надо в тот же момент, что и выпадающий список. Поэтому внесите изменения в функцию LoadStud(), чтобы она соответствовала коду: void TFNewInfo::LoadStud() { int i=0; FShow->ADOTbFam->Active=false; FShow->ADOTbFam->Active=true; FShow->ADOTbFam->First(); CBStudExam->Items->Clear(); while(!FShow->ADOTbFam->Eof) { CBStudExam->Items->Add(FShow->ADOTbFamfam_student->Value+" "+FShow->ADOTbFamname_student->Value); MasStud[i][0]=FShow->ADOTbFamfam_student->Value+" "+FShow->ADOTbFamname_student->Value; MasStud[i][1]=FShow->ADOTbFamid_student->AsString; i++; FShow->ADOTbFam->Next(); } FShow->ADOTbFam->First(); } Теперь найти уникальный номер студента по его фамилии можно используя программный код: for (i=0; i < 50; i++) { if(MasStud[i][0]==CBStudExam->Text) break; } ... MasStud[i][1]//используем по надобности уникальный номер Внутри цикла происходит перебор фамилий, пока не будет найдено совпадение. При совпадении происходит выход из цикла с сохранением значения переменной-параметра, которая и соответствует искомому элементу. У этого способа установления уникального номера есть ряд недостатков. Во-первых, если студентов меньше 50, то имеет место неэффективное использование памяти. Во-вторых, если студентов больше 50, то программа не будет работать корректно и придется увеличивать размер массива, что опять же приведет к неэффективному использованию памяти. Повысить эффективность для этих двух пунктов можно путем использования динамических массивов, но тогда усложнится программный код. В-третьих, поиск по массиву нельзя назвать эффективным. Т.е. при достаточно большом количестве элементов цикла, время поиска увеличится. Чтобы повысить в этом случае эффективность можно отсортировать массив. В-четвертых, введенное пользователем значение может не найтись в исходном массиве. Т.к. в нашем примере пользователь выбирает значение из заранее сформированного списка, то наличие в списке «недопустимой» фамилии невозможно. Теперь продемонстрируем на списке предметов использование поиска по набору данных. Для этого можно использовать один из методов: SetKey, FindKey, Lookup и Locate. Наиболее универсальным является метод Locate, т.к. он применим к любым наборам данных. Метод объявлен следующим образом: bool __fastcall Locate(const System::AnsiString KeyFields, const System::Variant SKeyValues, TLocateOptions Options); В качестве первого параметра KeyFields передается строка, содержащая список ключевых полей. В качестве второго параметра передается KeyValues – массив ключевых значений. А третий параметр Options является множеством опций, элементами которого могут быть loCaseInsensitive – нечувствительность поиска к регистру, в котором введены символы, и loPartialKey – допустимость частичного совпадения. Метод возвращает false, если искомая запись не найдена. Метод Locate ищет первую запись, удовлетворяющую критерию поиска, и если такая запись найдена, делает ее текущей. Метод применяется к НД. Поэтому нужно создавать под эти цели отдельный компонент или использовать существующий. В нашем случае можно использовать компонент TbNewPred, т.к. при вводе данных в таблицу ocenki он никак не задействован. Тогда строчка: TbNewPred->Locate("name_predmet",CBPredExam->Text,SearchOptions<<loPartialKey<<loCaseInsensitive); будет искать в таблице predmet в поле name_predmet текст введенный (выбранный) в компоненте CBPredExam. Если такая запись будет найдена, то эта запись будет сделана текущей и можно будет получить уникальный номер предмета стандартным способом. В связи со всем сказанным, обработка нажатия кнопки «Ввести новую оценку» должна выглядеть следующим образом: void __fastcall TFNewInfo::BNewOcenClick(TObject *Sender) { TbNewOcen->Open(); if((CBStudExam->ItemIndex==-1)||(CBPredExam->ItemIndex==-1)||(CBOcen->ItemIndex==-1)) { ShowMessage("Введены не все поля!"); } else { int i; TLocateOptions SearchOptions; TbNewOcen->Insert(); for (i=0; i < 50; i++) { if(MasStud[i][0]==CBStudExam->Text) break; } TbNewOcen->FieldByName("id_student")->AsString=MasStud[i][1]; TbNewPred->Open(); TbNewPred->Locate("name_predmet",CBPredExam->Text,SearchOptions<<loPartialKey<<loCaseInsensitive); TbNewOcen->FieldByName("id_predmet")->AsString=TbNewPred->FieldByName("id_predmet")->AsString; TbNewOcen->FieldByName("data_ocenka")->AsDateTime=DateOf(DTExam->Date); TbNewOcen->FieldByName("ocenka")->AsString=CBOcen->Text; TbNewOcen->Post(); ShowMessage("Информация успешно введена!"); CBStudExam->ItemIndex=-1; CBStudExam->Text="студенты"; CBPredExam->ItemIndex=-1; CBPredExam->Text="предметы"; CBOcen->ItemIndex=-1; CBOcen->Text="оценки"; } TbNewOcen->Open(); }
У обоих описанных выше способов есть единый недостаток: если в БД заведены полные тезки, то при поиске фамилии результатом будет уникальный номер одного из них, что является логической ошибкой. Решение этой проблемы выходит за рамки данной лабораторной работы.
Дата добавления: 2015-05-09; Просмотров: 391; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |