Windows 7 style Notifications Flyouts in Delphi
Asked Answered
C

1

17

Regarding Notification Area recommendations by Microsoft, I'm looking for ideas or a Delphi component to implement Notification Area Flyouts.

alt text

The first "natural" idea is to use a standard Delphi form, but I'm facing two issues with it:

  1. I can't get the form border behavior using the standard "BorderStyle" property. Tried to "mimic" the border using the GlassFrame property along with BorderStyle set to bsNone, but there's no GlassFrame when there's no border (at least, in Delphi 2007).
  2. I can't figure out how to make the form close when the user clicks everywhere out of the form itself. Yesterday I was trying with different messages, but no one works as expected.

I will thank any clue or component to make it happen :)

Best regards.

jachguate.

ps. There's a related question in converting notification area icon to Program icon in Win7 (Delphi).

update[0] I'm still looking for advise. @skamradt answer looks very good, but unfortunately doesn't work well in practice.

update[1] Finally, The auto-close behavior is working with the WM_ACTIVATE message after a calling SetForegroundWindog to force flyout "activation"

begin
  FlyoutForm.Show;
  SetForegroundWindow(FlyoutForm.Handle);
end;

Now, I'm looking for advise to reach the border behavior and visual style, because the closest behavior is achieved with style as WS_POPUP or WS_DLGFRAME, while the closest visual goal is achieved setting style as WS_POPUP or WS_THICKFRAME.

Cannelloni answered 20/1, 2010 at 21:14 Comment(1)
Thank you RRUZ for the link conversion :)Cannelloni
F
9

I believe what your after is the following:

TForm1 = class(TForm)
  :
protected
  procedure CreateParams(var Params: TCreateParams); override;
  procedure WMActivate(Var msg:tMessage); message WM_ACTIVATE;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := WS_POPUP or WS_THICKFRAME;
end;

procedure TForm4.WMActivate(var msg: tMessage);
begin
  if Msg.WParam = WA_INACTIVE then
    Hide; // or close
end;

This will give you a sizeable popup window with a glass frame. You can't move the window without additional programming, since the standard windows caption is missing. When another window gets focus, the FormDeactivate event gets fired...but only if you switch to another form in the same application. To handle it regardless of the application switched, use the message capture method.

Fenton answered 21/1, 2010 at 0:6 Comment(8)
Thank you! It looks very, very well. I don't have win7 on hand, and in vista it works 50% of the time, because the WM_ACTIVATE is not fired on all situations, or maybe I'm too tired now. In a couple of hours, with some rest and Win7 on hand I will make another try. Thanks again.Cannelloni
I finally get the Win7 machine and tested it, but as in vista, the form is still visible in cases when other flyouts close. For example, if you switch to another application selecting it's task bar button, it closes only 50% of the times (approximate). I tried a couple of things to understand, and the form doesn't get the WM_ACTIVATE message all the times. Maybe a win bug, but for sure there's a workaround because system flyouts (battery) works. If you click on another tray icon, the delphi frm doesn't close. Am I missing something? As far as I see, your idea is in my test program.Cannelloni
You can also hook into the Application.OnDeactivate event. Just set Application.OnDeactivate to a notification event which also hides the popup if its visible. Unfortunately I don't have Vista to test with.Fenton
@skamradt: Thank you for your advice, but unfortunately the behavior is the same as with WM_ACTIVATE message... maybe a delphi bug. It's driving me crazyCannelloni
@jachguate: You probably need to handle WM_ACTIVATEAPP in addition to WM_ACTIVATE. If this fails, try WM_NCACTIVATE too.Picky
@mghie: Thankyou, I keep trying. I found the reason of why not always getting the inactivate events, and it was the form is not always "activated" at Show(); call. It is fixed now calling SetForegroundWindow after show and auto-close seems to work well just with the WM_ACTIVATE message. Now, I'm trying to get the correct border behavior. @Fenton suggestion of WS_POPUP or WS_THICKFRAME let's the user resize the window. I was trying with lot of combination, but no one works as expected (thick border, no caption, no move, no resize).Cannelloni
You can always disable resizing by setting form constraints = the size of the requested form. Since there is no move handle, you shouldn't be able to move it with only WS_POPUP or WS_THICKFRAMEFenton
@skamradt: I know I can disable the resizing using the constraints, but it has two miss-behaviors: The user still gets resize cursors when the mouse is over form's border and a funny one (I just tested it with D2007), if the user pulls the left border of the form, it draws a resize rect and when the mouse button is released the form is actually moved! I really appreciate your time and help (and of the people reading this). Still looking for a clue of how to get better (correct) behavior? Best regards.Cannelloni

© 2022 - 2024 — McMap. All rights reserved.