Форум: "Основная";
Текущий архив: 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.dfmobject 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