如何创建一个无焦点窗口 如题类似photoshop的工具窗口,它是独立于主窗口的,有句柄,类名PSFloatC 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 给窗体的 GWL_STYLE, 或 GWL_EXSTYLE 加上 WS_EX_NOACTIVATE 回楼上,那样窗体上的东西全部不能用了photoshop工具窗口上的工具是可以点的,点了原来窗口上的焦点不会丢失. 一个障眼法:procedure TForm2.FormActivate(Sender: TObject);begin SendMessage(Application.MainForm.Handle, WM_NCACTIVATE, Integer(True), 0);end; 楼上的放一个speedbutton放form2上再点点看...... 哈终于完成了,参考如下代码:unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type TFloatWnd = class(TForm) private procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE; procedure FormClose(Sender: TObject; var Action: TCloseAction); public constructor CreateEx(AOwner: TComponent; CFrame: TWinControlClass); procedure ShowAt(X, Y: Integer); end; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE; end;var Form1: TForm1;implementationuses Unit2;{$R *.dfm}{ TFloatWnd }constructor TFloatWnd.CreateEx(AOwner: TComponent; CFrame: TWinControlClass);begin inherited CreateNew(AOwner); AutoSize := True; FormStyle := fsStayOnTop; BorderStyle := bsToolWindow; with CFrame.Create(self) do Parent := Self; OnClose := FormClose;end;procedure TFloatWnd.FormClose(Sender: TObject; var Action: TCloseAction);begin Action := caFree;end;procedure TFloatWnd.ShowAt(X, Y: Integer);begin Left := X; Top := Y; Show;end;procedure TFloatWnd.WMActivate(var Message: TWMActivate);var i: Integer;begin for i := 0 to Screen.FormCount - 1 do if Screen.Forms[i].Handle <> Handle then SendMessage(Screen.Forms[i].Handle, WM_NCACTIVATE, Ord(Message.Active <> WA_INACTIVE), 0);end;procedure TForm1.Button1Click(Sender: TObject);var FloatWnd: TFloatWnd;begin FloatWnd := TFloatWnd.CreateEx(Self, TFrame2); FloatWnd.ShowAt(Left + 10, Top + 20);end;procedure TForm1.WMActivate(var Message: TWMActivate);var i: Integer;begin for i := 0 to Screen.FormCount - 1 do if Screen.Forms[i].Handle <> Handle then SendMessage(Screen.Forms[i].Handle, WM_NCACTIVATE, Ord(Message.Active <> WA_INACTIVE), 0);end;end. unit Unit2;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons;type TFrame2 = class(TFrame) SpeedButton1: TSpeedButton; SpeedButton2: TSpeedButton; SpeedButton3: TSpeedButton; SpeedButton4: TSpeedButton; BitBtn1: TBitBtn; BitBtn2: TBitBtn; Edit1: TEdit; Edit2: TEdit; private { Private declarations } public { Public declarations } end;implementation{$R *.dfm}end. Toolbar2000就做得很好,楼主可以去下载来参考一下,事实上上面的代码也参考了Toolbar2000中的一些代码的。建一个工程试试看效果吧,反正我试了一下觉得还可以。 http://www.delphibbs.com/keylife/iblog_show.asp?xid=965IME类是实现IME用户界面部分的预定义全局窗口类。“IME”类与预定义的公共控制窗口类有许多相同的特点,IME窗口实例与静态控制一样通过CreateWindowEx函数创建,IME类窗口自己不响应用户输入,取而代之的是接收不同类型的控制消息实现全部IME用户接口。应用程序可以使用IME类创建自己的IME窗口,还可以使用ImmGetDefaultIMEWnd函数获取缺省IME窗口。 TO linzhengqun(风。我回来了) 你的程序....只是让窗口看起来和主窗口同时激活,而实际上它还是会抢去其它窗口的焦点,比如主窗口上有个edit,焦点在edit上时点你的窗口,edit会失去焦点,而我要的效果是不失去焦点!toolbar2000的代码我看了半天还没找到他是怎么实现的,它的工具窗口是不会抢焦点的,除非工具窗口里有可以获得焦点的控件TO aiirii: 不会创建一个无焦点窗口一定要用IME接口吧? 好吧,你研究一下TB2Dock单元的TTBFloatingWindowParent类吧,它应该就是所有浮动窗口的外壳。 我记得 CreateWindowex 有一个参数可以设置,但一时没找到 CreateWindowex 好象没有哪个参数可以实现这样的功能.....试着把TTBFloatingWindowParent从toolbar2000分离出来,没成功:(好象子类还实现了一些功能,分离出来后建立一个实例Show不出来 createwindowEx用WS_EX_TOOLWINDOW 就OK啦 输入法的窗口为什么不会得到“焦点”呢?因为它是一个“禁用”的窗口!在建立窗口的时候指定WS_DISABLED风格或事后EnableWindow()都可以的,那么这个窗口如何响应鼠标动作呢?答案是利用WM_SETCURSOR消息……… 这是我写的一个输入法状态条窗口:unit Unit_Stat;interfaceuses Windows;function StatusWndProc(hStatWnd: hWnd; uMsg: uInt; wParam: WParam; lParam: LParam): LResult; stdcall;function RegisterStatClass(): Bool;function CreateStatWindow(hUIWnd: hWnd): hWnd;implementationuses Messages, Unit_Class, Unit_Bmp, Unit_Public; // Stat窗口回调function StatusWndProc(hStatWnd: hWnd; uMsg: uInt; wParam: WParam; lParam: LParam): LResult; stdcall;const {$J+} OldPoint: TPoint = (X: 0; Y: 0); {$J-} // 每次只可能"拖拽"一个状态条, 所以只用一个全局变量就够了..var pCurStat: PStatus; hStatDC: HDC; ps: TPaintStruct; StatRect, ScreenRect: TRect; CurPoint: TPoint;begin case (uMsg) of WM_CREATE: begin GetMem(pCurStat, SizeOf(TStatus)); SetWindowLong(hStatWnd, 0, Integer(pCurStat)); if (pCurStat = nil) then Result := -1 else begin pCurStat.Chinese := True; pCurStat.FullShape := False; pCurStat.Symbol := False; Result := 0; end; end; WM_DESTROY: begin pCurStat := PStatus(GetWindowLong(hStatWnd, 0)); if (pCurStat <> nil) then FreeMem(pCurStat); Result := 0; end; WM_PAINT: begin hStatDC := BeginPaint(hStatWnd, ps); pCurStat := PStatus(GetWindowLong(hStatWnd, 0)); if (pCurStat <> nil) then DrawStatus(hStatDC, pCurStat^); EndPaint(hStatWnd, ps); Result := 0; end; WM_SETCURSOR: begin if (HiWord(lParam) = WM_LBUTTONDOWN) then begin SetCursor(LoadCursor(0, IDC_HAND)); pCurStat := PStatus(GetWindowLong(hStatWnd, 0)); GetCursorPos(CurPoint); ScreenToClient(hStatWnd, CurPoint); case ButtonPos(CurPoint) of 0: begin // 麻子头像 end; 1: begin // 单拼字样 SetCursor(LoadCursor(0, IDC_SIZEALL)); GetCursorPos(OldPoint); SetCapture(hStatWnd); // 接收鼠标消息 end; 2: begin // 全角半角 if (pCurStat <> nil) then begin pCurStat.FullShape := not pCurStat.FullShape; InvalidateRect(hStatWnd, nil, True); end; end; 3: begin // 标点符号 if (pCurStat <> nil) then begin pCurStat.Symbol := not pCurStat.Symbol; InvalidateRect(hStatWnd, nil, True); end; end; 4: begin // 中文英文 if (pCurStat <> nil) then begin pCurStat.Chinese := not pCurStat.Chinese; InvalidateRect(hStatWnd, nil, True); end; end; end; // case of .. Result := 0; end else Result := DefWindowProc(hStatWnd, uMsg, wParam, lParam); end; WM_LBUTTONUP: begin ReleaseCapture(); Result := 0; end; WM_MOUSEMOVE: begin SetCursor(LoadCursor(0, IDC_SIZEALL)); GetCursorPos(CurPoint); GetWindowRect(hStatWnd, StatRect); OffsetRect(StatRect, CurPoint.X - OldPoint.X, CurPoint.Y - OldPoint.Y); SystemParametersInfo(SPI_GETWORKAREA, 0, @ScreenRect, 0); if (StatRect.Right > ScreenRect.Right) then StatRect.Left := ScreenRect.Right - BmpWidth else if (StatRect.Left < ScreenRect.Left) then StatRect.Left := ScreenRect.Left; if (StatRect.Bottom > ScreenRect.Bottom) then StatRect.Top := ScreenRect.Bottom - BmpHeight else if (StatRect.Top < ScreenRect.Top) then StatRect.Top := ScreenRect.Top; MoveWindow(hStatWnd, StatRect.Left, StatRect.Top, BmpWidth, BmpHeight, True); GetCursorPos(OldPoint); Result := 0; end; else Result := DefWindowProc(hStatWnd, uMsg, wParam, lParam); end;end; // 注册stat类function RegisterStatClass(): Bool;var StatClass: TWndClass;begin StatClass.style := CS_VREDRAW or CS_HREDRAW or CS_IME; StatClass.lpfnWndProc := @StatusWndProc; StatClass.cbClsExtra := 0; StatClass.cbWndExtra := SizeOf(PStatus); // ** StatClass.hInstance := HInstance; StatClass.hCursor := LoadCursor(0, IDC_HAND); StatClass.hIcon := 0; StatClass.lpszMenuName := nil; StatClass.lpszClassName := Stat_ClassName; StatClass.hbrBackground := COLOR_BTNFACE + 1; Result := RegisterClass(StatClass) <> 0;end; // 建立stat窗口function CreateStatWindow(hUIWnd: hWnd): hWnd;var ScreenRect: TRect;begin SystemParametersInfo(SPI_GETWORKAREA, 0, @ScreenRect, 0); Result := CreateWindow(Stat_ClassName, nil, WS_DISABLED or WS_POPUP, ScreenRect.Left + 5, ScreenRect.Bottom - BmpHeight - 5, BmpWidth, BmpHeight, hUIWnd, 0, HInstance, nil); ShowWindow(Result, SW_SHOWNOACTIVATE); // **end;end. 有兴趣的话,请看看这个:http://www.2ccc.com/article.asp?articleid=2850 很明显Toolbar2000不是用的DISABLE窗口,它是继承自TCustomForm用VCL在设计程序时要简单得多,直接用API的话我还不如拿着toolbar2000就用...自己处理WM_MOUSEACTIVATE消息,返回MA_NOACTIVATE可以让鼠标点窗体客户区不抢焦点,但不能点标题和边框.要处理标题和边框的点击好象要处理WM_NCHITTEST消息......它里面的代码有点杂,分离出来达不到效果... 用VCL在设计程序时要简单得多,直接用API的话我还不如拿着toolbar2000就用...-------------------------------------------------------嘿嘿,的确,我贴的是API代码,但不代表就一定要完全用API来写呀? ^^VCL和SDK有本质区别吗?我看是没有!SDK能实现的,VCL就更能实现了…指定窗口风格,重载CreateParams不就可以了?处理WM_SETCURSOR消息,方法就更多了。。楼主应该是老鸟了,这些应该都知道的吧,俺就不在这里班门弄斧啦… :~) 当然,Toolbar2000如何实现的,是另一回事了,我只是路过说了两句,楼主莫怪…… 也许是我表达得不太好,photoshop的工具窗口有两种,左边的是绘图工具,是不能获得焦点的,右边的一系列窗口分两种情况,1是窗口里没有可以获得焦点的控件,那么它也是不能获得焦点的,2是窗口里有能获得焦点的控件,点客户区不会抢走焦点,点能获得焦点的控件是可以获得焦点的,和toolbar2000实现的效果完全一样,我想要的就是这种效果.刘麻子兄的方法是完全不能获得焦点的了,这种窗口也有它的用处,当然不止是IME其实我现在都用不着-_- 研究研究嘛,呵呵从toolbar2000以及dfw的lich的回答来看,应该从TForm类继承的普通窗口响应WM_MOUSEACTIVATE及WM_NCHITTEST消息就能做到我说的那种效果,前一个简单,第二个好象复杂点,还没研究过这个消息,希望不要自画~ 在DFW上看了很多刘麻子兄的帖子,高手了。,怎么高手都跑到csdn里来了。 如何选中绘图了的对象? 监视dll文件中的函数 兼职开发问题(QQ:188567235) 怎樣使用adoquery函數locate的第三個參數? 一个查询语句--急死人的急(等着你) 怎样检查一个字符串是否符合 数据库表名的命名规则? 在一个明细表中增加一个计算字段显示记录的序号 ADO的Recordset为什么不好用?? 200分:200分:关于窗体继承和事务控制:谁能解决?困扰了我好几天,怎么就没人懂呢????? 180分征集--支持离线下载的控件或源码 Delphi 中设置的快捷键 为什么无效啊 ????————————在线等待!!!! 怎么样取消GRIDEH的过滤功能?
WS_EX_NOACTIVATE
procedure TForm2.FormActivate(Sender: TObject);
begin
SendMessage(Application.MainForm.Handle, WM_NCACTIVATE, Integer(True), 0);
end;
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type TFloatWnd = class(TForm)
private
procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
public
constructor CreateEx(AOwner: TComponent; CFrame: TWinControlClass);
procedure ShowAt(X, Y: Integer);
end; TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
end;var
Form1: TForm1;implementation
uses
Unit2;
{$R *.dfm}{ TFloatWnd }constructor TFloatWnd.CreateEx(AOwner: TComponent; CFrame: TWinControlClass);
begin
inherited CreateNew(AOwner);
AutoSize := True;
FormStyle := fsStayOnTop;
BorderStyle := bsToolWindow;
with CFrame.Create(self) do
Parent := Self;
OnClose := FormClose;
end;procedure TFloatWnd.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;procedure TFloatWnd.ShowAt(X, Y: Integer);
begin
Left := X;
Top := Y;
Show;
end;procedure TFloatWnd.WMActivate(var Message: TWMActivate);
var
i: Integer;
begin
for i := 0 to Screen.FormCount - 1 do
if Screen.Forms[i].Handle <> Handle then
SendMessage(Screen.Forms[i].Handle, WM_NCACTIVATE,
Ord(Message.Active <> WA_INACTIVE), 0);
end;procedure TForm1.Button1Click(Sender: TObject);
var
FloatWnd: TFloatWnd;
begin
FloatWnd := TFloatWnd.CreateEx(Self, TFrame2);
FloatWnd.ShowAt(Left + 10, Top + 20);
end;procedure TForm1.WMActivate(var Message: TWMActivate);
var
i: Integer;
begin
for i := 0 to Screen.FormCount - 1 do
if Screen.Forms[i].Handle <> Handle then
SendMessage(Screen.Forms[i].Handle, WM_NCACTIVATE,
Ord(Message.Active <> WA_INACTIVE), 0);
end;end.
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;type
TFrame2 = class(TFrame)
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
SpeedButton4: TSpeedButton;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
Edit1: TEdit;
Edit2: TEdit;
private
{ Private declarations }
public
{ Public declarations }
end;implementation{$R *.dfm}end.
事实上上面的代码也参考了Toolbar2000中的一些代码的。建一个工程试试看效果吧,反正我试了一下觉得还可以。
http://www.delphibbs.com/keylife/iblog_show.asp?xid=965
IME类是实现IME用户界面部分的预定义全局窗口类。“IME”类与预定义的公共控制窗口类有许多相同的特点,IME窗口实例与静态控制一样通过CreateWindowEx函数创建,IME类窗口自己不响应用户输入,取而代之的是接收不同类型的控制消息实现全部IME用户接口。应用程序可以使用IME类创建自己的IME窗口,还可以使用ImmGetDefaultIMEWnd函数获取缺省IME窗口。
你的程序....只是让窗口看起来和主窗口同时激活,而实际上它还是会抢去其它窗口的焦点,比如主窗口上有个edit,焦点在edit上时点你的窗口,edit会失去焦点,而我要的效果是不失去焦点!toolbar2000的代码我看了半天还没找到他是怎么实现的,它的工具窗口是不会抢焦点的,除非工具窗口里有可以获得焦点的控件TO aiirii:
不会创建一个无焦点窗口一定要用IME接口吧?
CreateWindowex 有一个参数可以设置,但一时没找到
好象子类还实现了一些功能,分离出来后建立一个实例Show不出来
输入法的窗口为什么不会得到“焦点”呢?因为它是一个“禁用”的窗口!在建立窗口的时候指定WS_DISABLED风格或事后EnableWindow()都可以的,那么这个窗口如何响应鼠标动作呢?答案是利用WM_SETCURSOR消息………
function RegisterStatClass(): Bool;
function CreateStatWindow(hUIWnd: hWnd): hWnd;implementationuses Messages, Unit_Class, Unit_Bmp, Unit_Public; // Stat窗口回调
function StatusWndProc(hStatWnd: hWnd; uMsg: uInt; wParam: WParam; lParam: LParam): LResult; stdcall;
const {$J+}
OldPoint: TPoint = (X: 0; Y: 0); {$J-} // 每次只可能"拖拽"一个状态条, 所以只用一个全局变量就够了..
var
pCurStat: PStatus;
hStatDC: HDC;
ps: TPaintStruct;
StatRect, ScreenRect: TRect;
CurPoint: TPoint;
begin
case (uMsg) of
WM_CREATE:
begin
GetMem(pCurStat, SizeOf(TStatus));
SetWindowLong(hStatWnd, 0, Integer(pCurStat)); if (pCurStat = nil) then
Result := -1
else begin
pCurStat.Chinese := True;
pCurStat.FullShape := False;
pCurStat.Symbol := False; Result := 0;
end;
end; WM_DESTROY:
begin
pCurStat := PStatus(GetWindowLong(hStatWnd, 0));
if (pCurStat <> nil) then FreeMem(pCurStat); Result := 0;
end; WM_PAINT:
begin
hStatDC := BeginPaint(hStatWnd, ps); pCurStat := PStatus(GetWindowLong(hStatWnd, 0));
if (pCurStat <> nil) then DrawStatus(hStatDC, pCurStat^); EndPaint(hStatWnd, ps); Result := 0;
end; WM_SETCURSOR:
begin
if (HiWord(lParam) = WM_LBUTTONDOWN) then
begin
SetCursor(LoadCursor(0, IDC_HAND));
pCurStat := PStatus(GetWindowLong(hStatWnd, 0)); GetCursorPos(CurPoint);
ScreenToClient(hStatWnd, CurPoint); case ButtonPos(CurPoint) of
0: begin // 麻子头像
end; 1: begin // 单拼字样
SetCursor(LoadCursor(0, IDC_SIZEALL)); GetCursorPos(OldPoint);
SetCapture(hStatWnd); // 接收鼠标消息
end; 2: begin // 全角半角
if (pCurStat <> nil) then
begin
pCurStat.FullShape := not pCurStat.FullShape;
InvalidateRect(hStatWnd, nil, True);
end;
end; 3: begin // 标点符号
if (pCurStat <> nil) then
begin
pCurStat.Symbol := not pCurStat.Symbol;
InvalidateRect(hStatWnd, nil, True);
end;
end; 4: begin // 中文英文
if (pCurStat <> nil) then
begin
pCurStat.Chinese := not pCurStat.Chinese;
InvalidateRect(hStatWnd, nil, True);
end;
end;
end; // case of .. Result := 0;
end else
Result := DefWindowProc(hStatWnd, uMsg, wParam, lParam);
end; WM_LBUTTONUP:
begin
ReleaseCapture();
Result := 0;
end; WM_MOUSEMOVE:
begin
SetCursor(LoadCursor(0, IDC_SIZEALL)); GetCursorPos(CurPoint);
GetWindowRect(hStatWnd, StatRect);
OffsetRect(StatRect, CurPoint.X - OldPoint.X, CurPoint.Y - OldPoint.Y); SystemParametersInfo(SPI_GETWORKAREA, 0, @ScreenRect, 0); if (StatRect.Right > ScreenRect.Right) then StatRect.Left := ScreenRect.Right - BmpWidth
else if (StatRect.Left < ScreenRect.Left) then StatRect.Left := ScreenRect.Left; if (StatRect.Bottom > ScreenRect.Bottom) then StatRect.Top := ScreenRect.Bottom - BmpHeight
else if (StatRect.Top < ScreenRect.Top) then StatRect.Top := ScreenRect.Top; MoveWindow(hStatWnd, StatRect.Left, StatRect.Top, BmpWidth, BmpHeight, True); GetCursorPos(OldPoint);
Result := 0;
end; else Result := DefWindowProc(hStatWnd, uMsg, wParam, lParam);
end;
end; // 注册stat类
function RegisterStatClass(): Bool;
var
StatClass: TWndClass;
begin
StatClass.style := CS_VREDRAW or CS_HREDRAW or CS_IME;
StatClass.lpfnWndProc := @StatusWndProc;
StatClass.cbClsExtra := 0;
StatClass.cbWndExtra := SizeOf(PStatus); // **
StatClass.hInstance := HInstance;
StatClass.hCursor := LoadCursor(0, IDC_HAND);
StatClass.hIcon := 0;
StatClass.lpszMenuName := nil;
StatClass.lpszClassName := Stat_ClassName;
StatClass.hbrBackground := COLOR_BTNFACE + 1; Result := RegisterClass(StatClass) <> 0;
end; // 建立stat窗口
function CreateStatWindow(hUIWnd: hWnd): hWnd;
var
ScreenRect: TRect;
begin
SystemParametersInfo(SPI_GETWORKAREA, 0, @ScreenRect, 0); Result := CreateWindow(Stat_ClassName, nil, WS_DISABLED or WS_POPUP,
ScreenRect.Left + 5, ScreenRect.Bottom - BmpHeight - 5,
BmpWidth, BmpHeight, hUIWnd, 0, HInstance, nil); ShowWindow(Result, SW_SHOWNOACTIVATE); // **
end;end.
-------------------------------------------------------
嘿嘿,的确,我贴的是API代码,但不代表就一定要完全用API来写呀? ^^
VCL和SDK有本质区别吗?我看是没有!SDK能实现的,VCL就更能实现了…
指定窗口风格,重载CreateParams不就可以了?处理WM_SETCURSOR消息,方法就更多了。。
楼主应该是老鸟了,这些应该都知道的吧,俺就不在这里班门弄斧啦… :~)
从toolbar2000以及dfw的lich的回答来看,应该从TForm类继承的普通窗口响应WM_MOUSEACTIVATE及WM_NCHITTEST消息就能做到我说的那种效果,前一个简单,第二个好象复杂点,还没研究过这个消息,希望不要自画~
,怎么高手都跑到csdn里来了。