Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.07.11;
Скачать: [xml.tar.bz2];

Вниз

Фокус при выводе диалоговых окон в MDI приложениях   Найти похожие ветки 

 
Суслик ©   (2005-06-22 19:07) [0]

Есть проект, состоящий из:
1. unit1 - mdi form
2. unit2 - mdi child

На форме unit2 есть 2 кнопки. После запуска приложения фокус находится на первой кнопке. Используя клавишу tab можно преключаться между кнопками. В кнопке номер 1 есть вызов диалогового окна.

После закрытия диалогового окна пропадает фокус. Судя по результатам анализа (использовал функции winapi GetFocus и GetWindowText) фокус переходит главной форме.

ВОПРОСЫ.
1. Почему так происходит?
2. Как сделать так, чтобы фокус оставался на кнопке номер 1?

unit1.pas


unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;
type
 TForm1 = class(TForm)
 end;
var
 Form1: TForm1;
implementation
{$R *.dfm}
end.


unit1.dfm

object Form1: TForm1
 Left = 397
 Top = 106
 Width = 798
 Height = 640
 Caption = "Form1"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 FormStyle = fsMDIForm
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
end


unit2.pas


unit Unit2;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;
type
 TForm2 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
 end;
var
 Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
  enabled := false;
  with tform.create(application) do
  begin
     showmodal();
     free();
  end;
  enabled := true;
end;
end.


unit2.dfm


object Form2: TForm2
 Left = 370
 Top = 154
 Width = 870
 Height = 640
 Caption = "Form2"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 FormStyle = fsMDIChild
 OldCreateOrder = False
 Position = poDefault
 Visible = True
 PixelsPerInch = 96
 TextHeight = 13
 object Button1: TButton
   Left = 72
   Top = 64
   Width = 75
   Height = 25
   Caption = "Button1"
   TabOrder = 0
   OnClick = Button1Click
 end
 object Button2: TButton
   Left = 176
   Top = 56
   Width = 75
   Height = 25
   Caption = "Button2"
   TabOrder = 1
 end
end


project1.dpr


program Project1;
uses
 Forms,
 Unit1 in "Unit1.pas" {Form1},
 Unit2 in "Unit2.pas" {Form2};
{$R *.res}
begin
 Application.Initialize;
 Application.CreateForm(TForm1, Form1);
 Application.CreateForm(TForm2, Form2);
 Application.Run;
end.


 
Суслик ©   (2005-06-22 19:21) [1]

А блин! Забыл сказать, что при нажатии кнопки я делаю enabled := false;

Это дело не лишнее, т.к. на самом деле вызову диалога предшествует длинная операция, в ходе которой вызывается ProcessMessages.

И вот для того, чтобы форма не реагировала ни на что я делаю enabled := false;. Т.е. это ДОЛЖНО остаться.


 
ANB ©   (2005-06-22 19:29) [2]

Тогда не забывай делать и SetFocus, когда включишь кнопку обратно.


 
ANB ©   (2005-06-22 19:30) [3]

Хотя, нарывался, WM_SETFOCUS работает несколько лучше.


 
Суслик ©   (2005-06-22 19:35) [4]


>  [2] ANB ©   (22.06.05 19:29)

Да это понятно, что можно делать это явно. Вопрос почему это происходит?


 
Юрий Зотов ©   (2005-06-22 19:36) [5]

> Суслик ©   (22.06.05 19:21) [1]

> при нажатии кнопки я делаю enabled := false;

Ну так это все и объясняет, видимо. При закрытии диалога форма еще задизаблена, поэтому получить фокус она не может и система отдает его главной форме - а уж только ПОТОМ (т.е. ПОСЛЕ обработки всей кучи оконных сообщений) выполняется Enabled := True. Но уже поздно - фокус остается у главной формы.

Вывод: Enabled := True надо выполнять либо перед непосредственным показом диалога (после окончания той самой длинной операции), либо в коде самого диалога (но уже после закрытия его окна, поскольку оно модальное - то есть, в OnDestroy, а не в OnClose). Еще вариант - оставить все как есть, но после Enabled := True сразу же вызвать SetFocus.


 
Суслик ©   (2005-06-22 19:45) [6]


> Еще вариант - оставить все как есть, но после Enabled :=
> True сразу же вызвать SetFocus.

Какой setfocus: self.setfocus или windows.setfocus?
Если первый, то это не работает (не имеет эффекта).
Если воторой, то это работает, но я как-то побаиваюсь делать вызовы winapi в обход vcl. Это безопасно?


 
Суслик ©   (2005-06-22 19:47) [7]

Кстати self.setfocus не работает потому, что active для формы = TRUE!


 
ANB ©   (2005-06-22 19:58) [8]

1. Второй сетфокус.
2. Абсолютно безопасно, VCL сам очень любит API вызывать.


 
Юрий Зотов ©   (2005-06-22 19:59) [9]

> Суслик ©   (22.06.05 19:45) [6]

> я как-то побаиваюсь делать вызовы winapi в обход vcl.

Начиная с того момента, как программа откомпилирована, ее код состоит из нашего кода и кода VCL на совершенно равных началах. Исполняя программу, Windows и CPU не знают, какой код кем написан. И если одна часть кода (VCL-ная) запросто вызывает функции WinAPI, то почему то же самое не может делать другая часть того же кода?

> Это безопасно?

Если делать с умом, то все безопасно. Иногда даже безопаснее именно делать прямые вызовы WinAPI, чем вызывать методы VCL (во втором случае код VCL может возбудить логически ненужное в данном месте алгоритма исключение, в первом же функция просто не сработает и тихо установит код ошибки). В конкретном случае с передачей фокуса - вполне безопасно. Ведь то же самое сообщение посылает и сама система, когда происходит переключение между программами - и все проходит нормально. Так почему то же самое не может сделать наша программа?


 
Суслик ©   (2005-06-22 20:01) [10]


> 1. Второй сетфокус.
> 2. Абсолютно безопасно, VCL сам очень любит API вызывать.


Понимаешь ли, с учетом [7] у меня есть ощущение, что это вообще небольшой глючок.

Если делать как я, то после enabled := true свойство active у формы = true.

См. в доку TCustomForm.Active и видим:

Specifies whether the form has focus.
property Active: Boolean;

А форма-то, очевидно, фокуса не имеет :(


 
ANB ©   (2005-06-22 20:05) [11]

Короче, проблема была в следующем : когда окно с фокусом дисайблится, то теряет фокус, так как не может его иметь. И это нормально. А кто объяснит винде, что когда ты окно обратно включишь, нужно фокус поставить на место ? Никто, кроме тебя.


 
Суслик ©   (2005-06-22 20:05) [12]


>  [9] Юрий Зотов ©   (22.06.05 19:59)


А что ты скажешь на [10]?

Понимаешь, тут како-то противоречие получается - я явно вызываю TCustomForm.SetFocus, а она не отрабатывает, т.к. форма считает, что она уже в фокусе: TCustomForm.Active = true.
Т.е. это некое противоречие vcl.

Конечно, я могу вызывать напрямую windows.setfocus(self.handle). Но я должен быть уверен, что форма, handle которой я передаю, корректно на это все отреагирует. Например, обновит acitve.


 
Суслик ©   (2005-06-22 20:06) [13]


>  [11] ANB ©   (22.06.05 20:05)

Да я понимаю, что я не прав. Я скорее говорю, про глючок vcl - self.setfocus() не имеет эффекта, т.к. форма (с точки зрения vcl) до сих пор считает, что она фокусирвана.


 
ANB ©   (2005-06-22 20:15) [14]

Да дался тебе этот Active. Форма зафокусилась ? Фокус на кнопку стал ? Чего еще надо. Ну пощелкай на ней, убедись, что ничего не сломалось. Если борланд так написал, значит зачем то это было нужно. За теорией - к Юрию Зотову или Шевченко.


 
Юрий Зотов ©   (2005-06-22 20:15) [15]

> Суслик ©   (22.06.05 20:05) [12]

Может быть, это и глючок, но может быть, это неточность в хелпе или в нашей его трактовке. Честно сказать, мелочи подобного рода я просто не беру в голову. Даже если они и всплывают, то  просто пишу код, который 100% работает, как надо, вот и все.

Дим, вызывай WinAPI и не мучайся сомнениями. Все будет окейчики, вот ей-богу. Печенкой чую, а она меня еще ни разу не подводила!
:о)


 
Суслик ©   (2005-06-22 20:17) [16]


> Дим, вызывай WinAPI и не мучайся сомнениями. Все будет окейчики,
> вот ей-богу. Печенкой чую, а она меня еще ни разу не подводила!
> :о)

Пойду дебужить, реакцию формы на wm_setfocus и прочих контролов на wm_killfocus.
Вот тогда тоже буду печенкой чуять.


 
Юрий Зотов ©   (2005-06-22 20:19) [17]

> Суслик ©   (22.06.05 20:05) [12]

Если уж прям все так страшно и охота докопаться до самого нутра, то походи по коду VCL отладчиком - там все и увидишь. Если только не вывалишься отладчиком в DefWindowProc - а если вывалишься, то по ней можно всю оставшуюся жизнь ходить, и то времени не хватит.


 
Игорь Шевченко ©   (2005-06-22 23:52) [18]


> Пойду дебужить, реакцию формы на wm_setfocus и прочих контролов
> на wm_killfocus


procedure TCustomForm.WndProc(var Message: TMessage);
var
 FocusHandle: HWND;
....
   case Msg of
     WM_ACTIVATE, WM_SETFOCUS, WM_KILLFOCUS:
       begin
         if not FocusMessages then Exit;
         if (Msg = WM_SETFOCUS) and not (csDesigning in ComponentState) then
         begin
           FocusHandle := 0;
           if FormStyle = fsMDIForm then
           begin
             if ActiveMDIChild <> nil then FocusHandle := ActiveMDIChild.Handle;
           end
           else if (FActiveControl <> nil) and (FActiveControl <> Self) then
             FocusHandle := FActiveControl.Handle;
           if FocusHandle <> 0 then
           begin
             Windows.SetFocus(FocusHandle);
             Exit;
           end;
         end;
       end;

И чего там, спрашивается, дебужить ?


 
Суслик ©   (2005-06-23 00:08) [19]


> И чего там, спрашивается, дебужить ?

ты, например, видишь где тут выставляется fActive?
Думаю, что не видишь. Значит нужно дебужить. В доке то этого точно нет.


 
Суслик ©   (2005-06-23 00:15) [20]

>>> Игорь Шевченко

Судя по всему реакция vcl в данному случае на непосредственный вызов winapi происходит не только в том куске, который ти привел, а в обработчике WM_ACTIVATE.

---------------
Все же продолжу утверждать, что реакция vcl на такое с ней обращение неадекватна. Она была бы адекватна, если бы либо я получал, что хочу (т.е. не поднимал данного топика :))), либо active у формы стал бы вообще = false (но он то равен true), т.е. vcl считает, что форма в фокусе и вызов tcustomform.setfocus не имет эффекта. Мое мнение, что тут есть недостаток документации в области preconditions для ShowModal.


 
Игорь Шевченко ©   (2005-06-23 00:34) [21]

Суслик ©   (23.06.05 00:15) [20]


> Все же продолжу утверждать, что реакция vcl на такое с ней
> обращение неадекватна


Дима, хочешь хороший совет ? Не надо возмущаться недостатками VCL - воспринимай ее (VCL), как данность, ищи обходные пути, все равно все в Windows упрется, а он (Windows) написан и протестирован людьми, коих было гораздо больше, чем писателей VCL. Не так давно я тебе приводил пример некорректности (с моей точки зрения) поведения в VCL, однако ж, выход нашел и забыл про это поведение. Советую и тебе идти тем же путем - энтропия во вселенной не так сильно возрастет.

Удачи!


 
Суслик ©   (2005-06-23 00:41) [22]


> Игорь Шевченко ©   (23.06.05 00:34) [21]

Да....согласен. Так и делаю. А в группы я все же запостю....т.к. я думаю, что сказал - либо дока виновата, либо код...


 
evvcom ©   (2005-06-23 00:48) [23]

Да, Дим. Все равно генофонд править бессмысленно. Прими его как есть и обойди.


 
Суслик ©   (2005-06-23 00:54) [24]

Я бы хотел несколько пояснить свою позицию.

Одно дело, когда ты нашел глюк (как тебе кажется), обошел его, а в перспективе получил еще больший глюк. А все дело в том, что исходный глюк не глюк, а твое ламерство.

Другое дело, что ты нашел реальный глюк, о котором многие знают и которые многие обходят известным всем образом.

Об этом и речь. Хотелось бы уяснить систематичность найденной мной проблемы.


 
evvcom ©   (2005-06-23 01:01) [25]

Если этот "глюк" не приводит к краху в последующей работе твоего алгоритма, то это вовсе не глюк, это маленькая "фичка". :) Не бери в голову.


 
Суслик ©   (2005-06-23 01:05) [26]


> evvcom ©   (23.06.05 01:01) [25]

Проблема в том, что свой продукт по моим расчетам я буду еще поддерживать лет 5 не меньше (уже 5 поддерживаю). Так, что это не то, что сказал ЮЗ: откомпилил, работает, и слава богу. Это надолго. Поэтому нужно "в точку".


 
evvcom ©   (2005-06-23 01:12) [27]

Тем лучше. Вот за последующие 5 лет, если вдруг что всплывет, нам и расскажешь, а пока не бери в голову. :) Извини, я сам не люблю относиться типа "работает, и слава богу", но в данном случае... Если через WinAPI работает, а по другому нет, то это явные глюки используемых компонент, пусть даже VCL. Необязательно об этом кричать на всех углах, но тем не менее, даже Билл Гейтс не безгрешен, и в WinAPI люди находят ошибки...


 
Gero ©   (2005-06-23 01:16) [28]


Суслик ©   (22.06.05 19:07)
> Есть проект, состоящий из:
> 1. unit1 - mdi form
> 2. unit2 - mdi child



Суслик ©   (23.06.05 01:05)
>  свой продукт по моим расчетам я буду еще поддерживать лет
> 5 не меньше (уже 5 поддерживаю).


Вот это и вправду круто. Где ж ты такого работодателя-то нашел?

:)


 
Суслик ©   (2005-06-23 01:25) [29]


> Gero ©   (23.06.05 01:16) [28]

таки ты не понял, что это тестовый проект дабы показать тебе и остальным суть проблемы?


 
evvcom ©   (2005-06-23 01:29) [30]


> 5 не меньше (уже 5 поддерживаю).

А не засиделся ли ты, Дим, на одном месте? Или хорошо платят? Хотя недавно возле Грибоедова я подумал, что второе вроде как не подходит. :)


 
Суслик ©   (2005-06-23 01:40) [31]


> evvcom ©   (23.06.05 01:29) [30]

дело не в оплате - это семейный бизнес.
вернее платят - оч хорошо :)
дело в том, что я кормиться с проекта буду еще 5 лет, или более (если борланд не умрет)


 
evvcom ©   (2005-06-23 01:56) [32]


> я кормиться с проекта буду еще 5 лет, или более (если борланд
> не умрет)

А борланд тут при чем? Ты ж не станешь через пару лет переписывать проект под Delphi 2007! Как видимо, не стал переписывать под D7, когда он появился. Так что жизнедеятельность этого проекта не зависит от дядьки борланда, а скорее зависит от новых идей и технологий.
Всё, я спать. Пиво выветривается, а завтра на работу. :)


 
Суслик ©   (2005-06-23 11:04) [33]

Спасибо за ответы.

Буду восстанавливать фокус с помощью winapi.

Вопрос: чем нужно пользоваться функциями GetActiveWindow/SetActiveWindow или GetFocus/SetFocus?

С уважением,
Тимохов Дмитрий


 
Игорь Шевченко ©   (2005-06-23 19:38) [34]


> Вопрос: чем нужно пользоваться функциями GetActiveWindow/SetActiveWindow
> или GetFocus/SetFocus?


Для MDI-форм посылкой сообщения WM_MDIACTIVATE окну MDIClient + SetFocus


 
Gero ©   (2005-06-23 22:46) [35]


> Суслик ©   (23.06.05 01:25)

Да я не такой тупой каким кажусь.
Может, у меня юмор слишком специфичен?

Ладно, без обид.


 
Defunct ©   (2005-06-24 02:37) [36]

В MDI приложениях с Active/Focus явно есть лажа. Например: имеем несколько открытых MDI Child, при изменении размеров главной MDI формы состояние Active получает один MDI Child, при этом фокус находится совсем на другом MDI Child"e. Для лечения наверое надо начинать со свойства Active (лажа именно в нем, значение Active должно соответствовать написаному в справке, и тогда все будет работать как надо) .


 
Суслик ©   (2005-06-24 11:55) [37]


>  [35] Gero ©   (23.06.05 22:46)

Без обид :)

-------------

Всем спасибо. Я понял, что есть все-таки не вполне адекватное поведение vcl (т.е. не соотв. справке). Спасибо ИШ, пойду читать, зачем еще WM_MDIACTIVATE нужне, если в моем случае SetFocus вполне успешно работает.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.07.11;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.037 c
14-1118673261
ms1
2005-06-13 18:34
2005.07.11
Moи oтnyck нa Kyбe.


1-1118401791
seregka
2005-06-10 15:09
2005.07.11
Архивация при помощи Zlib


1-1118261613
SniZ
2005-06-09 00:13
2005.07.11
Сжатие строки


14-1118832825
Ega23
2005-06-15 14:53
2005.07.11
Программистские песни


6-1113033236
Skokanov
2005-04-09 11:53
2005.07.11
Интернет трафик





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский