Board index » delphi » Adding an item to the system menu

Adding an item to the system menu

I'm trying to add an item to the system menu of a form. It would be a simple
item that checks and unchecks itself, and of course runs some code to go
with it's click event.

The only way I've been able to do this, is to make a TMenuItem (so that I
have a unique Command value), and calling the Windows API directly with
GetSystemMenu and AppendMenu to create the item on the menu. This work to
actually put the item there, but I cannot figure out how to handle it.

The Delphi help contains an example on making a WMCommand event handler, but
how do you do this? If I were able to use this procedure, I would just check
to see if the WMCommand parameter is equal to the TMenuItem's Command
property, and take it from there.

How can I accomplish this, and is there an easier way?

An e-mail reply would be preferred, but post to Usenet if you like.

Thanks!
Steve

 

Re:Adding an item to the system menu


steve...@teleport.com (Steven M. Ziuchkovski) wrote:

Quote
>I'm trying to add an item to the system menu of a form. It would be a simple
>item that checks and unchecks itself, and of course runs some code to go
>with it's click event.
>The only way I've been able to do this, is to make a TMenuItem (so that I
>have a unique Command value), and calling the Windows API directly with
>GetSystemMenu and AppendMenu to create the item on the menu. This work to
>actually put the item there, but I cannot figure out how to handle it.
>The Delphi help contains an example on making a WMCommand event handler, but
>how do you do this? If I were able to use this procedure, I would just check
>to see if the WMCommand parameter is equal to the TMenuItem's Command
>property, and take it from there.
>How can I accomplish this, and is there an easier way?
>An e-mail reply would be preferred, but post to Usenet if you like.

Here's another tip posted to The City Zoo's Tips and Tricks Page. Hope
it helps...

-----------------------------------------------------------------------------
From: JCIRI...@physiology.uwo.ca
Subject:       Here is a Tip for Delphi
Date:          Tue, 8 Aug 1995 10:45:07 EDT

 >I just found out how to add menu items to the system menu of your
 >apps.  The following unit shows how.

unit Unit1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Menus;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
     procedure winmsg(var msg:tmsg;var handled:boolean);
     {This is what handles the messages}

     procedure DOWHATEVER;{procedure to do whatever}
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
const ItemID=99;{the ID number for your menu item--can be anything}

procedure tform1.winmsg(var msg:tmsg;var handled:boolean);
begin
  if msg.message=wm_syscommand then{if the message is a system one...}
   if msg.wparam = ItemID then DOWHATEVER;{then check if its parameter
                                           is your Menu items ID,}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  application.onmessage:=winmsg;
  {tell your app that 'winmsg' is the application message handler}

  AppendMenu(GetSystemMenu(form1.handle,false),mf_separator,0,'');
  {Add a seperator bar to form1}

AppendMenu(GetSystemMenu(form1.handle,false),mf_byposition,ItemID,
  '&New Item');
{add your menu item to form1}

AppendMenu(GetSystemMenu(application.handle,false),mf_separator,0,'');
{Add a seperator bar to the application system menu(used when app
 is minimized)}

AppendMenu(GetSystemMenu(application.handle,false),mf_byposition,
ItemID,'&New Item'
{add your menu itemto the application system menu(used when app is
 minimized)}

{for more information on the AppendMenu and GetSystemMenu see online
 help}

end;

procdure TForm2.DOWHATEVER;
begin
 {add whatever you want to this procedure}
end;

end.

---------------------------------
*            ANkH               *
*  jciri...@physiology.uwo.ca   *
---------------------------------

Michael McGaha, Programmer / Systems Analyst
webmas...@prodentec.com
The Delphi / MSSQL Client Server Classroom
http://www.prodentec.com/michaelm.htm

Re:Adding an item to the system menu


steve...@teleport.com (Steven M. Ziuchkovski) wrote:

Quote
>I'm trying to add an item to the system menu of a form. It would be a simple
>item that checks and unchecks itself, and of course runs some code to go
>with it's click event.
>The only way I've been able to do this, is to make a TMenuItem (so that I
>have a unique Command value), and calling the Windows API directly with
>GetSystemMenu and AppendMenu to create the item on the menu. This work to
>actually put the item there, but I cannot figure out how to handle it.
>The Delphi help contains an example on making a WMCommand event handler, but
>how do you do this? If I were able to use this procedure, I would just check
>to see if the WMCommand parameter is equal to the TMenuItem's Command
>property, and take it from there.
>How can I accomplish this, and is there an easier way?
>An e-mail reply would be preferred, but post to Usenet if you like.
>Thanks!
>Steve

Hi Steve

This is how you can do it:

unit Unit1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    SysMenu: HMenu;
    procedure OnSystemMenu(var Msg: TWMSysCommand); message
WM_SYSCOMMAND;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

const
  NEW_ITEM_ID = 4490;

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
     { Get System Menu Handle }
     SysMenu := GetSystemMenu(Handle, False);

     { Appending a separator }
     AppendMenu(SysMenu, MF_SEPARATOR,0, '');

     { Append another item
       ( You may of course append as many as you like) }
     AppendMenu(SysMenu, MF_UNCHECKED, NEW_ITEM_ID, 'New Item');

     { And draw the menubar }
     DrawMenuBar(Handle);
end;

procedure TForm1.OnSystemMenu(var Msg: TWMSysCommand);
begin
     { Is this our message }
     if Msg.CmdType = NEW_ITEM_ID then
        begin
             { Do your stuff }

             { CheckMenuItem returns true if checked or false if
unchecked }
             if CheckMenuItem(SysMenu, NEW_ITEM_ID, MF_BYCOMMAND) then
                begin
                     CheckMenuItem(SysMenu, NEW_ITEM_ID, MF_BYCOMMAND
or MF_UNCHECKED)
                     { Do rest of stuff if checked }
                end
             else begin
                       CheckMenuItem(SysMenu, NEW_ITEM_ID,
MF_BYCOMMAND or MF_CHECKED);
                       { Do rest of stuff if un-checked }
                  end;

             { And redraw menubar }
             DrawMenuBar(Handle);
        end
     else with Msg do
               inherited;
end;

end.

If you want to change the forms apperance, like changing the formstyle
from fsNormal to fsStayOnTop then you need to re-read the system-menu
handle.

I hope this helps

Stig

Re:Adding an item to the system menu


Quote
Steven M. Ziuchkovski wrote:

> I'm trying to add an item to the system menu of a form. It would be a simple
> item that checks and unchecks itself, and of course runs some code to go
> with it's click event.
> Steven,

You're in luck, I just solved the very same problem 3 days ago!

The good news is, it's solvable with not much code. The bad news is, you
do need the Win API.

My requirement was to make the entire "normal" menu visible or invisible
with a checkable option in the system menu. This confuses the issue a
bit, but I think you can find your way thru my code.

Here is a chunk out of my form declaration:

    procedure Statusbar1Click(Sender: TObject);
  private
    { Private declarations }
    FSysMen: HMenu;         { System menu handle }
    FCurId, FLastId: Word;  { Selected menu item IDs }
    FFKeys: Array[1..12] of TFKeyRef;
  protected
    { Protected declarations }
    procedure WMMenuSelect(var Mess: TWMMenuSelect);
              message WM_MENUSELECT;

Here is the routine which gets called when I press the MENU button or
activate the 'menu visible' item I've added to the system menu:

procedure TMainScreen.btnMenuClick(Sender: TObject);
{ This toggles the menu visible/invisible }
var
  MenuVisible: Boolean;
  j: Integer;
  MenuFlags: Word;
begin
  MenuVisible := not MainMenu1.Items[0].Visible;
  for j:=0 to MainMenu1.Items.Count - 1 do begin
    MainMenu1.Items[j].Visible := MenuVisible;
  end; { for }
  if MenuVisible then
    MenuFlags := MF_CHECKED
  else
    MenuFlags := MF_UNCHECKED;
  CheckMenuItem(FSysMen, ID_SHOWMENU, MenuFlags);
end; { btnMenuClick }

The following code is from my FormCreate() and adds the new item to the
system menu:

begin
  { Add 'Show menu' to system menu }
  FSysMen := GetSystemMenu(Handle, False);
  AppendMenu(FSysMen, MF_SEPARATOR, 0, nil);
  AppendMenu(FSysMen, MF_STRING, ID_SHOWMENU, SysMenTxt);

This routine handles the MenuSelect messages. It's a bit messy: What you
have to catch is not just a simple selection of a menu item, but a menu
exit via a click on that item. So we remember the previously selected
item and the current item (or something like that). If the current value
says we've hit RETURN and the previous one was the menu item we want to
work with, then we have a winner.

procedure TMainScreen.WMMenuSelect(var Mess: TWMMenuSelect);
begin
  FLastId := FCurId;
  FCurId := Mess.IdItem;
        (* I put in some code to show the contents of the
           message at this point while debugging.
           WARNING: Do not use a dialog to display info
           at this point. Bad things happen. Just update
           a label or something.
        *)
  if (FLastId = ID_SHOWMENU) and (FCurId = 0) then begin
    btnMenu.Click;
    Mess.Result := 0;
  end;
end; { WMMenuSelect }

There! I think I've covered most of what's relevant. Trudging in my
footsteps should give you a leg up on the problem. If not, feel free to
e-mail me back!

Carl

Re:Adding an item to the system menu


Oops!

My apologies to all who feel spammed by my lengthy response. I meant to
e-mail it!

Carl

Re:Adding an item to the system menu


Quote
Carl Smotricz <ca...@mail.ipf.de> wrote:
>My apologies to all who feel spammed by my lengthy response. I meant to
>e-mail it!

Carl, anybody who feels spammed by a useful Delphi response to a proper
Delphi question is here by mistake.

Actually, I get a whole lot more annoyed by people who ask a question for
which maybe a lot of people would like to see the answer, and then says
'email me'.

Alan

Other Threads