Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / FoxPro, Visual FoxPro Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 [2] 3   вперед  Ctrl      все
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
Дело в том, что у формы должен быть свой собственный метод, который обеспечивает коррекное закрытие этой и именно этой формы. Ну, например, при закрытии некоторой формы возникает дополнительный запрос на какие-либо дополнительные модификации.

При этом, есть различие "штатного" закрытия (самим пользователем) и "аварийного" (по нажатию на крестик в правом верхнем углу приложения).

Лично у меня, вызов этого метода по закрытию формы происходит из штатного метода Form.QueryUnload.

Например, на форме есть кнопка "Выход" в событии Click() которой и прописано закрытие формы (после соответсвующих проверок дается команда ThisForm.Release()). Тогда в событии Form.QueryUnload() будет примерно такой код

*Form.QueryUnload()
NODEFAULT
ThisForm.CmdExit.Click()

Соответственно, метод по закрытию всех открытых форм заключается не в вызове события Release() форм, а в вызове события QueryUnload() которое и берет на себя всю работу по корректному закрытию формы.

При этом надо учитывать последовательность форм. Т.е. закрывать формы в "правильном" порядке. Начиная с самой последней. В коллекции _SCREEN.Forms() самая последняя открытая форма имеет индекс 1, предпоследняя - 2 и т.д. Т.е. закрывать надо всегда 1 форму, поскольку после закрытия первой формы индекс 1 получит та, которая была второй.

FOR lnI = 1 TO _SCREEN.FormCount
	* Индекс ВСЕГДА 1, а не значение счетчика
	_SCREEN.Forms(1).QueryUnload()
ENDFOR

Но в этом случае есть опасность зацикливания, если форма по каким-то причинам не может быть закрыта. Точнее, не зацикливания, а нескольких попыток закрытия только одной формы, не закрывая все остальные.

В общем, вот один из вариантов, который, впрочем, тоже ничего не гарантирует

* Данный метод предпринимает попытку закрыть ВСЕ формы текущего проект
* В случае успеха возвращает .T. и .F. в случае неудачи.

LOCAL IsDoing, loForm, lnHideForms, lnFormSet, lcOnError
*!* Для отладки
*!*	lcOnError = ON("ERROR")
*!*	ON ERROR *		&& подавляю выдачу сообщений об ошибках
IsDoing = .T.
lnHideForms = 0
lnFormSet = 0
DO WHILE _SCREEN.FormCount>m.lnHideForms AND m.IsDoing=.T.
	lnCount=_SCREEN.FormCount		&& запоминаю количество существующих форм
	loForm=_SCREEN.Forms(1+m.lnHideForms+m.lnFormSet)
	
	* В моих проектах закрытию ЛЮБОЙ формы можно вызвать из метода QueryUnload
	m.loForm.QueryUnload()

	* Если форма успешно удалилась, то переменная loForm должна принять значение NULL
	IF TYPE('m.loForm')='O' AND IsNull(m.loForm)=.F. 
		* Т.е. форма не удалилась
		IF loForm.Visible=.T.
			* Если форма не удалилась и осталась видимой - это значит
			* что в результате диалога с пользователем было решено прервать выход
			IsDoing=.F.
		ELSE
			* Это на случай существования FormSet, когда дочернии
			* формы не удаляются, а лишь делаются невидимыми
			DEACTIVATE WINDOW (m.loForm.Name)
			lnFormSet = m.lnFormSet + 1
		ENDIF
	ELSE
		lnFormSet = 0
		IF m.lnCount = _SCREEN.FormCount
			* т.е. это как раз тот случай, когда форма хотя и удалилась,
			* но осталась в памяти из-за не завершенного метода
			lnHideForms = m.lnHideForms+1
		ENDIF
	ENDIF

ENDDO

*!*	ON ERROR &lcOnError

RETURN (_SCREEN.FormCount=m.lnHideForms)
13 авг 08, 17:48    [6063729]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
ВладимирМ

спасибо большое за участие. Я попробовала сделать как Вы написали, но, к сожалению, все тоже самое: форма2 закрывается, проходит unload, а на форме1 нет. :(
14 авг 08, 09:36    [6065090]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
Может я не права, но мне вот еще что не понятно: ведь в последней форме (форма2) отрабатывает закрытие формы по всем правилам (т.е. release, unload), значит вводе как мы должны вернуться в метод откуда было открытие формы (например, клик по кнопке) и закончить его, а потом уже все остальные действия (если таковые имеются). Разве нет?
14 авг 08, 09:47    [6065141]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
AnnaSPB
Может я не права, но мне вот еще что не понятно: ведь в последней форме (форма2) отрабатывает закрытие формы по всем правилам (т.е. release, unload), значит вводе как мы должны вернуться в метод откуда было открытие формы (например, клик по кнопке) и закончить его, а потом уже все остальные действия (если таковые имеются). Разве нет?


FoxPro - это однопоточное приложение. Вернуться-то он должен. Весь вопрос в том КОГДА.

Он не может прервать выполнение текущей процедуры, чтобы обработать закрытие формы "по всем правилам". Т.е. завершение обработки клика кнопки произойдет только после того, как будет закончена процедура закрытия всех открытых форм. А к этому моменту эта форма уже может быть безнадежно испорчена попытками ее закрыть. И завершение события Click() кнопки уже ничего не исправит.

У нас есть программа (инструкция) соержащая примерно такую последовательность команд:

Инструкция 1
1. Закрыть форму 1
2. Закрыть Форму 2

Вот он ее "тупо" и выполняет. От начала и до конца. То, что после выполнения команды "Закрыть форму 1" теоретически должна выполнится еще одна инструкция вида

Инструкция 2
1. Завершить событие Click() кнопки на форме 2

Вовсе не означает, что "Инструкция 2" будет выполнена сразу после команды "Закрыть форму 1". Эта инструкция будет поставлена в очередь инструкций. В данном случае сразу за "Инструкцией 1". В результате получаем такой список:

Инструкция 1
1. Закрыть форму 1 (выполнено)
2. Закрыть Форму 2

Инструкция 2
1. Завершить событие Click() кнопки на форме 2

Получаем неразрешимое противоречие. В данный конкретный момент времени выполняется вторая команда Инструкции 1 (закрыть Форму 2), а в очереди процессов ждет своего часа еще одна инструкция на завершение метода этой закрываемой формы.

Хуже всего то, что FoxPro может "частично" закрыть Форму 2 в такой ситуации. Т.е. уничтожить часть объектов свойств и методов этой формы. И последующее выполнение Инструкции 2 уже ничего не рашает. Форма 2 оказывается в таком состоянии, что ее невозможно уничтожить уже никакими способами.

Именно поэтому, закрытие формы должно выполняться не через прямые команды ThisForm.Release(), а через методы, которые прежде, чем дать команду на закрытие проверят, а можно ли вообще закрыть форму.
14 авг 08, 11:36    [6065962]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
ВладимирМ

Да я в этом уже убедилась. Я пробовала сделать как Вы рекомендовали, через QueryUnload(), но получила тотже результат. Я уже просто и не знаю что можно с этим сделать!?! И вообще можно ли с этим как-то бороться?
14 авг 08, 11:47    [6066043]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
QueryUnload() - это один из вариантов. Смысл-то не в каком-то методе, а в его НАПОЛНЕНИИ. Что там внутри записано.

Как один из вариантов решения - запустить процесс самозакрытия форм через объекты-таймеры.

Т.е. на каждой форме есть объект-таймер. Который с некоторой периодичностью просматривает содержимое некой служебной таблички. Если в этой табличке выставлен некий флаг (значение поля), то этот таймер дает команду на закрытие данной, текущей формы. "По быстрому" это можно сделать не через поле таблицы, а через глобальную переменную. Хотя таблица рано или поздно все-равно понадобиться.

Если из метода формы вызывается модальная форма, то перед вызовом модальной формы этот таймер отключается и включается только после закрытия модальной формы. Ну, примерно так:

ThisForm.TmrAutoClose.Enabled = .F.
DO FORM ChildModalForm.scx
ThisForm.TmrAutoClose.Enabled = .T.

Объект TmrAutoClose - это как раз этот таймер автозакрытия.

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

Обработка выполняется через таймеры именно для того, чтобы все процессы по автозакрытию форм отработали в нужной последовательности. Чтобы не возникло проблем с очередями процессов.

Да, разумеется, выставление флага блокирует открытие новых форм.
14 авг 08, 12:03    [6066157]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
да это же УЖАС! В каждой форме писать обработку по таймеру, организация таблиц... а если форм в проекте десятки??? К тому же насколько я в курсе таймер "не очень хорошо" ладит с модальными формами, а в моем случае формы модальные. Замкнутый круг какой-то.
14 авг 08, 12:31    [6066384]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Анатолий Широков
Member

Откуда: Санкт-Петербург
Сообщений: 1319
AnnaSPB
да это же УЖАС! В каждой форме писать обработку по таймеру, организация таблиц... а если форм в проекте десятки??? К тому же насколько я в курсе таймер "не очень хорошо" ладит с модальными формами, а в моем случае формы модальные. Замкнутый круг какой-то.


Для этого надо наследовать свою форму от некоторого базового класса, в которую и поместить всю общую для всех форм функциональность.
14 авг 08, 12:40    [6066464]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
Попробовала закрыть формы с использованием таймеров.
На двух формах, последовательно вызываемых друг из друга поместила таймеры, которые следять за переменной lCloseFormAll, и если она равна true, закрывают форму.
На внешней кнопке такой код:
For x = _SCREEN.FORMCOUNT to 1 step -1
IF !(ALLTRIM(UPPER(_SCREEN.FORMS(x).NAME))=="BUTTONS")
lCloseFormAll = .T.
ENDIF
EndFor

* выполнение неких действий
...
...
...

Результаты аналогичные: первая форма закрывается, вторая нет.
В общем то это и логично, управление в первую форму не возвращается. Продолжают выполняться действия на внешней кнопке (при этом форма 1 не закрыта). А вот после выполнения всех действий на внешней кнопке, возвращается управление на форму 1, срабатывает таймер и форма закрывается.
Но задача стоит перед выполнением действий на форме предварительно закрыть ВСЕ открытые формы.
Посоветуйте пожалуйста как можно этого добиться?
14 авг 08, 14:26    [6067271]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
AnnaSPB
На внешней кнопке такой код

А кнопка где расположена? Если формы модальные, то на верхней форме должна быть, т.к. все остальное недоступно.
AnnaSPB
For x = _SCREEN.FORMCOUNT to 1 step -1
IF !(ALLTRIM(UPPER(_SCREEN.FORMS(x).NAME))=="BUTTONS")
lCloseFormAll = .T.
ENDIF
EndFor

* выполнение неких действий
...
...
...


Сделай таймер там же где кнопка. Для ожидания отработки остальных таймеров :)
Код раздели так:
proc Кнопка.Click()
lCloseFormAll = .T.
Timer.Interval = 10
return

proc Timer.Timer()
this.Interval = 0
For x = _SCREEN.FORMCOUNT to 1 step -1
   IF !(ALLTRIM(UPPER(_SCREEN.FORMS(x).NAME))=="BUTTONS")
      * Есть еще формы, ждем дальше
      this.Interval = 10
      return
   ENDIF
EndFor

* выполнение неких действий
...
...
...
14 авг 08, 14:49    [6067433]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
Если формы хоть по одной но закрываются, то можно одним таймером попробовать обойтись. Там же где и кнопка:
proc Кнопка.Click()
Timer.Interval = 10
return

proc Timer.Timer()
this.Interval = 0
llFormOpen = .F.
For x = _SCREEN.FORMCOUNT to 1 step -1
   IF !(ALLTRIM(UPPER(_SCREEN.FORMS(x).NAME))=="BUTTONS")
      * Есть еще формы, ждем дальше
      llFormOpen = .T.
      _SCREEN.FORMS(x).Hide()
      _SCREEN.FORMS(x).Release()
   ENDIF
EndFor

if llFormOpen
      this.Interval = 10
      return
endif
* выполнение неких действий
...
...
...
14 авг 08, 14:53    [6067456]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
кнопка находится не на форме, это тулбар с несколькими кнопками
14 авг 08, 14:56    [6067469]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
кнопка находится не на форме, это тулбар с несколькими кнопками
14 авг 08, 15:18    [6067654]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
Во-первых, таймеры должны быть привязаны к формам. Каждой отдельно взятой форме соответствует свой собственный таймер. Через классы это легко делается. Никакого ужаса.

Т.е. открытие каждой формы сопровождается запуском таймера, расположенного на этой форме.

Во-вторых, запуск процесса закрытия всех открытых форм сам по себе ничего не удаляет. Он только выставляет флаг - закрыть формы. Затем запускается таймер, который анализирует, во-первых, состояние флага (он может быть отменен в процессе закрытия какой-либо формы), а, во-вторых, количество открытых форм.

Другими словами, невозможно сделать процесс закрытия всех форм "одноразовым" . Т.е. дать команду и тут же все закроется. Необходимо периодически проверять процесс закрытия.

Выставили флаг и ждем. Через некоторое время проверям - есть флаг? Формы закрыты? Если флаг есть, а формы не закрыты, опять ждем. Через некоторое время опять проверяем - есть флаг? Формы закрыты? ...

И так до тех пор пока флаг не окажется сброшенным или все формы не окажутся закрытыми.
14 авг 08, 17:26    [6068592]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Galyamov Rinat
Member

Откуда:
Сообщений: 658

DimaT, а зачем каждый раз передергиваешь свойство таймера this.Interval = 10


Это лишнее.

PS для запуска таймера надо использовать его свойство enabled


Posted via ActualForum NNTP Server 1.4

14 авг 08, 18:02    [6068867]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
Посмотри простой пример во вложении. Я поставил интервал в 5 секунд. Запускаешь main.prg и открываешь несколько вложенных модальных форм. Для закрытия всех форм нажимаешь кнопку Close в ToolBar и ждешь 5..10 секунд пока не появится сообщение о том, что все формы закрыты.

К сообщению приложен файл (AutoCloseForms.rar - 6Kb) cкачать
14 авг 08, 18:27    [6068991]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
Galyamov Rinat

DimaT, а зачем каждый раз передергиваешь свойство таймера this.Interval = 10
Это лишнее.

PS для запуска таймера надо использовать его свойство enabled


Не знал что enabled у таймера есть и работает, при Interval = 0 таймер не работает. По большому счету оба способа запуска/остановки равнозначны - объем кода одинаковый.
14 авг 08, 18:53    [6069085]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
Попробовал с одним таймером на тулбаре. Вроде работает.
Только еще надо проверять лишние срабатывания таймера, а то полезный код может дважды отработать.

К сообщению приложен файл (AutoCloseForms.zip - 4Kb) cкачать
15 авг 08, 09:04    [6070172]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
спасибо большое всем за участие.

но, честно говоря, задача так до конча и не решена.
Как я уже не однократно писала, проблема в том, что помимо закрытия предыдущих форм, на этом тулбаре прописаны некие действия (это не кнопка закрыть), там может идти вызов какой-нибудь программы или формы и т.д. Так вот проблема заключается в том, что все формы кроме последней не МОГУТ быть закрыты пока не выполняться все действия на кнопке тулбара. А нужно перед выполнением этих действий сначало закрыть всё, что открыто к этому моменту, а потом выполнять некие действия.
Например, открываем форму1, из нее форму2 и кликаем по кнопке тулбара, на которой прописано закрытие всех открытых к этому моменту форм и открытие некой формы3. И получается, что форма2 (последняя из двух открытых) закрывается корректно, а форма1 не может быть закрыта, т.к. выполняется код на кнопке тулбара и мы не можем завершить клик, на котором прописано открытие формы2. Т.е. открывается форма3 (поверх формы1), там что-то делается и когда мы закрываем форму3, происходит unload формы3, далее завершение действий на клике в форме1 и unload формы1.
15 авг 08, 13:58    [6072179]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
AnnaSPB
но, честно говоря, задача так до конча и не решена.


Нами задача решена до конца и полностью :)

Внимательно перечитай что я и ВладимирМ предлагали и приложенные файлы позапускай.

Прилагаю еще один пример (запускать main.prg). Добавил MessageBox() в Unload() чтобы понятно было что нужный код выполнится ПОСЛЕ закрытия всех форм. Смотри на порядок мессаджбоксов.

К сообщению приложен файл (AutoCloseForms.zip - 4Kb) cкачать
15 авг 08, 14:26    [6072376]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
AnnaSPB
Member

Откуда: Санкт-Петербург
Сообщений: 38
Dima T

СПАСИБО! все понятно, это я уже туплю. работает все супер!

Спасибо большое :)
15 авг 08, 14:43    [6072503]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
MikhailB
Member

Откуда:
Сообщений: 2
Жалко что закончисля этот флейм, но хочется всетаки добавить свои пять копеек...


Эту проблему можно решить еще вот так, используя простые немодальные формы:

1.Запуская новую "модальную" форму устанавливаешь ей свойство AlwaysOnTop=.T., а у элементов запущеной до этого "модальной" формы ты просто выставляешь свойство Enabled=.F.
и выключаешь свойство формы AlwaysOnTop=.F.

2.Перед запуском новой "модальной" формы нужна процедурка, которая бы искала предыдущию "модальную" форму и запоминала бы куда-нибудь ее имя

3.Когда ты закрываешь текущую "модальную" форму, ты востанавливаешь для запомненной предыдущей "модальной" формы свойство AlwaysOnTop=.T.


Закрыть ты эти формы можешь в любое время простым скриптом

FOR i01=1 TO _SCREEN.FORMCOUNT
_SCREEN.FORMS(1).Release
next i01

Как все это реализовать уже дело техники...
3 сен 08, 15:52    [6142759]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
ВладимирМ
Member

Откуда: г. Москва
Сообщений: 7864
MikhailB

Вы бы сначала данную тему почитали. Проблема именно в том, что закрытие перебором массива _SCREEN.Forms для более чем 2 одновременно открытых модальных форм - не всегда работает.

Запоминать предыдущую форму нет никакой необходимости, поскольку индекс активной в данный момент формы автоматически устанавливается равным 1, а индексы всех прочих формы также автоматически "сдвигаются".

Другими словами, активная в данный момент модальная форма всегда будет иметь индекс 1, а та модальная форма из которой ее вызвали всегда будет иметь индекс 2 в массиве _SCREEN.Forms. Разумеется, если вызов происходит из событий формы, а не через пункты меню или ToolBar.

"Игры" с AlwaysOnTop в отношении модальных форм просто опасны. Вы можете получить "мертвое" зависание случайно вытащив на верх предыдущую форму. Переключится на активную модальную форму невозможно и закрыть вытащенную форму - тоже.
3 сен 08, 16:49    [6143233]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
MikhailB
Member

Откуда:
Сообщений: 2
Спасибо, тему прочитал и ничего противоречивого ей в своем посте не нашел.

Хочу только поправиться от вероятно возникшего недопонимания...

В моем предыдущем сообщении под "модальной" формой, имется в виду простая немодальная форма.
То есть при запуске новой формы которая должна быть якобы модальной, но таковой не является необходимо определить ей свойство AlwaysOnTop=.T., а у предыдущей "модальной" формы его сбросить AlwaysOnTop=.F. и установить Enabled=.F.

Для того чтобы избежать коллизий для всех прочих запущеных "модальных" и немодальных форм мы должны каким-то образом установить их свойство Enabled=.F. тоже.

В данном случае нет никакой опасности в "играх" с AlwaysOnTop, так как нет модальных форм.
4 сен 08, 14:35    [6147108]     Ответить | Цитировать Сообщить модератору
 Re: закрытие нескольких форм  [new]
Dima T
Member

Откуда:
Сообщений: 15281
MikhailB
Спасибо, тему прочитал и ничего противоречивого ей в своем посте не нашел.

...так как нет модальных форм.


Читай самый первый пост:
AnnaSPB
... последовательно одна из другой открываются формы (все модальные)...


Если уж хочется доказать свою правоту - возьми выше пример (мой или Владимира), замени код в кнопке на тулбаре на свой и продемонстрируй что все у тебя отлично работает.
4 сен 08, 14:54    [6147283]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 [2] 3   вперед  Ctrl      все
Все форумы / FoxPro, Visual FoxPro Ответить