-
Июл14
Создание диалоговой формы «Справочник-редактор»
Filed under: Без рубрики;Справочник предназначен для ввода, отображения и редактирования данных хранимым в качестве таблиц.
Состоит из одной двухстраничной формы представленной на рисунке 1 и 2.
При этом первая страница-закладка (рисунок 1) предназначена для отображения и выбора данных в виде компактного списка, а вторая (рисунок 2) является редактором и полностью отображает все поля таблицы, которая является источником данных. Следует избегать ненужных и непонятных цифр, а отображать данные в привычной для пользователя форме, если возможно то в графической.
рис.1.
рис.2.
Как видно на рисунке 1, первая закладка состоит из не изменяемой части — кнопок управления («Первая», «Последняя» «Создать», «Редактировать», «Выбрать и закрыть») и части списка, в которой следует отображать только минимально необходимый набор полей, одно — два.
При выводе формы на экран (событие Form1OnShow) должна выполнится следующая процедура:
procedure TForm1.FormShow(Sender: TObject);
begin
DBGrid1.SetFocus; // фокус на список
PSor:=’’; // Данная переменная определяет сортировку , о ней позднее…
PageControl1.ActivePage:=TabSheet1; //Сделать видимой закладку 1.
SQL4PRIKAZ; // Подготовить запрос
end;
При этом процедура SQL4PRIKAZ имеет следующий вид:
procedure TForm1.SQL4PRIKAZ;
Var TempBool: Boolean;
begin
case VarInt of
01001: // Выбор запроса в зависимости от значения переменной VarInt
begin
…
Query1.SQL.Add(SQL1+ PSor);
…
end;
else // По умолчанию все записи.
begin
…
Query1.SQL.Add(SQLx+ PSor);
…
end;
end;
TempBool:= ((Query1.IsEmpty) or not(Query1.Active)); // Изменяем переменную в зависимости от наличия ошибок и данных
If TempBool
then ShowMessage (‘Нет данных для отображения!’)
else
Begin
DataSource1.DataSet:=Query1; // Ассоциируем данные
DBGrid1.DataSource:=DataSource1; // и средства отображения
End;
DBGrid1.Visible:=not( TempBool ); // Показывает список, только если все в порядке
PageControl1.Enable:= not( TempBool );// делаем доступными список и редактор
End;
Для сортировка отображаемых данных, возможно использовать обработчик события на клик по заголовку списка, в форме должна быть определена переменная хранящая порядок сортировки в примере это PSor, кроме этого в главном модуле желательно определить следующие константы DESC = ‘ DESC’; ORDERBY =’ ORDER BY ‘; для некоторой экономии памяти
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var TempStr : string;
begin
PID:=Query1.Fieldbyname(‘PID’).AsString; // запомним где находились…
TempStr:=PSor; //запомним прежней фильтр
PSor:=ORDERBY + Column.FieldName; // создаем новый фильтр
if TempStr=PSor then PSor:=PSor+DESC; // если фильтр не изменился, то сортируем в обратном порядке..
SQL4PRIKAZ; // выполняем запрос
GoToLastPos; // вернемся на прежнее место…
end;
Иногда для выбора данных из справочника удобно использовать следующую возможность, по нажатию клавиш на клавиатуре курсор переносится на запись содержащую введенную последовать символов, для этого на форме нам понадобится таймер (срабатывает через 3 секунды), а также мы будем обрабатывать события нажатия клавиши на списке отображения. Нам также понадобится переменная для хранения введенных символов в примере это PREPODSel:
procedure TForm1.Timer1Timer(Sender: TObject);// срабатывание таймера
begin
Timer1.Enabled:=False; // останавливаем таймер
PREPODSel:=»; // очищаем переменную
Caption:=’Сотрудники’; //очищаем заголовок формы
end;
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char); // нажатие кнопок на списке
begin
Timer1.Enabled:=False; // перезапускаем таймер
Timer1.Enabled:=True;
PREPODSel:=PREPODSel+Key; // увеличиваем строку символов
Query1.Locate(‘PREPODFIO‘, PREPODSel, [loPartialKey]); // пытаемся перейти на ближайшую похожую запись
Caption:=’Сотрудники — ‘ + PREPODSel; // изменяем заголовок формы, чтобы то, что мы наводили
end;
При закрытии формы справочника, необходимо вернуть данные для этого на Form1OnClose вешаем следующий обработчик:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
try
ValueN:= Query1.FieldByName(‘Name’).AsString; // «Человеческое обозначение»
Value:= Query1.FieldByName(‘ID’).AsString; // «Обозначение машины»
ValueDate:= Query1.FieldByName(‘Date’).AsString; // Если нужно то и дату
except
ValueN:= ‘-=НЕТ ДАННЫХ=-‘; // В случаи сбоя оговоренные «Пустые данные»
Value:= ‘-1’;
ValueDate:= DateToStr(now);
end;
end;
Переменные ValueXXXX : String; должны быть определены в модуле данных, для передачи данных между формами, также как и VarIntXXXX : Integer;
Вторая закладка, изображенная на рисунке 2, более «наворочена» и состоит из нескольких видов объектов:
1. Поля ввода (например «ФИО»), в данное поле возможно вводить данные в одну строчку, при этом стоит ограничить максимально возможное количество символов которое возможно ввести в данное поле (Edit1.MaxLenght:=50);
2. Поля выбора из списка (например «Уч. степень»), в данное поле нельзя непосредственно ввести данные (Edit2.ReadOnly:=True), данные в данное поле вводятся путем выбора из списка для этого на событие Edit2OnClick вешаем такой обработчик:
procedure TForm1.Edit2Click(Sender: TObject);
Var TVarInt, TVarInt1 : integer;
begin
TVarInt := VarInt; // Запоминаем старые переменные
TVarInt1:= TVarInt1;
VarInt:=00201; // Передача данных в вызываемую форму для определения вида SQL запроса
form2.showmodal; // Вызов подчиненного справочника
if Value=’-1′ // Проверяем наличие пустых данных
then ShowMessage(‘Внимание! Ошибка передачи данных’)
else
Begin
edit2.text:=ValueN; // Запись в поле понятных человеку данных
ust:=Value; //Запись в переменную данных понятных для базы данных, переменная должна быть определена заранее, после слова implementation.
End;
VarInt:= TVarInt; // Восстанавливаем переменные
VarInt1:= TVarInt1;
SQL4PRIKAZ; // Освежаем старый запрос
GoToLastPos; // Возвращаем указатель на прежнюю запись
end;
3. Группы кнопочного выбора «RadioButton» (например «Пол»);
4. Поля ввода «Memo» (например «Адрес») для ввода данных в несколько строк, тут как и в предыдущем случаи без особенностей;
5. Кнопки с ассоциированным редактором (например «Темы ДР») для ввода большого количества данных, которые не удобно показывать при пролистывании данных;
Создадим еще одну форму простого редактора (состоит из MEMO и двух кнопок «ОК», «Отменить»), а вызывать его будем через следующую процедуру:
procedure BLOBview (filed: string); // в качестве переменной передаем имя поля из которого будем брать данные
begin
Query2.Close; // Выбираем из Базы данных только редактируемое поле
Query2.SQL.Clear;
Query2.SQL.Add(‘Select ‘+filed+’ FROM PREPOD’);
Query2.SQL.Add(‘WHERE PREPODID=’+ PREPODID);
Query2.Open;
IF Query1.IsEmpty // Заполняем редактор
THEN form3.Memo1.Lines.Clear
ELSE form3.Memo1.Text:=Query1.FieldBYNAME(filed).AsString;
Form3.showmodal; //Показываем редактор
If MR=mrOk then // Если в редакторе нажали «ОК»
begin
IF form3.Memo1.Text<>Query1.FieldBYNAME(filed).AsString //Если изменили что—то…
THEN
begin
Query2.Close; // обновляем поле
Query2.SQL.Clear;
Query2.SQL.Add( ‘Update PREPOD’ );
Query2.SQL.Add( ‘set ‘+filed+’ =:blobfl’ );
Query2.SQL.Add( ‘Where REPODID=’+PREPODID );
Query2.ParamByName(‘blobfl’).AsString:=form3.Memo1.Text;
Query2.ExecSQL;
Transaction1.CommitRetaining;
end;
end;
end;
6. Кнопки с ассоциированным списком (например «Приказы»), обработчик точно такой же, как и для Edit2OnClick;
7. Списки (например «Читает следующие дисциплины»), тоже самое, что и описанная форма целиком.
Стоит также завести процедуру, которая будет обновлять содержимое (второй) закладки редактора при изменении позиции курсора в отображаемой таблице:
procedure ReFill;
begin
PRIKAZID:=Query1.FieldByName(‘PRIKAZID‘).AsString; //изменяем номер редактируемой записи
TempQuery(Query2, FORMAT(‘SELECT * FROM PRIKAZ_SEL1(%s)’,[ PRIKAZID ])); //выполнение запроса выбора одной полной записи из базы данных, PRIKAZ_SEL1 это хранимая процедура на SQL сервере
Edit1.Text:=Query2.FieldByName(‘PRIKAZNOM’).AsString; // присвоение поля ввода (п.1.)
Memo1.Text:=Query2.FieldByName(‘PRIKAZNM’).AsString; //присвоение MEMO (п.4.)
Edit3.Text:=Query2.FieldByName(‘PRIKAZVIDNM‘).AsString; //присвоение поля выбора из списка в виде понятным человеку(п.2.)
PRIKAZVID:=Query2.FieldByName(‘PRIKAZVID’).AsString; // в виде для машины
TempQuery(Query2, FORMAT(‘SELECT * FROM PRIKAZ_ADV(%s)’,[ PRIKAZID ])); // запрос заполнения списка (п.7.)
end;
Дважды была использована следующая функция:
procedure TempQuery(ADateSet:TQuery ; SQL:String ); // Данная функция просто сокращает повторяющиеся операторы.
begin
if ADateSet.Active then ADateSet.Close;
ADateSet.SQL.Clear;
ADateSet.SQL.Add(SQL);
ADateSet.Open;
end;
Теперь обработка нажатия кнопок управления («первый», «последний», «предыдущий», «следующий»):
procedure TForm1.BitBtnNClick(Sender: TObject);
begin
Query1.{First, Last, Prior, Next}; //Просто подставляем нужное слово
ReFill
end;
Добавление новой записи:
procedure TForm1.BitBtn6Click(Sender: TObject);
begin
StoredProc1.StoredProcName:=’PREPOD_INS’; // Опять процедура сервера
StoredProc1.ExecProc;
Transaction1.CommitRetaining;
PREPODId:= StoredProc1.ParamByName(‘ PREPODId ‘).AsString; //Которая возражает один параметр – новый индекс
SQL4PRIKAZ; //Обновляем запрос
GoToLastPos; //Переходим на новый элемент
ReFill; //перезаполняем редактор
PageControl1.ActivePage:=TabSheet2;
end;
procedure GoToLastPos; //Данная процедура перемещает указатель на указанную запись
begin
Query1.Locate(‘PREPODID’,PREPODID, [loCaseInsensitive]);
end;
По нажатию кнопки «Редактировать» нужно просто выполнить PageControl1.ActivePage:=TabSheet2;
При ручном выборе второй закладки (редактора) должно выполняться просто REFILL.
Обновление измененной записи будет выглядеть так:
procedure TForm1.BitBtn5Click(Sender: TObject);
begin
StoredProc1.StoredProcName:=’PREPOD_UPD’; // Опять процедура на сервере
StoredProc1.Prepare; //Нужно «Предупредить» процедуру о параметрах
if RadioButton2.Checked //Это сохранение группы кнопочного выбора «RadioButton» (п.3.)
then StoredProc1.ParamByName(‘PREPODPOL’).AsString := ‘0’
else StoredProc1.ParamByName(‘PREPODPOL’).AsString := ‘1’;
StoredProc1.ParamByName(‘PREPODID’).AsString := PREPODID; //это сохранение поля выбора (п.2)
StoredProc1.ParamByName(‘PREPODFIO’).AsString := edit1.Text; // а дальше все как обычно
StoredProc1.ParamByName(‘PREPODDR’).AsDateTime := DateTimePicker2.DateTime;
StoredProc1.ParamByName(‘PREPODADR’).AsString:= memo2.Text;
StoredProc1.ExecProc; // Исполняем процедуру
Transaction1.CommitRetaining;
StoredProc1.UnPrepare; //Снимаем приготовление
SQL4PRIKAZ;
GoToLastPos
end;
Пример процедуры добавления записи:
CREATE PROCEDURE PERIODEDNS_INS (
PERIODEDNSDATE TIMESTAMP,
PERIODEDNSTYPE INTEGER)
AS
DECLARE VARIABLE PERIODEDNSID INTEGER;
BEGIN
select MAX(PERIODEDNSID) FROM PERIODEDNS INTO :PERIODEDNSID; // можно конечно использовать триггер, но иногда нужно знать какой именно номер мы получили…
if (PERIODEDNSID is null) then PERIODEDNSID=0;
PERIODEDNSID=PERIODEDNSID+1;
INSERT INTO PERIODEDNS (PERIODEDNSID,PERIODEDNSDATE,PERIODEDNSTYPE)
VALUES (:PERIODEDNSID,:PERIODEDNSDATE,:PERIODEDNSTYPE);
END
Пример процедуры обновления:
CREATE PROCEDURE PERIODEDNS_UP (
PERIODEDNSID INTEGER,
PERIODEDNSDATE TIMESTAMP,
PERIODEDNSTYPE INTEGER)
AS
BEGIN
UPDATE PERIODEDNS
SET
PERIODEDNSDATE = :PERIODEDNSDATE,
PERIODEDNSTYPE = :PERIODEDNSTYPE
WHERE PERIODEDNSID = :PERIODEDNSID;
END
Пример процедуры выбора одной строки:
CREATE PROCEDURE PRIKAZVID_SEL1 (
PRIKAZVIDID INTEGER)
RETURNS (
PRIKAZVIDPRM BLOB sub_type 0 segment size 80,
PRIKAZVIDTEMP BLOB sub_type 0 segment size 80)
AS
BEGIN
FOR SELECT PRIKAZVIDPRM,PRIKAZVIDTEMP
FROM PRIKAZVID
WHERE PRIKAZVIDID=:PRIKAZVIDID
INTO :PRIKAZVIDPRM,:PRIKAZVIDTEMP
DO
BEGIN
SUSPEND;
END
END