菜单问题,我绝望了, csdn 上没有高手(200分)

  • 主题发起人 主题发起人 IrisCat
  • 开始时间 开始时间
谢谢你,不过还不是我想要的,请你装一个 Winamp3 beta (一定要最新版本)
再看看他的任务烂按钮菜单
 
winamp没有3吧!只有2.7阿!
 
找第三方控件研究一下
 
我认为WINAMP不是用的系统菜单,也没这个必要.
你看看它的弹出方式——斜斜地弹出,有两种可能:一种是popmenu,另一种是mainmenu,只不
过设置了一个控件的menuitem属性罢了.

至少我个人认为没必要把问题想那么复杂,因为有能够做得到的途径.
 
bubble已经说了一种解决方法
还有一个就是彻底替换掉系统菜单,用自己的替代
当然是拦截消息了。[:)]
简单问题,CSDN应该不是没人会,而可能是你运气不太好吧[:D]
 
真的没人会
 
你说的我会,但用不成
 
哈哈,我也问了这个问题,但是也没有解决。
有些人总说很容易,可是我就不会呀。
VC能做到(Winamp是VC做的吧??),DELPHI也能做到吧?

http://www.delphibbs.com/delphibbs/dispq.asp?lid=1166388
 
定制任务栏上的系统菜单
云南昆明市
吴中卫
---- 通常,当我们在特定的场合或是在多应用的环境运行自己或其他的应用程序时,会在多窗口之间进行频繁的切换,以实施实时的交互得到所期望的结果,对于这样的“笨”办法,我们会不厌其烦地进行好多次,甚至是无数次。好在 Win 9x 在任务栏上显示了我们所运行或期望的程序,并配备了相应的右键系统弹出菜单,使我们在使用时方便多了。问题是那些都是缺省的系统菜单(命令),对于我们来说没有太大的帮助,下面我所介绍的就是利用 Win9x 为我们设定的任务栏系统菜单来达到快速、简捷的获取信息(执行命令)的目的。

---- 提到系统菜单,就让我们联想到底层的 WIN32 系统调用:AppendMenu、Inert-Menu、ModifyMenu。仅此三个函数,就足可以让我们对缺省的系统菜单进行定制,应用自如了。为简单起见,本文就 AppendMenu 进行一些介绍,其余的请朋友们参见 WIN32API 帮助文件。

以下是 AppendMenu 函数原型:
BOOL AppendMenu(
HMENU hMenu, // 要定制的菜单句柄
UINT uFlags, // 怎样定制菜单项
UINT uIDNewItem, // 要定制的菜单项标识或子菜单句柄
LPCTSTR lpNewItem // 要定制的菜单项(字串)
);

---- 在 AppendMenu 函数里,lpNewItem 和 uIDNewItem 参数依赖 uFlags 的不同标志而有所变化,让我们来看一看 uFlags 到底有那一些定义值:

MF_BITMAP 指明该菜单项是一位图,在 lpNewItem 参数代表位图句柄
MF_CHECKED 在菜单项的前面放上一个“选中”标记
MF_DISABLED 屏蔽该菜单项,但不象平常那样变成灰色
MF_ENABLED 与 MF_DISABLED 相反
MF_GRAYED 除了有 MF_DISABLED 的作用以外,还把该菜单项变灰
MF_MENUBREAK 把该菜单与现有菜单并排放在一起
MF_MENUBARBREAK 与 MF_MENUBREAK 相同,除了在中间放一条竖线外
MF_OWNERDRAW 表明该菜单项为自绘菜单项,还必须处理一切的显示、更新
问题
MF_POPUP 该菜单项为一子菜单,uIDNewItem 参数代表其句柄
MF_SEPARATOR 与上一菜单项画上一分割线,系统将忽略 lpNewItem 和
uIDNewItem 参数
MF_STRING 该菜单项是一文本字串,lpNewItem 是其内容
MF_UNCHECKED 取消该菜单项前面的“选中”标记

---- 我们看到,除了 MF_POPUP,MF_BITMAP,MF_OWNERDRAW 以外,MF_STRING 是最常用的菜单项定义方法,uIDNewItem 在这里是命令消息的 wParam 参数。朋友们还记得获取普通菜单的句柄用 GetMenu, 那么获取系统菜单的句柄就应该用 GetSyst-emMenu。这时有一个问题:程序怎么知道该获取的系统菜单是窗口上的系统菜单,还是任务栏上的系统菜单呢?这就依靠传递给 GetSystemMenu 的是哪一个参数。因为我们当前考虑的是任务栏,因此这个参数就必须是 Application.Handle。
---- 如果这时候就着手编制一个 Project 检验一下,朋友们就会发现...“我”定义的菜单怎么没有反应!原来该菜单项根本没有在 Application 里处理过。显然,我们还得过滤一下传到 Application 的 WM_SYSCOMMAND 消息。

---- 为了加深了解,我们首先追加一个简单的任务栏系统菜单:

Unit AddMenuDemo;
interface

uses Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms,
Dialogs,Menus;

type
TDemoForm = class(TForm)
procedure FormCreate(Sender: TObject);
...
private
{ Private declarations }
// 我的消息过滤器
procedure OnAppMessage
(var Msg: TMsg; var Handled: Boolean);
...
public
{ Public declarations }
...
end;

var
DemoForm1: TDemoForm;

implementation

const
My_SimpleCMD1 = WM_USER + 1;
// 定义三个用户消息,用来处理菜单项被点击

// 时相应的动作
My_SimpleCMD2 = WM_USER + 2;
My_SimpleCMD3 = WM_USER + 3;
...

procedure TDemoForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnAppMessage;
//定义自己的消息处理过程

//定义了提交、反馈、处理三个菜单项
AppendMenu(GetSystemMenu
(Application.Handle, FALSE),MF_STRING,
My_SimpleCMD1,'提交');
AppendMenu(GetSystemMenu
(Application.Handle, FALSE),MF_STRING,
My_SimpleCMD2,'反馈');
AppendMenu(GetSystemMenu
(Application.Handle, FALSE),MF_SEPARATOR,
0, ''); // 定义一分割线
AppendMenu(GetSystemMenu
(Application.Handle, FALSE),MF_STRING,
My_SimpleCMD3,'处理');
end;

procedure TDemoForm1.OnAppMessage
(var Msg: TMsg; var Handled: Boolean);
begin
// 定制自己的消息处理过程
if (Msg.message = WM_SYSCOMMAND) and
(Msg.wParam = My_SimpleCMD1) then
begin
ShowMessage('正在提交...');
Handled := True;
...
end;
if (Msg.message = WM_SYSCOMMAND) and
(Msg.wParam = My_SimpleCMD2) then
begin
ShowMessage('正在反馈...');
Handled := True;
...
end;
if (Msg.message = WM_SYSCOMMAND) and
(Msg.wParam = My_SimpleCMD3) then
begin
ShowMessage('正在处理...');
Handled := True;
...
end;
end;
....

---- 当我们处理的事务比较多并且可分组,以上的做法就比较烦琐,这时就应该定义成多个 MF_POPUP ,其各个子菜单除了 uIDNewItem 传递这个子菜单的句柄外,另外独特之处在于消息过滤器的 Msg.wParam 是各个菜单项的 Command。这个 Command是在构建 TPopupMenu 时就定义了的。无论是否是 MenuItem 或 PopupMenu,其Command的值都是顺序递增的。以下是一范例:

unit Unit1;

interface

uses Windows, Messages, SysUtils,
Classes, Graphics, Controls, Forms,
Dialogs, Menus;

type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
N1: TMenuItem; // Caption := '范例一';
N2: TMenuItem; // Caption := '范例二';
N3: TMenuItem; // Caption := '范例三';
procedure FormCreate(Sender: TObject);
...
private
{ Private declarations }
// 我的消息过滤器
procedure OnAppMessage
(var Msg: TMsg; var Handled: Boolean);
...
public
{ Public declarations }
...
end;
...

var
Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnAppMessage;
//定义自己的消息处理过程

// 定义一分割线
AppendMenu(GetSystemMenu(Application.Handle,
FALSE), MF_SEPARATOR, 0, '');

// 定义'提交'子菜单
AppendMenu(GetSystemMenu
(Application.Handle, FALSE), MF_POPUP,
PopupMenu1.Handle,'提交');
end;

procedure TForm1.OnAppMessage
(var Msg: TMsg; var Handled: Boolean);
begin

// 定制自己的消息处理过程
if (Msg.message = WM_SYSCOMMAND)
AND (Msg.wParam < WM_USER) then
begin
Case Msg.wParam of
// N1.Command = 1
1:ShowMessage
('范例一 Command:'+ IntToStr(N1.Command));
// N1.Command = 2
2:ShowMessage
('范例二 Command:'+ IntToStr(N2.Command));
// N1.Command = 3
3:ShowMessage
('范例三 Command:'+ IntToStr(N3.Command));
end;
Handled := True;
end;
...
end;


---- 可以看出,MF_STRING 与 MF_POPUP 在消息处理机制上是稍微有点不同的,另外如果要在菜单前面加上图标的话,这在 Delphi 4.x、Delphi 5.x 版本下是不成问题,如果是在 Delphi 3.x 下的话,只要定义成自绘 MenuItem 即可,不过稍许复杂了一点。在应用过程中,需要提醒的是,这几组定义是不能一起使用:
* A. MF_DISABLED, MF_ENABLED, 和 MF_GRAYED
* B. MF_BITMAP, MF_STRING, 和 MF_OWNERDRAW
* C. MF_MENUBARBREAK 和 MF_MENUBREAK
* D. MF_CHECKED 和 MF_UNCHECKED
 
对于这个问题,我也问了多次。具体请看以下网址:
http://www.csdn.net/Expert/TopicView1.asp?id=825020
http://delphibbs.com/delphibbs/dispq.asp?lid=1178788

很高兴,现在问题终于解决了。
请看以下DEMO。
http://www.lkgarden.com/lfpsoft/index.zip

如果对此问题有兴趣的话请与我联系。lfpsoft@163.com
 
to lfpsoft,呵呵,你按Alt+空格,实验一下。
 
呵呵,这里主要是对任务栏的操作。
Alt+空格不是主要问题,不过也是我的考虑不周。
现在改了。请大家试试看还有没有其他问题。
谢谢!
http://www.lkgarden.com/lfpsoft/index.zip
 
来自:IrisCat, 时间:2001-12-21 23:03:00, ID:803519
-_-
哪里都一样

这样的话不太好听。
楼上给你的回答还满意么?
这样的例子很多。

用到了2个部分,一个是动态修改并加载自己的菜单到系统菜单,一个是隐藏窗口标题关闭菜单,使用自己定义的菜单。
 
我写的类似功能控件可以将POPMEMU加到系统菜单上,你参考一下!

unit SystemMenu;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,MenuS;

type
TSystemMenu = class(TComponent)
private
{ Private declarations }
Factive :Boolean ;
FpopupMenu :TPopupMenu ;
FWnd :HWND ;
Fmenu :HMENU ;
FoldWinProc:FARPROC ;
FNewWinProc:FARPROC ;
procedure AppendMenuToSysmenu();
procedure DeleteMenuFrSysmenu();
procedure SetActive(value :Boolean );
procedure SetPopMenu(value:TPopupMenu );
procedure _SysCommand(var Message :TMessage);
protected
{ Protected declarations }
procedure WndProc(var Message: TMessage);
procedure Loaded;override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy ;override;
procedure Open;
procedure Close;
published
{ Published declarations }
property Active : Boolean Read Factive Write SetActive;
property PopMenu: TPopupMenu Read FPopupMenu Write SetPopMenu;
end;

procedure Register;

implementation


{TsystemMenu}

constructor TSystemMenu.Create (AOwner :TComponent);
begin
inherited;
if (Owner is TForm ) then
begin
FWnd := (Owner as TForm) .Handle ;
Fmenu := GetSystemMenu (FWnd ,False );
FoldWinProc := pointer(GetWindowLong (FWnd ,GWL_WNDPROC));
Factive := False ;
end
else
begin
Raise Exception .Create ('The owner muse be TForm!');
end;
end;

destructor TSystemMenu.Destroy ;
begin
Close ;
inherited Destroy ;
end;

procedure TSystemMenu.WndProc(var Message: TMessage);
begin
with Message do
begin
case Msg of
WM_SYSCOMMAND : _SysCommand( Message );
else
Result := CallWindowProc(FoldWinProc , FWnd , Msg, wParam, lParam);
end;
end;
end;


procedure TSystemMenu._SysCommand (var Message :TMessage);
var
i:Byte ;
begin
with TWMCOMMAND(Message) do
begin
for i:= 0 to FpopupMenu .Items .Count - 1 do
if TWMCOMMAND(Message).ItemID = FpopupMenu .Items .Command then
begin
FpopupMenu .Items .Click ;
end;
end;
CallWindowProc(FoldWinProc , FWnd ,Message. Msg,Message . wParam,Message .lParam);
end;

procedure TsystemMenu.AppendMenuToSysmenu ();
var
i:Integer ;
begin

for i:=0 to FpopupMenu .Items .Count - 1 do
begin
AppendMenu (FMenu ,MF_BYPOSITION ,i+1,
PCHAR(FpopupMenu .Items .Items .Caption ));
end;
DrawMenuBar (FWnd );
end;

procedure TsystemMenu.DeleteMenuFrSysmenu ;
var
i:Integer ;
begin
for i:=0 to FpopupMenu .Items .Count - 1 do
begin
DeleteMenu(Fmenu ,i+1,MF_BYCOMMAND );
end;
DrawMenuBar (FWnd );
end;

procedure TsystemMenu.SetPopMenu (Value :TPopupMenu);
begin
FpopupMenu := value ;
end;

procedure TSystemMenu.SetActive(value :Boolean );
begin
if FActive <> Value then
begin
FActive := Value;
if FActive then
begin
if Assigned(FPopupMenu) then
begin
AppendMenuTosysmenu();
Factive := value ;
FNewWinProc := MakeObjectInstance (WndProc );
FoldWinProc := pointer(GetWindowLong (FWnd ,GWL_WNDPROC ));
SetWindowLong(FWnd , GWL_WNDPROC, LongInt(FNewWinProc));
end;
end else begin
if Assigned(FPopupMenu) then
begin
DeleteMenuFrSysmenu() ;
Factive := value ;
SetWindowLong(FWnd , GWL_WNDPROC, LongInt(FoldWinProc ));
FreeObjectInstance(FNewWinProc);
end;
end;
end;
end;
{
procedure TSystemMenu.SetActive(value :Boolean );
begin
if (value = True) and ( Factive = False ) then
begin
if FpopupMenu <> nil then
begin
AppendMenuTosysmenu();
Factive := value ;
FNewWinProc := MakeObjectInstance (WndProc );
FoldWinProc := pointer(GetWindowLong (FWnd ,GWL_WNDPROC ));
SetWindowLong(FWnd , GWL_WNDPROC, LongInt(FNewWinProc));
end;
end;
if (Value = False) and ( Factive = True ) then
begin
if FpopupMenu <> nil then
begin
DeleteMenuFrSysmenu() ;
Factive := value ;
SetWindowLong(FWnd , GWL_WNDPROC, LongInt(FoldWinProc ));
FreeObjectInstance(FNewWinProc);
end;
end;
end;
}
procedure TSystemMenu.Open ;
begin
SetActive (True);
end;

procedure TsystemMenu.Close ;
begin
SetActive (False);
end;

procedure TSystemMenu.Loaded;
begin
inherited;
if Active then
begin
FActive := False; //直接赋值
Active := True;
end;
end;

procedure Register;
begin
RegisterComponents('Samples', [TSystemMenu]);
end;

end.
 
自己看吧
********************************************************************************
①、 如 何 把 用 户 菜 单 项 加 入 系 统
菜 单, ②、 如 何 才 能 响 应 这 一 菜 单 项。

---- 要 解 决 第 一 个 问 题, 就 需 要 获 取 系 统 菜 单 的 句 柄, 这 一 点 可 用 API 函 数
getsystemmenu() 来 获 取(getmenu() 只 能 获 取 用 户 菜 单 句 柄), 有 了 系 统 菜 单 句 柄, 便
可 以 用 API 函 数appendmenu() 向 系 统 菜 单 中 加 入 用 户 菜 单 选 项 了。

---- 要 解 决 第 二 个 问 题, 需 要 重 载 WM_SYSCOMMAND 或WM_MENUSELECT 消 息。 我 们
知 道, 当 用 户 从 菜 单 中 选 一 项 时, 系 统 便 会 发 出 WM_COMMMAND 消 息, 而 对
于 系 统 菜 单, 则 会 发 出 WM_SYSCOMMAND 消 息, 重 载 这 个 消 息, 并 判 断 选 中 菜
单 的 ID 值 是 否 为 用 户 设 定 值 便 可 以 了。Delphi 为 我 们 提 供 了 这 方 面 的 机 制, 使
我 们 能 方 便 的 实 现 这 一 功 能。 当 然, 为 实 现 这 一 功 能 我 们 还 可 以 利 用 子 类
或 为 系 统 加 消 息 钩 子 的 方 法 来 解 决。

---- 为 了 便 于 实 现, 在 这 里, 我 们 采 用 重 载 WM_SYSCOMMAND 消 息 和 填 写
WM_MENUSELECT 消 息 结 构 的 方 法 来 实 现 这 一 功 能。

---- 下 面 为 笔 者 为 实 现 这 一 功 能 而 开 发 的 实 例。

---- 程 序 在Delphi ver 1.0 下 调 试 通 过。


program Psysmenu;
uses
Forms,
Sysmenu in '/SYSMENU.PAS' {Form1};

{$R *.RES}
begin
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

unit Sysmenu;

interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes,
Graphics, Controls,Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure user_sysmenu(var msg:twmmenuselect);
message wm_syscommand;

public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}

procedure TForm1.user_sysmenu(var msg:TWMMENUSELECT);
begin
if msg.iditem=100 then
showmessage(' 响应系统菜单!')
{ 也 可 以setwindowpos()来实现处于最前端功能}
else
inherited; { 作缺省处理,必须调用这一过程}
end;

procedure TForm1.FormCreate(Sender: TObject);
var hmenu:integer;
begin
hmenu:=getsystemmenu(handle,false);
{获取系统菜单句柄}
appendmenu(hmenu,MF_SEPARATOR,0,nil);
appendmenu(hmenu,MF_STRING,100,'加入系统菜单');
{加入用户菜单}
end;
end.
////////////////////////////////////////////////////
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

const
SC_MyMenuItem = WM_USER + 1;

procedure TForm1.FormCreate(Sender: TObject);
begin
AppendMenu(GetSystemMenu(Handle, FALSE), MF_SEPARATOR, 0, '');
AppendMenu(GetSystemMenu(Handle, FALSE),
MF_STRING,
SC_MyMenuItem,
'My Menu Item');
end;

procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType = SC_MyMenuItem then
ShowMessage('Got the message') else
inherited;
end;
////////////////////////////////////////////////////////
这个过程可以:
procedure AppendToSystemMenu (Form: TForm;
Item: string; ItemID: Word);
{----------------------------------------------------------------}
{ Appends menu item to end of system menu of specified form and }
{ to system menu of application's minimized icon. To append a }
{ separator bar start the item with '-' (and use 0 for ItemID). }
{----------------------------------------------------------------}
var
NormalSysMenu, MinimizedMenu: HMenu;
AItem: array[0..255] of Char;
PItem: PChar;
begin
NormalSysMenu := GetSystemMenu(Form.Handle, false);

MinimizedMenu := GetSystemMenu(Application.Handle, false);
if StartsWith('-', Item) then
AppendMenu(NormalSysMenu, MF_SEPARATOR, 0, nil);
AppendMenu(MinimizedMenu, MF_SEPARATOR, 0, nil);
end
else
begin
PItem := StrPCopy(PChar(@AItem), Item);
AppendMenu(NormalSysMenu, MF_STRING, ItemID, PItem);
AppendMenu(MinimizedMenu, MF_STRING, ItemID, PItem);
end
end; {AppendToSystemMenu}
过程是如下定义:
function StartsWith (const StartString, theString: string)

: Boolean;
{-----------------------------------------------------------------}
{ Tests whether or not theString starts with the StartString. }
{ N.B. Case sensitive. }
{----------------------------------------------------------------}
begin
if Copy(theString, 1, length(StartString)) = StartString then
StartsWith := True
else
StartsWith := False
end; {StartsWith}
建立新FORM
type
TForm1 = class(TForm)
private
{ Private declarations }
public
procedure WinMsgHandler( var Msg : TMsg; var Handled : Boolean );

{ Public declarations }
end;
const
WM_ABOUT = WM_USER + 1; { About message }
IMPLEMENTATION
procedure TForm1.WinMsgHandler( var Msg : TMsg; var Handled : Boolean );
begin
If Msg.Message = WM_SYSCOMMAND then begin
if Msg.wParam = WM_ABOUT then Showmessage('Hello World!!');
end;
end;
你必须在窗体中加入以下方法:
Application.OnMessage := WinMsgHandler; {Use my message handler}
AppendMenu( GetSystemMenu( Self.Handle, False ),
MF_SEPARATOR, 0, ''); {Append our new value}
AppendMenu( GetSystemMenu(
rm1.FormCreate(Sender: TObject);

begin
AppendMenu(GetSystemMenu(Handle, False), { API call; see API Help }
MF_STRING, SC_UDF, '&About');
AppendMenu(GetSystemMenu(Application.Handle, False),
MF_STRING, SC_UDF, '&About');
Application.OnMessage := AppOnMessage;
end;
procedure TForm1.AppOnMessage(VAR Msg: TMsg; VAR Handled: BOolean);
VAR
Hf, Ha : hMenu;
Checkd : Boolean;
CONST
NuFlag : ARRAY[Boolean] OF Word = (MF_CHECKED, MF_UNCHECKED);
NuHWnd : ARRAY[Boolean] OF HWnd = (HWND_TOPMOST, HWND_NOTOPMOST);
BEGIN
IF Msg.Message WM_SYSCOMMAND THEN Exit;

IF Msg.wParam AND $FFF0 SC_UDF THEN Exit;
{ show your About Dialog }
END;
end.
 
后退
顶部