KAN`ский блог

Мысли вслух…

  • Июл
    14

    Справочник предназначен для ввода, отображения и редактирования данных хранимым в качестве таблиц.

     

    Состоит из одной двухстраничной формы представленной на рисунке 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 = :P ERIODEDNSDATE,

          PERIODEDNSTYPE = :P ERIODEDNSTYPE

      WHERE PERIODEDNSID = :P ERIODEDNSID;

      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 :P RIKAZVIDPRM,:PRIKAZVIDTEMP

      DO

      BEGIN

        SUSPEND;

      END

    END

    Комментарии отключены