I try to use trayicon in delphi 5, but I can't hide the main form completely as which contain a MDI child form. Any solution for it? :(
Duoas 1,025 Postaholic Featured Poster
I've not messed with MDI forms much, but when you create your mainform you have to modify some of the application's system window properties.
procedure FormCreate(...);
begin
exstyle := getWindowLong( application.hanle, GWL_EXSTYLE )
end;
procedure FormShow(...);
begin
setWindowLong( application.handle, GWL_EXSTYLE, exstyle )
end;
procedure FormHide(...);
begin
setWindowLong( application.handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW )
end;
The exstyle should be a cardinal variable somewhere.
Now the window will not appear in the taskbar whenever it is hidden. If you never want it in the taskbar then forget the show and hide stuff and just set the exstyle to toolwindow in the create event.
Hope this helps.
csy 0 Light Poster
Dear friend, thanks for reply! I've try your advice, but the result same.
After closed the main form, taskbar should be nothing only trayicon there. However the main form still in taskbar as which contain a MDI child form (I've tried to take out the child form then result OK :the taskbar show nothing ).
Any advice? :( :(
My FormClose coding about :
procedure TFrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
hide;
end;
Duoas 1,025 Postaholic Featured Poster
I'm afraid I've never used the trayicon component, but a lot of these inject code into your application's or main form's constructor. Make sure that isn't happening.
If the problem is one of MDI then you'll have to wait until I mess around with it to figure out why...
(I use my Delphi 5 IDE for everything. Best IDE ever as far as I'm concerned...)
Give me a day or two and if you (or someone else) haven't figured it out by then I'll post a more comprehensive response.
Sorry I couldn't be of more help in the meantime...
csy 0 Light Poster
Thank you so much! thanks for your willing help!! :D
Duoas 1,025 Postaholic Featured Poster
Me again. I just made an MDI that lives in the System Tray without any trouble (~30 min). My only guess is that the trayicon component is doing something that is messing you up. So... here's what I can do for you.
How to put your application in the system tray using Delphi 5.
File: SystemTray.pas
unit SystemTray;
interface
uses Windows;
const
WM_ICONTRAY = WM_USER +1;
NIM_ADD = 0;
NIM_MODIFY = 1;
NIM_DELETE = 2;
NIF_MESSAGE = $00000001;
NIF_ICON = $00000002;
NIF_TIP = $00000004;
NIF_STATE = $00000008;
NIF_INFO = $00000010;
NIF_GUID = $00000020;
type
tNotifyIconData = record
size: cardinal;
wnd: THANDLE;
ID: cardinal;
flags: cardinal;
callbackMessage: cardinal;
icon: HICON;
tip: array[ 0..63 ] of char;
end;
function Shell_NotifyIcon( message: cardinal; var pnid: tNotifyIconData ): BOOL;
stdcall; external 'shell32.dll' name 'Shell_NotifyIcon';
implementation
end.
File: MAIN.pas
unit Main;
interface
uses
..., SystemTray; // add the new unit to the end of your uses clause
type
TMainForm = class(TForm)
...
private
// used when hiding the application from the taskbar
f_ExStyle: cardinal;
// used to add the application's icon to the system tray
f_TrayIconData: tNotifyIconData;
...
public
procedure TrayMessage( var msg: tMessage ); message WM_ICONTRAY;
...
end;
implementation
...
procedure TMainForm.FormCreate(Sender: TObject);
begin
// remember the proper display mode for the application
f_ExStyle := getWindowLong( application.handle, GWL_EXSTYLE );
// add the application icon to the system tray
with f_TrayIconData do begin
size := sizeof( tNotifyIconData );
wnd := handle;
ID := 0;
flags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
callbackMessage := WM_ICONTRAY;
icon := application.icon.handle;
strpcopy( tip, copy( application.title, 1, 63 ) )
end;
Shell_NotifyIcon( NIM_ADD, f_TrayIconData )
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
// remove the application icon from the system tray
Shell_NotifyIcon( NIM_DELETE, f_TrayIconData )
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
// add the application to the taskbar if visible
setWindowLong( application.handle, GWL_EXSTYLE, f_ExStyle )
end;
procedure TMainForm.FormHide(Sender: TObject);
begin
// remove the application from the taskbar if hidden
setWindowLong( application.handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW )
end;
procedure TMainForm.TrayMessage( var msg: tMessage );
begin
// show the form if the user left-clicks the tray icon
if msg.lParam = WM_LBUTTONDOWN then show
end;
...
end.
Now, a Delphi MDI application by default uses tMainForm.close to terminate, so if you want to capture the system menu close event (clicking the [X] button on the titlebar or chosing "Close" from the application's system menu or pressing Alt+F4) you'll have to account for actual attempts to terminate the application in the FormCanClose method. Personally, I like the way ZoneAlarm AntiVirus does it. If you click the [X] button it pops up a dialogue asking whether you really want to terminate or just to minimize to the system tray, and remembers the response. If you select minimize it gives you another dialogue with instructions on how to actually terminate the application.
Well, that's it.
Hope this helps.
csy 0 Light Poster
Thanks friend.
As the example, I need to custom the trayicon component, right?
I'll try it!:idea:
What my application request is :
At the starting only tray icon , after click the tray icon, the form display, after press the [x] to close the form, the form hidden but tryicon still fuction, only right click the trayicon and select the "terminate" the application will be terminate completly.
But I tried quite a long time still can't make the application hide completely (still display in task bar) as MDI child form. :'(
Duoas 1,025 Postaholic Featured Poster
Don't give up yet. I failed to account for the MDI child forms.
The icon/button you see on the taskbar actually belongs to the application, and not the main form. So if you have any windows other than the main form open (you can't hide a MDI child form) the application button will automagically appear on the taskbar.
The trick is to get rid of the application button and put the main form's button on the taskbar instead.
Like I said, I haven't played much with MDI applications before so I've had to learn some stuff to help. I'm cleaning up my code now. Give me another day or two and I'll post an example that does everything you want (and then some) with full source code you can scavenge as you like.
csy 0 Light Poster
Thanks your encourage.:)
Here is my simple testing :
File: ChildForm.pas
unit ChildForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm2 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.DFM}
end.
File: MainForm.pas
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
TrayIcon, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
TrayNotifyIcon1: TTrayNotifyIcon;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TrayNotifyIcon1DblClick(Sender: TObject);
procedure TrayNotifyIcon1Click(Sender: TObject);
private
{ Private declarations }
procedure createchildform;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses ChildForm;
{$R *.DFM}
procedure TForm1.createchildform ;
var tempChildForm : TForm2;
begin
try
tempChildForm := TForm2.Create(Self);
tempChildForm.FormStyle := fsMDIChild ;
finally
end;
end ;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
try
createchildform ;
Finally
End ;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TrayNotifyIcon1.IconVisible := True;
end;
procedure TForm1.TrayNotifyIcon1DblClick(Sender: TObject);
begin
show ;
end;
procedure TForm1.TrayNotifyIcon1Click(Sender: TObject);
begin
hide;
end;
end.
I'd set Application.ShowMainForm := False before application run.
Duoas 1,025 Postaholic Featured Poster
Time enough has passed that I haven't answered here.
As I mentioned already, the reason you see a button on the taskbar is because the application puts it there. Your forms don't. You can see this by going to the main menu --> Project --> Options --> Application --> Title and giving your application a title that differs from the main form's caption. The button on the taskbar will show the application title, and not the mainform caption.
When you have MDI children, which cannot be hidden, the application button is restored to the taskbar because you technically still have windows showing... even if the MDI main form is hidden.
So, to get rid of it you have to turn it off explicitly. In MAIN.pas, make sure you have the following:
interface
type
TMainForm = class(TForm)
procedure ApplicationActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
private:
procedure SysCommandMessage(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
protected:
procedure CreateParams(var Params: TCreateParams); override;
end;
implementation
procedure TMainForm.ApplicationActivate( Sender: TObject );
begin
// Remove the application button from the taskbar
// (and make sure it stays that way)
ShowWindow( Application.Handle, SW_HIDE )
end;
procedure TMainForm.FormCreate( Sender: TObject );
begin
// Keep the application button out of the taskbar
application.OnActivate := ApplicationActivate
end;
procedure TMainForm.SysCommandMessage(var Msg: TWMSysCommand);
begin
// Routing WM_SYSCOMMAND messages through here instead of the default
// handler prevents Delphi from trying to create a taskbar button for the
// application when minimized and maximized, which when combined with
// ApplicationActivate would otherwise cause flicker.
//
// You could capture the SC_MINIMIZE command here and instead hide the
// window, but you would have to make sure to let the user know that the
// window was minimized to the system tray. Otherwise it will look like the
// window just disappeared...
//
// You could also remove biMinimize and biMaximize from the mainForm's
// BorderIcons, and trap the SC_MINIMIZE button to do nothing... For
// example:
// if msg.CmdType <> SC_MINIMIZE then defaultHandler( msg )
//
defaultHandler(Msg)
end;
procedure TMainForm.CreateParams(var Params: TCreateParams);
begin
// Add the main form's window button to the taskbar
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow
// If I understand things correctly, if you comment out the last line then
// when you manipulate the window (say, restore it) other toplevel windows
// belonging to the application will also be affected (say, restored). But
// since this is an MDI application you shouldn't have any other toplevel
// windows... And I haven't played around with this any...
end;
If you insert this code into your main form you will get the taskbar button response you want. Weird stuff, huh?
I'll post back in a few days more with a fairly interesting example (I've been having fun with it, but my simple object pascal syntax highlighter needs a little more work...) which comes with all its own source code and demonstrates all kinds of weird things, such as how to make an application mutex to prevent multiple instances of the application from running at the same time, tray icon popup menus and animations, using XP style controls if available, etc.
csy commented: Helpful +1
csy 0 Light Poster
Yeah! Hide succesfull ~~ ^o^
Thanks & Thanks~~
if you are around I must treat you a lunch...haha
really help me a lot ~ :D
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.