Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

A Mouse Over Form 2

Status
Not open for further replies.

Glenn9999

Programmer
Jun 19, 2004
2,312
US
One of the consistent problems I've run into (a couple of projects now) is the need to show a small form upon an event which is on top of other windows, and then dismisses itself after a certain amount of time. The main reason is to be able to show more information (even some graphical data) than a hint text.

Any ideas on how to solve this? The main thing I've done is as follows, using a button to simulate what I'm trying to do:

Code:
// form1
procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Form2.Show;
  Button1.OnMouseMove := nil;
end;

// form2
procedure TForm2.FormCreate(Sender: TObject);
begin
  Timer1.Enabled := true;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  Form2.Close;
  Form1.Button1.OnMouseMove := Form1.Button1MouseMove;
end;

The major problems:
1. Getting the event to fire once and only once, no matter what? I'm not sure what I did is the best way from an "extensible" standpoint, but it seems to work.
2. Making sure the window shows no matter what. If the application happens to not have focus (which is realistic given these apps, as they are notification area programs), the extended hint window (form2) has a way of being buried or not shown at all.
3. Since they're notification area programs, the other unrelated problem is one of positioning the form. One problem I noticed on varying windows platforms is that SHAppBarMessage fails on the older ones (I have intentions on making one of the projects as universal as possible). I couldn't find any documentation on how to find the app bar outside of that API, so I'm wondering am I stuck here or is there another way to do it?

Ideas?

 
Since I made a little better test representative of what my projects are, another problem:

4. The window happens to be pretty disruptive when the application does have focus. So I guess, the main thing is to get a form that acts like a hint text, shows the notification it needs to show, and just gets out of the way.

 
5. One problem hearkening to #3, but different.

Link to image

It seems something's reporting incorrectly somewhere or I'm not considering something, as I want the form to sit directly on the appbar.

(sorry, the link parsing here doesn't seem to work right to show the image, just click on the link)



 
Did you know you can upload images to TT now?[lol]

So to summarize your question are:

- how to find the taskbar to determine the correct position for your notification window
- show that window without stealing focus

Am I correct?

P.S.: why do you not adhere to the windows standard and use a tray icon that show a balloon tip?

/Daddy

-----------------------------------------------------
Helping people is my job...
 
Uploading the image did not work correctly. As did linking directly to it to show it on the page, as the link parsing code is off here.

>how to find the taskbar to determine the correct position for your notification window

Which I *can* do with the SHAppBarMessage API as detailed in the link above. The problem is that the call fails on older OSes. I thought of looking for Shell_TrayWnd and then finding the bounding rectangle, but I'm not sure how universal *that* is. In terms of where the line is that I can expect the proper API call to work, is perhaps the question as documentation for older Windows versions has a way of disappearing very quickly. Ironically, the code behind the specific project I have in mind for the older OSes is so rudimentary that it worked for *all* Windows versions ever made, but the problem is one of display.

>show that window without stealing focus

This was problem #2, for which I'm doing this:
Code:
   SetFocus;
   SetForegroundWindow(Handle);
   BringToFront;

It works great if the application has focus, but if it doesn't, the window always shows up behind the others.

Other issues are more appearance related (#5) and whether I'm doing it the best way (#1). The appearance related stuff might iron itself out once I take away the border and add a panel bevel.

>why do you adhere to the windows standard and use a tray icon that show a balloon tip?

I guess this should be "why do you not"? Anyway, the balloon tip has a text limit on it too like the hints (and don't think you can show graphics). Besides, I've seen different apps be able to do what I'm looking to do, so I can't say it's out of the question. Just not been able to pull it off properly.

 
It seems I happen to have this feature in one of my applications:

Code:
unit u_frm_alertwindow;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TFrm_alert = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Lbl_alert: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    FT5CallId : Integer;
    FHwnd     : THandle;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWindowHandle(const Params: TCreateParams); override;
  public
    { Public declarations }
    procedure AlertModal(T5CallId : Integer; AlertStr : String);
    procedure Alert(T5CallId : Integer; AlertStr : String; Hwnd : THandle);
    procedure SetWindowToTop;
    property T5CallId : Integer read FT5CallId;
  end;

var
  Frm_alert: TFrm_alert;

implementation

uses u_class_t5connector;

{$R *.dfm}

function TaskBarHeight: integer;

// this is just to get the taskbar height to put the form in the correct position

var hTB: HWND;
    TBRect: TRect;

begin
 hTB := FindWindow('Shell_TrayWnd', ');
 if hTB = 0 then
  Result := 0
 else
  begin
   GetWindowRect(hTB, TBRect);
   if TBRect.Top = 0  // tray bar is positioned to the left or to the right
   then
     Result := 1
   else
    Result := TBRect.Bottom - TBRect.Top;
  end;
end;

function TaskBarWidth: integer;

// this is just to get the taskbar height to put the form in the correct position

var hTB: HWND;
    TBRect: TRect;
begin
 hTB := FindWindow('Shell_TrayWnd', ');
 if hTB = 0 then
  Result := 0
 else
  begin
   GetWindowRect(hTB, TBRect);
   if TBRect.Left = 0  // tray bar is positioned to the left or to the right
    then
     Result := 1
    else
     Result := TBRect.Right - TBRect.Left
  end;
end;

procedure TFrm_alert.SetWindowToTop;
begin
 SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
end;

procedure TFrm_alert.Alert(T5CallId: Integer; AlertStr: String; Hwnd : THandle);
begin
 FT5CallId := T5CallId;
 Lbl_alert.Caption := AlertStr;
 FHwnd := Hwnd;
 ShowWindow(Handle, SW_SHOWNOACTIVATE);
 Visible := True;
end;

procedure TFrm_alert.AlertModal(T5CallId : Integer; AlertStr: String);
begin
 FHwnd := 0;
 FT5CallId := T5CallId;
 Lbl_alert.Caption := AlertStr;
 ShowModal;
end;

procedure TFrm_alert.Button1Click(Sender: TObject);
begin
 Close;
end;

procedure TFrm_alert.CreateParams(var Params: TCreateParams) ;
begin
 inherited;
 with Params do
  begin
   ExStyle := ExStyle or WS_EX_TOPMOST or WS_EX_NOACTIVATE;
   WndParent := GetDesktopwindow;
   Style := Style and not WS_CAPTION;
  end;
end;

procedure TFrm_alert.CreateWindowHandle(const Params: TCreateParams);
begin
 inherited;
 SetWindowToTop;
end;

procedure TFrm_alert.FormClose(Sender: TObject; var Action: TCloseAction);
begin

end;

procedure TFrm_alert.FormCreate(Sender: TObject);
begin
 Left := Screen.Width - TaskBarWidth - Width - 2;
 Top := Screen.Height - Self.Height - TaskBarHeight - 2;
end;

end.

-----------------------------------------------------
Helping people is my job...
 
I think that got it, for most part. I guess for the compatibility issue for finding the taskbar, I can search for the window and if it fails, use the SHAppbar routine.

 
I guess for the compatibility issue for finding the taskbar, I can search for the window and if it fails, use the SHAppbar routine.

The FindWindow trick still works in Windows 8.1. Can't believe it, hardly.

 
yes I know as this is actual production code (used by over 200 computers ranging from XP to 8.1)

[afro]

-----------------------------------------------------
Helping people is my job...
 
Yeah, pre-XP was my problem, if you were wondering. Now I just need to look at the demo I have and see how I want to apply it to these projects here (don't think descending from TForm is going to produce forms that work in the designer - could be wrong though), and make the form stay if the mouse is on it (but that shouldn't be a huge problem).

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top