Студопедия

КАТЕГОРИИ:


Архитектура-(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 состояний:

dsInactive НД закрыт.
dsBrowse Состояние по умолчанию для открытого НД. Показывает, что записи просматриваются, но в данный момент не изменяются.
dsEdit НД находится в состоянии редактирования текущей записи (после явно или неявно вызванного метода Edit).
dsInsert НД находится в состоянии добавления новой записи (после явно или неявно вызванного метода Insert или Append).
dsSetKey НД находится в состоянии поиска записи по критерию, заданному методами FindKey, GotoKey, FindNearest или GotoNearest. По окончании поиска НД переходит в состояние dsBrowse.
dsCalcFields Выполняется установление значений вычисляемых полей (по алгоритму, заданному в обработчике события OnCalcFields). В данном режиме изменения в НД вноситься не могут. После выхода из режима НД переходит в предыдущее состояние.
dsFilter Обрабатывается фильтрация записей в НД при свойстве Filtered, установленном в true. Имеет место текущий вызов события OnFilterRecord для определения того, удовлетворяет ли текущая запись условию фильтрации, описанному в обработчике данного события. После выполнения события OnFilterRecord НД переводится в состояние dsBrowse.

Рассмотрим методы, которые могут переводить БД из одного состояния в другое.

• 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; Просмотров: 385; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.009 сек.