Конференция "KOL" » TrayIcon и WM_CLOSE [Delphi]
 
  • Ruzzz (20.07.09 01:37) [0]
    Как я понимаю, при создании TrayIcon вот таким образом NewTrayIcon(frmMain, frmMain.Icon) в качестве первого параматра мы передаем родителя, к функции окна которого мы прикрепим функцию окна нашего TrayIcon, на это указывает строчка из NewTrayIcon - Wnd.AttachProc( WndProcTray ). Далее если посмотреть WndProcTray то видно что мы перехватываем WM_CLOSE и в итоге удаляем иконку из трея. Это дает нам возможность при закрытии формы, автоматически удалять и иконку.
    1) Но при этом появляется проблема, так как (указано в описании AttachProc) «Last attached procedure is called first», то если мы захотим «не реагировать на закрытие формы», например установив Accept := False в OnClose, сообщение WM_CLOSE все равно попадет в WndProcTray, и все нам испортит :(
    2) Если же не передавать главную форму в NewTrayIcon (в инете есть пример работы с TrayIcon где в NewTrayIcon передается не форма а созданый PControl), то в результате при закрытии главной формы иконка не удаляется из трея.

    Что по вашему мнению более разумно сделать в этих ситуациях?
  • Ruzzz (20.07.09 01:42) [1]
    первая проблема актуальна также, если использовать главную форму и TrayIcon, при этом разрабатывая приложение с помощью MCK. Потому что в этом случае MCK генерирует код который в качестве первого параметра NewTrayIcon передает главную форму
  • Ruzzz (20.07.09 01:47) [2]
    Вообще интересует как при минимизации и закрытии формы просто скрыть ее.
  • Ruzzz (20.07.09 13:00) [3]
    Пока что пришел к такому:

    procedure DoFormClose(Dummy: Pointer; Sender: PObj; var Accept: Boolean);
    begin
     if frmMain.Visible then begin
       frmMain.Hide;
       Accept := False;
     end else begin
       Tray.Free;
       Accept := True;
     end;
    end;

    procedure DoWorkMenu(Dummy: Pointer; Sender: pMenu; Item: Integer);
    begin
     case Item of

    ...

       2: frmMain.Close;
     end;
    end;

    ...

     frmMain.OnClose := TOnEventAccept(MakeMethod(nil, @DoFormClose));

    ...

     Menu := NewMenu(frmMain, 0,
        ['Show/Hide',
        '-',
        'Exit' ],
       TOnMenuItem(MakeMethod(nil, @DoWorkMenu))
       );

    ...

     Tray.NoAutoDeactivate := True;



    Это позволяет скрывать форму при нажатии кнопки «Закрыть» и при этом корректно удалять иконку при выходе из программы.
  • Ruzzz (20.07.09 16:32) [4]
    Появилась проблема :( Если мы хотим выйти из программы с помощью меню трея, и при этом форма не скрыта, то она просто скрывается :(
  • Ruzzz (20.07.09 18:58) [5]
    var
     AppExit: Boolean = False;

    procedure DoWorkMenu(Dummy: Pointer; Sender: pMenu; Item: Integer);
    begin
     case Item of
       0: ShowHideForm;
       2: begin
         AppExit := True;
         frmMain.Close;
       end;
     end;
    end;

    procedure DoFormClose(Dummy: Pointer; Sender: PObj; var Accept: Boolean);
    begin
     if optCloseToHide and frmMain.Visible and not AppExit then begin
       frmMain.Hide;
       Accept := False;
     end else begin
       Tray.Free;
       Accept := True;
     end;
    end;

  • Дмитрий К © (20.07.09 19:35) [6]
    program testFormHide;

    uses
     Windows, Messages, KOL;
    type
     PForm1 = ^TForm1;
     TForm1 = object(TObj)
     private
       Form: PControl;
       TI: PTrayIcon;
       Menu: PMenu;
       function FormMessage(var Msg: TMsg; var Rslt: Integer): Boolean;
       procedure TIMouse(Sender: PObj; Message: Word);
       procedure MenuMenuItem(Sender: PMenu; Item: Integer);
     end;
    var Form1: PForm1;

    const
     WM_SHOWHIDE = WM_USER + 1000;
    { TForm1 }

    function TForm1.FormMessage(var Msg: TMsg; var Rslt: Integer): Boolean;
    begin
     Result := False;
     case Msg.message of
       WM_SYSCOMMAND: begin
         case Msg.wParam of
           SC_CLOSE, SC_MINIMIZE: begin
             Form.Perform(WM_SHOWHIDE, 0, 0);
             Result := True;
           end;
         end;
       end;
       WM_SHOWHIDE: begin
         if Form.Visible then
         begin
           Form.Hide;
           Menu.ItemText[0] := 'Show';
         end
         else begin
           Form.Show;
           Menu.ItemText[0] := 'Hide';
         end;
       end;
     end;
    end;

    procedure TForm1.MenuMenuItem(Sender: PMenu; Item: Integer);
    begin
     case Item of
       0: Form.Perform(WM_SHOWHIDE, 0, 0);
       2: Form.Close;
     end;
    end;

    procedure TForm1.TIMouse(Sender: PObj; Message: Word);
    var P: TPoint;
    begin
     case Message of
       WM_RBUTTONUP:begin
         SetForegroundWindow(Form.Handle);
         GetCursorPos(P);
         Menu.Popup(P.X, P.Y);
       end;
       WM_LBUTTONDOWN:
         SetForegroundWindow(Form.Handle);
       WM_LBUTTONDBLCLK:
         Form.Perform(WM_SHOWHIDE, 0, 0);
     end;
    end;

    begin
     New(Form1, Create);
     with Form1^ do
     begin
       Form := NewForm(nil, 'Test');
       Form.Add2AutoFree(Form1);
       Form.OnMessage := FormMessage;
       TI := NewTrayIcon(Form, LoadIcon(0, IDI_APPLICATION));
       TI.OnMouse := TIMouse;
       NewMenu(Form, 0, [], nil);
       Menu := NewMenu(Form, 0, ['Hide', '-', 'Exit'], MenuMenuItem);
       Menu.Items[0].DefaultItem := True;
       Run(Form);
     end;
    end.

  • Ruzzz (20.07.09 21:03) [7]
    Спасибо! :) Сам как раз разобрался и пришел к такому:
    function DoFormMessage(Dummy: Pointer; var Msg: TMsg; var Rslt: Integer): Boolean;
    begin
     Result := False;
     if Msg.message = WM_SYSCOMMAND then
       case Msg.wParam of
         SC_MINIMIZE:
           if optMinToHide then begin
             frmMain.Hide;
             Result := True;
           end;
         SC_CLOSE:
           if optCloseToHide then begin
             frmMain.Hide;
             Result := True;
           end
       end;
    end;



    Действительно лучше ловить не WM_Close, а SC_CLOSE
    НО Ваш пример много чего для меня показывает, например организация кода без использования MCK :)

    Вопрос, зачем использовать SHOWHIDE, а не вызывать сразу процедуру ShowHide?
  • Дмитрий К © (20.07.09 22:29) [8]

    > Вопрос, зачем использовать SHOWHIDE, а не вызывать сразу
    > процедуру ShowHide?

    В данном случае - незачем.
 
Конференция "KOL" » TrayIcon и WM_CLOSE [Delphi]
Есть новые Нет новых   [134431   +10][b:0][p:0.003]