How to display a message window in the right bottom corner of the active display using Delphi
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 = al开发者_如何学运维Left
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.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
function 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);
Result := TBRect.Bottom - TBRect.Top;
end;
end;
begin
Self.Left := Screen.Width - Self.Width;
Self.Top := Screen.Height-Self.Height-TaskBarHeight;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
TimeSleep: integer;
begin
TimeSleep := 5; // the speed you want to show/hide.Increase/descrease this to make it faster or slower
for i := 1 to Self.Height do
begin
Self.Top := Self.Top+1;
Sleep(TimeSleep);
end;
// now let's show it again(use this as code as the show code)
for i := 1 to Self.Height do
begin
Self.Top := Self.Top-1;
Sleep(TimeSleep);
end;
end;
end.
via http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_25043483.html
Try using the TJvDesktopAlert component wich is included in the JVCL, you can find an example in jvcl\examples\JvDesktopAlert\JvDesktopAlertDemo.dpr
(source: agnisoft.com)
What you are searching for are Balloon Tips in a System Tray. For general WinAPI here's a nice tutorial for it, that you shouldn't have problems translating to Delphi.
You can find some ready to use code for balloon tips in Delphi here.
A nice implementation is available here.
You can check where is Taskbar:
uses ShellAPI;
//...
Var AppBar: TAppbarData;
//...
begin
FillChar(AppBar, sizeof(AppBar), 0);
AppBar.cbSize := Sizeof(AppBar);
if ShAppBarMessage(ABM_GETTASKBARPOS, AppBar) <> 0 then
begin
//AppBar.rc is TRect
end;
end;
And then show your form...
You could use Growl for Windows - I don't think there is a Delphi library for it yet, but you can control it via UDP messages, so any network library should do.
TMsnPopUpNotify
http://www.torry.net/vcl/forms/appearence/tmsnpopup.zip
Check out Snarl, similar to Growl for Windows, but I have found to be better. There is a Pas file to easily interface, and the way it works is very simple, with just sending windows messages.
http://fullphat.net/
It also allows the end user some amount of control of which messages to see, duration before fading, etc.
精彩评论