Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.03.20;
Скачать: CL | DM;

Вниз

Реализация ShowModal   Найти похожие ветки 

 
a.denisov   (2005-03-08 16:15) [0]

Добрый день, мастера!

Собственно, не вопрос, а крик души, так сказать. Все время, пока программирую на дельфи, мне абсолютно не нравится стандартное поведение форм приложения при вызове ShowModal - почему-то не заложена такая обыкновенная реакция, как мерцание окна при попытке выполнить действия с любой другой формой кроме модальной. Дело вкуса, так сказать.

Пока не вижу подводных камней, но сделать поведение форм "нормальным", с моей точки зрения, оказалось не так уж трудно (при том что моя реализация -  почти полная копия ShowModal, где ради простоты эксперимента, выполняются не все действия)

Вопрос: где подводные камни, которые помешали Borland сделать, ну, как минимум, также как в нижеприведенном коде?



type
 PPTaskWindow = ^PTaskWindow;
 PTaskWindow = ^TTaskWindow;
 TTaskWindow = record
   Next: PTaskWindow;
   Window: HWnd;
 end;

 TFormAccess = class(TForm)
 end;

const
 WndProcProp       = "WndProc";
 RefCountProp      = "UpdateCount";
 RefCountNull      = 1;

procedure FlashModalWindow(Window: HWND);
var
 pfwi              : FLASHWINFO;
begin
 pfwi.cbSize := SizeOf(pfwi);
 pfwi.hwnd := Window;
 pfwi.dwFlags := FLASHW_CAPTION;
 pfwi.uCount := 4;
 pfwi.dwTimeout := 75;
 FlashWindowEx(pfwi);
 MessageBeep(MB_OK);
end;

function ModalStateWindowProc(Window: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
 WndProc           : Cardinal;

 procedure Default;
 begin
   Result := CallWindowProc(Pointer(WndProc), Window, Msg, wParam, lParam);
 end;

begin
 WndProc := GetProp(Window, WndProcProp);
 if WndProc = 0 then
   Result := CallWindowProc(@DefWindowProc, Window, Msg, wParam, lParam)
 else
   case Msg of
     WM_MOUSEACTIVATE:
       if Assigned(Screen.ActiveForm) then begin
         Result := MA_NOACTIVATEANDEAT;
         FlashModalWindow(Screen.ActiveForm.Handle);
       end
       else
         Default;
     WM_NCHITTEST: begin
         Default;
         Result := HTCLIENT;
       end;
   else
     Default
   end;
end;

function HookWindow(Window: HWnd; Data: Longint): Bool; stdcall;
var
 P                 : PTaskWindow;
 PP                : PPTaskWindow;
 WndProc, RefCount : Cardinal;
begin
 if IsWindowVisible(Window) then begin
   New(P);
   PP := PPTaskWindow(Data);
   P^.Next := PTaskWindow(PP^);
   P^.Window := Window;

   WndProc := GetWindowLong(P^.Window, GWL_WNDPROC);
   if (WndProc <> Cardinal(@ModalStateWindowProc)) then begin
     SetProp(P.Window, WndProcProp, WndProc);
     SetProp(P.Window, RefCountProp, RefCountNull);
     SetWindowLong(P^.Window, GWL_WNDPROC, Cardinal(@ModalStateWindowProc));
   end
   else begin
     RefCount := GetProp(P.Window, RefCountProp);
     SetProp(P.Window, RefCountProp, RefCount + 1);
   end;

   PP^ := P;
 end;
 Result := True;
end;

procedure UnhookTaskWindows(WindowList: Pointer);
var
 P                 : PTaskWindow;
 WndProc, RefCount : Cardinal;
begin
 while WindowList <> nil do begin
   P := WindowList;
   if IsWindow(P.Window) then begin

     WndProc := GetProp(P^.Window, WndProcProp);
     if (WndProc <> 0) then begin
       RefCount := GetProp(P.Window, RefCountProp);
       if RefCount <> RefCountNull then
         SetProp(P.Window, RefCountProp, RefCount - 1)
       else begin
         SetWindowLong(P.Window, GWL_WNDPROC, WndProc);
         RemoveProp(P.Window, RefCountProp);
         RemoveProp(P.Window, WndProcProp);
       end;
     end;
     
   end;
   WindowList := P.Next;
   Dispose(P);
 end;
end;

function HookTaskWindows: Pointer;
begin
 try
   Result := nil;
   EnumThreadWindows(GetCurrentThreadID, @HookWindow, Integer(@Result));
 except
   UnhookTaskWindows(Result);
   Result := nil;
   raise;
 end
end;

function ShowModalForm(FormClass: TFormClass): TModalResult;
var
 Form              : TForm;
 WindowList        : Pointer;
begin
 WindowList := HookTaskWindows;
 Form := FormClass.Create(Application);
 with Form do try
   Include(TFormAccess(Form).FFormState, fsModal);
   Application.ModalStarted;
   try
     Show;
     try
       SendMessage(Handle, CM_ACTIVATE, 0, 0);
       ModalResult := 0;
       repeat
         Application.HandleMessage;
         if Application.Terminated then
           ModalResult := mrCancel;
       until ModalResult <> 0;
       Result := ModalResult;
       SendMessage(Handle, CM_DEACTIVATE, 0, 0);
     finally
       Hide;
     end;
   finally
     UnhookTaskWindows(WindowList);
     Application.ModalFinished;
   end;
 finally
   Free;
 end;
end;


 
Fenik   (2005-03-08 16:39) [1]

А что? Это стандарт Windows шоб мигало.


 
a.denisov   (2005-03-08 16:47) [2]

Вот именно что стандарт. А мигает ли при стандартном вызове ShowModal? Просто выдается звуковой сигнал MB_OK. О чем и речь, что Борланд не мигать не хочет)


 
Fenik   (2005-03-08 16:50) [3]

А! Я почему-то наоборот понял :)
Действительно, почему не мигает?


 
a.denisov   (2005-03-08 17:10) [4]

Не мигает потому что вызывается EnableWindow(Handle,False) - для всех форм кроме модальной. Самый простой вариант, не подразумевающий никакой другой обработки.


 
GanibalLector ©   (2005-03-08 17:11) [5]

> что Борланд не мигать не хочет
А он то тут при чем? ИМХО,это принципы ОС. Покажите мне,кто(какая программа) мигает!


 
a.denisov   (2005-03-08 17:12) [6]

Или вот интересная (возможность?непонятка):

procedure TForm1.Button1Click(Sender: TObject);
begin
 Form1.Enabled := False;
 Form2.ShowModal;
 Form1.Enabled := True;
end;

procedure TForm2.FormShow(Sender: TObject);
begin
 Form1.Enabled := True;
end;


 
a.denisov   (2005-03-08 17:24) [7]

А раз сигнал подает - тогда почему не должна мигать?)
Естественное обращение внимания пользователя на открытую модальную форму. Не знаю, по-моему в оффисе (у меня дома не установлен, не проверю) все на принципе одна модальная форма открыта - при попытке переключения на любую другую форму - модальная мигает. Я согласен, что даже MessageBox мерцает, только если задели его родительское окно - но на то он и MessageBox)
В общем, мне симпатичнее так. Вроде и проблем не должно быть. Если есть замечания по коду, плиз)


 
Плохиш ©   (2005-03-08 17:56) [8]

У меня в офисе ничего не мигает.


 
a.denisov   (2005-03-08 18:11) [9]

Офис какой? Хотя я могу ошибиться. А вообще неважно. Элементарное поведение MessageBox - мерцание при переключении на родительское окно - и то не реализовано в ShowModal. Если видишь разницу между тем, что и как делает ShowModal и тем, какую реализацию предлагаю я...) Я бы остановился на моей) Ладно, кому как нравится.



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

Текущий архив: 2005.03.20;
Скачать: CL | DM;

Наверх




Память: 0.48 MB
Время: 0.036 c
14-1109313006
вредитель
2005-02-25 09:30
2005.03.20
МРОС (читать заадомм наа пеередд) не дремлет


6-1105613443
Homa_Programer
2005-01-13 13:50
2005.03.20
СОКЕТЫ :(


14-1109663563
Nikolay M.
2005-03-01 10:52
2005.03.20
Поисковик от разработчиков Рамблера для разработчиков


1-1109925653
antoxa
2005-03-04 11:40
2005.03.20
Подскажите, как работать с TClientDataSet?


14-1109533478
OneFragLeft
2005-02-27 22:44
2005.03.20
KVirc or mIRC or XChat or ... etc.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский