![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Не происходит переключение между формами
Андрей2 © (2004-06-12 23:19:00)Имеется три формы. После запуска они все отображаются (Visible = true). Но проблема не в этом - проблема с переключением между формами. Конкретно: при переключении между формами 2 и 3 всё происходит отлично - без глюков. Но вот при переключении на 1-ую форму спустя долю секунды фокус обратно возвращается на форму, с которой происходило переключение. Таким образом переключиться на фору 1 можно только после закрытия форм 2 и 3, хотя при двойном щелчке по заголовку 1-ой она успешно назворачивается, за заголовок успешно перемещается, но системные кнопки (свернуть, развернуть и закрыть) тоже не нажимаются. Как я понял - этот глюк происходит только с главными формами (в KOL по умолчанию 1-ая форма - главная, а остальные - её дочерние). Как исправить этот глюк? (где внести изменения в KOL.pas)
Gandalf (2004-07-02 19:17:00) [1]Желательно бы окончательный вариант сюда бросить чтоб оно потом в FAQ ушло.
Андрей2 (2004-06-30 22:08:00) [2]SPeller. Попытался я разобрать ваш код, однако не всё в нём понял - понял только как исправить глюк с переключением на не главные формы. Но мне также хотелось бы и узнать как без глюков отображать модальные формы. Пожалуйста, можно по подробнее? - выложите на форум пояснения к вашему коду или вышлюте мне на e-mail: Andr-forum@(собака)mail.ru (пишу "(собака)" для предотвращения действий спам-роботов) Ваш исправленный вариант KOL.pas. Заранее спасибо.
SPeller (2004-06-14 16:11:00) [3]
> Vladimir Kladov (13.06.04 18:56) [19]
Неправду говорите. 1Кбайт - это вы преувеличили, потому что 1К - это код для обеспечения модальности. Ваш код ещё больше занимает. А вот та часть кода, которая исправляет глюк с фокусом, которую я обозначал "xor", НИЧЕГО не добавляет (по крайней мере ничтожно мало). И уж гораздо меньше чем Аплет.
-----------------
[ничего] 17920
+Applet 18432
+xor 17920
Ну и где же мой килобайт? А глюк исправлен.
Vladimir Kladov (2004-06-13 18:56:00) [4]добавление TKOLApplet увеличивает код на 300 байт, а всего этого - на 1К. Кроме того, нет асм-кода. Кто его будет писать? Замечу что переход от асм-кода к пас-коду добавляет весьма ощутимо - на пустом проекте.
И вообще KOL.TApplet - это не исправление глюка, а опциональная фича, ее использование изначально было запланировано. Отсутствие его предполагалось только для проектов простейших, из 1 формы.
Андрей2 (2004-06-13 15:37:00) [5]Глюки надо искать и исправлять, а не обходить. SPeller, спасибо за столь полный ответ, сейчас попробую его переварить, а об итогах потом сообщу.
SPeller (2004-06-13 15:28:00) [6]
> Vladimir Kladov (13.06.04 15:21) [15]
Дык, можно ведь всё новое заключить в скобки условной компиляции и включать когда захочется. Да и откуда глюки, если программист может ошибиться только в написании строки Form.ShowModal или Form.ShowModalParented? Я ведь исправил два серьёзных глюка - с фокусом и с вызовом OnClose, в придачу уменьшил размер, занимаемый, кодом для модальности, а вы продолжаете говорить что надо использовать Аплет.
SPeller (2004-06-13 15:23:00) [7]Вот, выкладываю свои наработки на обозрение общественности по поводу модальности и описанного в вопросе глюка, который я устранил попутно с решением модальности.
Всё началось с того, что когда мне понадобились модальные формы, то я столкнулся с рядом проблем, таких как "хитрые" вызов и скрытие модальной формы, описанный выше глюк с фокусом, и ещё пара попутных глюков. После некоторого времени поисков решения и оптимизации я это всё нашёл. Кроме того, моё решение меньше увеличивает размер конечного ЕХЕ.
Доказательство о меньшем размере:
Я сравнивал, всё в pas-версии, так как моей функции в асм-версии нет, и размер её, естественно, будет больше исходного варианта. Для испытания использовал проект без аплета с тремя формами. На формах кроме стандартных кнопок ничего нет. Для испытаний я сделал следующее:
Разбил свои добавления в kol.pas на части. Условно обозначил их так:
Реализация ShowModalParented - "Parented";
Всё что относится к SetModalResult - "SetMR";
Мой вариант обработчика WM_CLOSE в TControl.WndProc - "WM_CLOSE";
оба куска такого кода в wndprocapp и wndprocform:
if Self_.fModalForm <> nil then
SetFocus( Self_.fModalForm.fHandle )
else
if (Self_.FCurrentControl <> nil) and not(Self_.fCurrentControl.IsForm xor Self_.fIsApplet) then
заменяющих в обычных условиях такую строку:
if Self_.FCurrentControl <> nil then
я обозначил как "xor".
А исходный вариант ShowModal - так и оставил "ShowModal".
SetModalResult это write-метод свойства ModalResult и предназначен для гарантированного скрытия формы с экрана при установке ModalResult. Причина в том, что если ModalResult станет отличным от нуля, но при этом в очередь сообщений потока не придёт ниодного сообщения, то форма так и будет висеть на экране. SetmodalResult просто устанавливает нужное значение результата и отправляет окну нейтральное сообщение.
Ниже получил размеры ЕХЕ. Использовалось Delphi 6 + SysDcu. Запись +ХХХ означает подключение части ХХХ моего кода в ЕХЕ.
Что включено: Размер ЕХЕ:
--------------------------------------------
[ничего] 24064
+ShowModal 25600 <---
+WM_CLOSE 24064
+Parented 24576
+SetMR 24576
+xor 24576
+WM_CLOSE+Parented 25088
+xor+WM_CLOSE+Parented 25088
+xor+WM_CLOSE+Parented+SetMR 25088 <---
Выводы делайте сами. Я так думаю, что можно переходить полностью на мой вариант. Для экономии кода я думаю отказаться от SetModalResult вовсе, либо заключить его в скобки вроде {USE_SETMODALRESULT}. Вот мои изменения
полностью:
function WndProcApp
...
WM_SETFOCUS:
{$IFDEF NEW_MODAL}
if Self_.fModalForm <> nil then
SetFocus( Self_.fModalForm.fHandle )
else
if (Self_.FCurrentControl <> nil) and not(Self_.fCurrentControl.IsForm xor Self_.fIsApplet) then
{$ELSE not_NEW_MODAL}
if Self_.FCurrentControl <> nil then
{$ENDIF not_NEW_MODAL}
begin
Self_.FCurrentControl.CreateWindow; //virtual!!!
...
end;
function WndProcForm
...
// with _Self^ do
WM_SETFOCUS:
begin
{$IFDEF NEW_MODAL}
if fModalForm <> nil then
SetFocus( fModalForm.fHandle )
else
if (FCurrentControl <> nil) and not(fCurrentControl.IsForm xor fIsApplet) then
{$ELSE not NEW_MODAL}
if FCurrentControl <> nil then
{$ENDIF}
begin
FCurrentControl.CreateWindow; //virtual!!!
...
end;
{$IFNDEF NEW_MODAL}
function TControl.ShowModalParented(const AParent: PControl): Integer;
begin
Result := 0;
end;
{$ELSE NEW_MODAL defined}
function TControl.ShowModalParented(const AParent: PControl): Integer;
var FL: PList;
OldMF,
F: PControl;
I: Integer;
begin
Result := 0;
if (AParent = nil) then Exit;
Inc( fModal );
FL := NewList;
OldMF := AParent.fModalForm;
AParent.fModalForm := @Self;
if AParent.fIsApplet or (AParent.IsMainWindow and AParent.fIsForm) then
begin
for I := 0 to AParent.ChildCount - 1 do
begin
F := AParent.fChildren.Items[ I ];
if (F <> @Self) and F.fIsForm and F.fEnabled and F.fVisible then
begin
FL.Add( F );
F.Enabled := FALSE;
end;
end;
end;
if AParent.fIsForm and AParent.Enabled then
begin
FL.Add( AParent );
AParent.Enabled := FALSE;
end;
ModalResult := 0;
Show;
while not AppletTerminated and (ModalResult = 0) do
begin
WaitMessage;
AParent.ProcessMessages;
{$IFNDEF NOT_USE_OnIdle}
ProcessIdle( @Self );
{$ENDIF}
end;
AParent.fModalForm := OldMF;
Dec( fModal );
for I := 0 to FL.Count - 1 do
PControl( FL.Items[ I ] ).Enabled := True;
FL.Free;
Hide;
Result := ModalResult;
end;
{$ENDIF NEW_MODAL}
Изменения WM_CLOSE уже есть в kol.pas.
В пользу моего варианта есть ещё и тот момент, что в исходном баг: в модальной форме при закрытии никогда не вызывается обработчик OnClose.
Теперь вопрос, который наверняка возник: почему ShowModalParented? Потому что существуют ситуации, когда в приложении нужно показать модальную форму только относительно определенного окна, которое и станет недоступным, а не относительно всего проекта, когда недоступными становятся все окна программы. Запись ShowModalParented( Applet ) в таком случае будет эквивалентна нынешнему ShowModal.
Что конкретно дают мои зменения?
1) Алгоритм вызова модальной формы не зависитот наличия отдельного объекта Applet;
2) Вызов модальной формы производится единственной строкой
Form.ShowModalParented( SomeFormOrApplet );
Больше не требуется обсолютно никаких действий чтобы вызов и завершение формы были правильными.
3) В модальной форме нет необходимости назначать обработчик OnClose для того чтобы предотвратить уничтожение объекта формы
4) Нет глюка с фокусом. В случае модальных форм — когда Аплет не используется, то при закрытии модальной формы главная никак не может получить фокус, точно так же как описывает здесь автор сабжа.
Vladimir Kladov (2004-06-13 15:21:00) [8]Мне непонятно, зачем вносить массу изменений и провоцировать новые возможные глюки, которые обязательно появятся при этом, если есть решение, придуманное изначально: Applet для того и предназначался, чтобы играть роль менеджера форм, и я вляется в этом смысле полным аналогом TApplication в VCL.
SPeller (2004-06-13 14:37:00) [9]Угу, если использовать аплет, то глюка нет. Только мне не понятно, почему надо заставлять использовать аплет для устранения глюка, если можно внести изменения, которые сократят размер бинарного кода в конечном файле и исправят глюк?
Vladimir Kladov (2004-06-13 14:20:00) [10]Не то написал я. TKOLApplet а не TKOLProject.
Андрей2 (2004-06-13 12:15:00) [11]Vladimir Kladov. Почему Вы меня не понимаете. У меня ПУСТОЙ проект, не ставлю обработчик ни на одно из событий - просто запускаю "три формы" и "наслаждаюсь глюками". Попробуйте сами: создаём проект, добавляем дополнительно ещё две формы (в итоге получается три формы). Переводим его в KOL (сохраняем проект, добавляем на Form1 компонент KOLProject, задаём значение свойства projectDest например Proba, далее на все без исключения формы кидаем кидаем компонент KOLForm, ещё раз сохраняем, из папки, в которую сохранили открываем файл Proba.dpr), делаем, чтобы после запуска были отображены все три формы (через Инспектор объектов или обработчик события OnCreate - не имеет значения), запускаем, пытаемся переключиться со второй или третьей формы на первую и терпим неудачу - фокус фозвращается обртно на вторую или третью (взависимости от того, с какой формы происходило переключение). После того как проделаете - поделитесь своими впечатлениями на форуме.
Vladimir Kladov (2004-06-13 11:48:00) [12]Точно так же. Только не из обработчика события, по завершении которого происходит обратное переключение. По-моему, это разумеется.
Андрей2 (2004-06-13 11:05:00) [13]Vladimir Kladov. Форма отображается без проблем, но пока она отображается невозможно переключиться на главную форму - на Form1 - после кратковременной паузы фокус возвращается на форму, с которой производилось переключение - в вашем слечае на Form4. Вопрос: Как переключиться на Form1 без закрытия Form4.
Vladimir Kladov (2004-06-13 10:18:00) [14]для немодальных не было проблем вообще: Form4.Form.Show; Если это не работает можно еще попробовать Form4.Form.BringToFront;
Андрей2 (2004-06-13 09:44:00) [15]Vladimir Kladov. Я так и делаю - так написано в инструкции по использованию KOL, а инструкции я читаю. И данная проблема этим не решается.
Андрей2 (2004-06-13 09:44:00) [16]Vladimir Kladov. Я так и делаю - так написано в инструкции по использованию KOL, а инструкции я читаю. И данная проблема этим не решается.
Андрей2 (2004-06-13 09:42:00) [17]SPeller. Извини. Дал неправильный e-mail. Правильный - Andr-forum@(собака)mail.ru.
Андрей2 (2004-06-13 09:40:00) [18]SPeller. А мне на e-mail: Andr@(собака)mail.ru прислать не можешь? (пишу "(собака)" для предотвращения действий спам-роботов по рассылке спама)
Андрей2 (2004-06-13 09:37:00) [19]Отвечаю Dimaxx. Формы - НЕ МОДАЛЬНЫЕ!!!
Vladimir Kladov (2004-06-13 08:18:00) [20]Нет такого глюка. Положить на главную форму KOLProject, закрыть проект, открыть его и сделать Project|Build.