These days you see a lot of software displaying message windows in the right bottom corner of the active screen for a few seconds or until a close button is clicked (f.i. Norton does this after it has checked a download).
I would like to do this using Delphi 7 (and if possible Delphi 2010, since I am slowly migrating my code to the latest version).
I found some posts here on SO regarding forms not receiving focus, but that's only one part of the problem. I'm thinking also on how to determine the exact position of this message window (knowing that f.i. a user may have put his taskbar to the right of the screen.
Thx in advance.
UPDATE 26 Jan, 10: Starting from the code of drorhan I created the following form (in Delphi 7) which works whether the taskbar is displayed at the bottom, the right, the left or the top of the schreen.
fPopupMessage.dpr: object frmPopupMessage: TfrmPopupMessage Left = 537 Top = 233 AlphaBlend = True AlphaBlendValue = 200 BorderStyle = bsToolWindow Caption = 'frmPopupMessage' ClientHeight = 48 ClientWidth = 342 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnClose = FormClose OnCreate = FormCreate DesignSize = ( 342 48) PixelsPerInch = 96 TextHeight = 13 object img: TImage Left = 0 Top = 0 Width = 64 Height = 48 Align = alLeft Center = True Transparent = True end object lblMessage: TLabel Left = 72 Top = 8 Width = 265 Height = 34 Alignment = taCenter Anchors = [akLeft, akTop, akRight, akBottom] AutoSize = False Caption = '...' Font.Charset = DEFAULT_CHARSET Font.Color = clNavy Font.Height = -11 Font.Name = 'Verdana' Font.Style = [fsBold] ParentFont = False Transparent = True WordWrap = True end object tmr: TTimer Enabled = False Interval = 3000 OnTimer = tmrTimer Left = 16 Top = 16 end end and
fPopupMessage.pas
unit fPopupMessage; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ImgList; type TfrmPopupMessage = class(TForm) tmr: TTimer; img: TImage; lblMessage: TLabel; procedure FormCreate(Sender: TObject); procedure tmrTimer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } bBeingDisplayed : boolean; function GetPopupMessage: string; procedure SetPopupMessage(const Value: string); function GetPopupCaption: string; procedure SetPopupCaption(const Value: string); function TaskBarHeight: integer; function TaskBarWidth: integer; procedure ToHiddenPosition; procedure ToVisiblePosition; public { Public declarations } procedure StartAnimationToHide; procedure StartAnimationToShow; property PopupCaption: string read GetPopupCaption write SetPopupCaption; property PopupMessage: string read GetPopupMessage write SetPopupMessage; end; var frmPopupMessage: TfrmPopupMessage; procedure DisplayPopup( sMessage:string; sCaption:string = ''); implementation {$R *.dfm} const DFT_TIME_SLEEP = 5; // the speed you want to show/hide.Increase/descrease this to make it faster or slower DFT_TIME_VISIBLE = 3000; // number of mili-seconds the form is visible before starting to disappear GAP = 2; // pixels between form and right and bottom edge of the screen procedure DisplayPopup( sMessage:string; sCaption:string = ''); begin // we could create the form here if necessary ... if not Assigned(frmPopupMessage) then Exit; frmPopupMessage.PopupCaption := sCaption; frmPopupMessage.PopupMessage := sMessage; if not frmPopupMessage.bBeingDisplayed then begin ShowWindow( frmPopupMessage.Handle, SW_SHOWNOACTIVATE); frmPopupMessage.Visible := True; end; frmPopupMessage.StartAnimationToShow; end; procedure TfrmPopupMessage.FormCreate(Sender: TObject); begin img.Picture.Assign(Application.Icon); Caption := ''; lblMessage.Caption := ''; bBeingDisplayed := False; ToHiddenPosition(); end; procedure TfrmPopupMessage.FormClose(Sender: TObject; var Action: TCloseAction); begin tmr.Enabled := False; Action := caHide; bBeingDisplayed := False; end; function TfrmPopupMessage.TaskBarHeight: integer; // this is just to get the taskbar height to put // my 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 TfrmPopupMessage.TaskBarWidth: integer; // this is just to get the taskbar height to put // my 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 TfrmPopupMessage.ToHiddenPosition; begin Self.Left := Screen.Width - TaskbarWidth - Self.Width - GAP; Self.Top := Screen.Height - TaskBarHeight; end; procedure TfrmPopupMessage.ToVisiblePosition; begin Self.Left := Screen.Width - TaskBarWidth - Self.Width - GAP; Self.Top := Screen.Height - Self.Height - TaskBarHeight - GAP; end; procedure TfrmPopupMessage.StartAnimationToShow; var i: integer; begin if bBeingDisplayed then ToVisiblePosition() else begin ToHiddenPosition(); for i := 1 to Self.Height+GAP do begin Self.Top := Self.Top-1; Application.ProcessMessages; Sleep(DFT_TIME_SLEEP); end; end; tmr.Interval := DFT_TIME_VISIBLE; tmr.Enabled := True; bBeingDisplayed := True; end; procedure TfrmPopupMessage.StartAnimationToHide; var i: integer; begin if not bBeingDisplayed then Exit; for i := 1 to Self.Height+GAP do begin Self.Top := Self.Top+1; Application.ProcessMessages; Sleep(DFT_TIME_SLEEP); end; bBeingDisplayed := False; Visible := False; end; procedure TfrmPopupMessage.tmrTimer(Sender: TObject); begin tmr.Enabled := False; StartAnimationToHide(); end; function TfrmPopupMessage.GetPopupMessage: string; begin Result := lblMessage.Caption; end; procedure TfrmPopupMessage.SetPopupMessage(const Value: string); begin lblMessage.Caption := Value; end; function TfrmPopupMessage.GetPopupCaption: string; begin Result := frmPopupMessage.Caption; end; procedure TfrmPopupMessage.SetPopupCaption(const Value: string); begin frmPopupMessage.Caption := Value; end; end. To be used as in my test form with two buttons:
procedure TfrmMain.button1Click(Sender: TObject); begin DisplayPopup('Message displayed at ' + FormatDateTime('ddd mmm yy zzz', Now),'My Program'); beep; end; procedure TfrmMain.button2Click(Sender: TObject); begin DisplayPopup('Another message displayed at ' + FormatDateTime('hh:nn zzz', Now),'My Program'); end; The message form will display the application icon, but I will probably add a TImageList and add a property to pass an image index so I can display different icons. I will also use the TcxLabel from the Dev.Express components as this will provide verticle positionting, but the above unit can be used as is.
I tested this with Delphi 7 and Windows XP. If anyone uses this unit with another version of Delphi and/or Windows Vista or Windows 7, please tell me if this unit will work there too.
