views:

671

answers:

1

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

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.

+4  A: 

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.

skamradt
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.
jachguate
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.
jachguate
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.
skamradt
@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 crazy
jachguate
@jachguate: You probably need to handle `WM_ACTIVATEAPP` in addition to `WM_ACTIVATE`. If this fails, try `WM_NCACTIVATE` too.
mghie
@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. @skamradt 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).
jachguate
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_THICKFRAME`
skamradt
@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.
jachguate