Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Фокус при выводе диалоговых окон в MDI приложениях [D6, Win2k]


Страницы:   1 2

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

Есть проект, состоящий из:
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 20:19:00) [21]

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

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


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


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

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


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

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

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

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


ANB   (2005-06-22 20:15:00) [24]

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


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


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

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


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


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


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

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

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


ANB   (2005-06-22 20:05:00) [27]

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


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


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


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

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

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

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

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


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

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

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

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

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

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


ANB   (2005-06-22 19:58:00) [30]

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


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

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


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


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

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


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

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

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

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

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


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


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

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


ANB   (2005-06-22 19:30:00) [35]

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


ANB   (2005-06-22 19:29:00) [36]

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


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

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

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

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо