![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Фокус при выводе диалоговых окон в MDI приложениях [D6, Win2k]
Суслик © (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;. Т.е. это ДОЛЖНО остаться.