4.3.3. Форма Street – справочник улиц

 

Мы перешли к созданию многопользовательских форм. Этот раздел поможет вам пройти через все этапы создания такой формы. На конкретном примере рассмотрим последствия применения буферизации, обработку ошибок и сообщения пользователю при выбранном типе буферизации. Самыми распространенными операциями в многопользовательских формах являются Add (Добавление), Edit (Редактирование) и Delete (Удаление). Мно­гопользовательские формы, которые включают буферизацию, должны иметь дело с каждой из этих операций.

Добавление требует наименьших усилий. Если при включенной буфериза­ции пользователь добавляет строку, Visual FoxPro помещает ее в буфер, и никто другой не может редактировать эту строку до обновления таблицы. Таким образом, конфликта между пользователями не возникнет.

На этапе редактирования при оптимистической буферизации конфликты могут возникать, если один из пользователей пытается редактировать и обновлять строку в то время, когда ее уже редактирует кто-то другой. Подчеркну, что столкновения такого рода ве­роятны только при оптимистической буферизации, но не при пессимистической. При подобном конфликте Visual FoxPro позволяет решить вопрос пользователю, кото­рый обновляет строку: Visual FoxPro спрашивает у него, записать ли строку поверх или пользователь отредактирует ее заново.

Конфликт, который возникает при удалении, является несколько более сложным. Возможно, хотя и маловероятно, что два пользователя захотят уда­лить одну и ту же строку в одно и то же время. Поскольку они оба хотят совер­шить одинаковое действие, это проблемы не составляет. Однако не исключено, что один из пользователей попытается удалить строку, которую другой в это время редактирует. Поэтому лучше всего задать в процедуре, отвечающей за удаление, следующую функцию: отследить тот факт, что другой пользователь работает над строкой, и если это так, не выполнять удаления.

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

 


В окружение данных формы добавлена одна таблица – Street. Набор полей которой представлен в табл. 2.1. Поле со списком List1 привязано к трем полям Street, Name и Sign. Изучите внимательно тексты процедур, приведенных ниже. Надеюсь, что достаточное количество комментариев к ним, ответит на все ваши вопросы.

 

Текст события Activate второй страницы формы:

 

* Если форма в режиме просмотра

IF This.Caption=[Просмотр]

   * Гасим кнопку сохранить

   This.Command2.Enabled=.F.

   * Делаем недоступными поля одной записи в таблице Street

   This.TxtStreet.Enabled=.F.   && Номер улицы

   This.TxtName.Enabled=  .F.   && Название улицы

   This.Combo1.Enabled=   .F.   && Признак адреса

   This.ChkFirst.Enabled= .F.   && Порядок следования

ENDIF

* Работаем с таблицей Street

SELECT STREET

* Перерисовать вторую страницу формы

This.refresh

 

Текст события Click кнопки Добавить:

 

Select Street

=CURSORSETPROP("Buffering",3)

* В памяти компьютера создается буфер строки

* Все изменения  заносятся пока только в буфер

* 3 - буферизация строки. Блокировка оптимистическая

* Запись блокируется только на время записи ее на диск

* Добавляем пустую запись (в данном случае - в буфер)

APPEND BLANK

* Делаем активной вторую страницу формы

ThisForm.PageFrame1.ActivePage=2                   

* Первую страницу делаем недоступной

ThisForm.PageFrame1.page1.Enabled=.F.              

* Меняем заголовок второй страницы Просмотр на Добавление

ThisForm.PageFrame1.page2.Caption=[Добавление]     

* Заменяем кнопку Выход на Отказ

ThisForm.PageFrame1.page2.Command1.Caption=[Отказ] 

* Делаем недоступной кнопку Удалить

ThisForm.PageFrame1.page2.Command3.Enabled=.F.     

* Делаем недоступной кнопку "Исправить"

ThisForm.PageFrame1.page2.Command4.Enabled=.F.

* Кнопку сохранить делаем доступной     

ThisForm.PageFrame1.page2.Command2.Enabled=.T.     

ThisForm.PageFrame1.page2.Label2.Caption=[Буферизация включена]

* Делаем доступными поля одной записи

ThisForm.PageFrame1.page2.TxtStreet.Enabled=.T.

ThisForm.PageFrame1.page2.TxtName.Enabled=  .T.

ThisForm.PageFrame1.page2.Combo1.Enabled=   .T.

ThisForm.PageFrame1.page2.ChkFirst.Enabled= .T.

* Устанавливаем курсор на поле "Номер"

ThisForm.PageFrame1.page2.txtStreet.SetFocus

 

Текст события Click кнопки Исправить:

 

SELECT Street

=CURSORSETPROP("Buffering",3)

* В памяти компьютера создается буфер строки

* Все изменения  заносятся пока только в буфер

* 3 - буферизация строки. Блокировка оптимистическая

* Запись блокируется только на время записи ее на диск

* Первую страницу делаем недоступной

ThisForm.PageFrame1.page1.Enabled=.F.             

* Меняем заголовок второй страницы Просмотр на Корректировка

ThisForm.PageFrame1.page2.Caption=[Корректировка] 

* Заменяем кнопку "Выход" на "Сброс"

ThisForm.PageFrame1.page2.Command1.Caption=[Сброс]

* Делаем доступной кнопку "Сохранить"

ThisForm.PageFrame1.page2.Command2.Enabled=.T.    

&& Делаем недоступной кнопку "Удалить"

ThisForm.PageFrame1.page2.Command3.Enabled=.F.    

ThisForm.PageFrame1.page2.Label2.Caption=[Буферизация включена]

* Делаем доступными поля одной записи

ThisForm.PageFrame1.page2.TxtStreet.Enabled=.T.

ThisForm.PageFrame1.page2.TxtName.Enabled=  .T.

ThisForm.PageFrame1.page2.Combo1.Enabled=   .T.

ThisForm.PageFrame1.page2.ChkFirst.Enabled= .T.

 

Текст события Click кнопки Удалить:

 

InMsgResult=MESSAGEBOX('Действительно хотите удалить?',;

            52,'Удаление')

* Вывод информационного окна с заголовком "Удаление"

* Текст в окне 'Действительно хотите удалить?'

* 52 = 4+48+0

* 4 - в информационном окне кнопки "Да" и "Нет"

* 48 - картинка восклицательного знака

* 0 - по умолчанию кнопка "Да"

IF InMsgResult=6   && Если выбрана кнопка "Да"

   SELECT STREET

   DELETE      && Удаление

   GOTO TOP    && Переход к первой записи

   * Делаем активной первую страницу формы

   ThisForm.PageFrame1.ActivePage=1

   * Обновление первой страницы формы

   ThisForm.PageFrame1.Page1.Refresh

   * Делаем активным поле со списком первой страницы

   ThisForm.PageFrame1.Page1.List1.SetFocus

   * Обновление поля со списком

   ThisForm.PageFrame1.Page1.List1.Refresh

ENDIF

 

Текст события Click кнопки Сохранить:

 

* Проверка "Все поля записи должны быть заполнены"

* Номер улицы

IF EMPTY(Street.Street)=.T.

   =MESSAGEBOX('Вы забыли ввести номер улицы!',48,'Ошибка!')

   ThisForm.PageFrame1.Page2.TxtStreet.Setfocus

   RETURN

ENDIF

* Название улицы

IF EMPTY(Street.Name)=.T.

   =MESSAGEBOX('Вы забыли ввести название улицы!',48,'Ошибка!')

   ThisForm.PageFrame1.Page2.TxtName.Setfocus

   RETURN

ENDIF

* Признак адреса

IF EMPTY(Street.Sign)=.T.

   =MESSAGEBOX('Вы забыли ввести признак адреса!',48,'Ошибка!')

   ThisForm.PageFrame1.Page2.Combo1.Setfocus

   RETURN

ENDIF

=TABLEUPDATE()  && Сброс из буфера в таблицу

=CURSORSETPROP("Buffering",1) && Буферизация выключена

ThisForm.PageFrame1.page1.Enabled=.T.

ThisForm.PageFrame1.page2.Caption=[Просмотр]

ThisForm.PageFrame1.page2.Command1.Caption=[Выход]

* Перечисленные ниже объекты доступны

ThisForm.PageFrame1.page2.Command3.Enabled= .T.

ThisForm.PageFrame1.page2.Command4.Enabled= .T.

ThisForm.PageFrame1.page2.TxtStreet.Enabled=.T.

ThisForm.PageFrame1.page2.TxtName.Enabled=  .T.

ThisForm.PageFrame1.page2.Combo1.Enabled=   .T.

ThisForm.PageFrame1.page2.ChkFirst.Enabled= .T.

* Убираем надпись "Буферизация выключена"

ThisForm.PageFrame1.page2.Label2.Caption=[]

SELECT Street

GOTO TOP

* Активна первая страница формы

ThisForm.PageFrame1.ActivePage=1

* Перерисовать первую страницу формы

ThisForm.PageFrame1.Page1.Refresh

* Сделать активным поле со списком

ThisForm.PageFrame1.Page1.List1.SetFocus

* Перерисовать поле со списком

ThisForm.PageFrame1.Page1.List1.Refresh           

 

Текст события Destroy формы Street:

 

DO CASE

   CASE ThisForm.PageFrame1.page2.Command1.Caption=[Отказ]

        * Пользователь передумал заносить новую улицу

        SELECT Street

        DELETE            && Удаление изменений в буфере

        =TABLEREVERT()    && Отказ от записи на диск

        ThisForm.Release  && Закрытие формы

 

   CASE ThisForm.PageFrame1.page2.Command1.Caption=[Сброс]

        * Пользователь передумал выполнить корректировку

        SELECT STREET

        =TABLEREVERT()    && Отказ от записи на диск

        ThisForm.Release  && Закрытие формы

 

   CASE ThisForm.PageFrame1.page2.Command1.Caption=[Выход]

        ThisForm.Release

ENDCASE       

 

Обратите внимание на надпись Label2 второй страницы формы. Она используется для индикации состояния буферизации. При создании формы ее свойство Caption представляет собой строку нулевой длины. В процессе работы оно может меняться на Буферизация включена и Буферизация выключена.

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

 


 

Рассмотрим процесс обработки ошибок, возникающих при одновременной корректировке одной записи несколькими пользователями в таблице Street. В этом случае методика, предложенная в приведенном выше коде, даст ошибку с номером 1585. Ее следует перехватить и обработать. Фрагмент обработки имеет вид:

 

* Обработка ошибки с кодом 1585

lnMsgResult=MESSAGEBOX('Пока Вы занимались корректировкой, '+;

          'эту запись уже кто-то изменил. '+;

          'Записать Ваши изменения поверх?',20,' Внимание!')

IF lnMsgResult=6      && Кнопка Да

   * Сбросить буфер на диск

   =TABLEUPDATE(.T.,.T.)

ELSE

   * Отказ от записи на диск

   =TABLEREVERT()

ENDIF

 

Процедура перехвата носит название ErrorHnd и находится в процедурном файле FileProc. Полный текст этого файла приведен в приложении.