7.1.4 建立自己的剪贴板观察程序
在这一节中我们要建立一个自己的剪贴板观察程序,用来保存截获到剪贴板中的位图。
Windows允许用户建立自己的剪贴板观察程序,并把该程序添加到一个剪贴板观察器链中。在链中,位置靠前的程序有义务把有关剪贴板的消息传递到紧随其后的观察程序。而处于链首的程序由Windows的消息循环机制直接把剪贴板消息发送过来。
建立一个剪贴板观察程序,首先该程序必须能响应相应的Windows消息。对于那些熟悉Microsoft公司Visual Basic的读者来说,这是令他们头疼而束手无策的地方。但Delphi在这方面却有良好的表现:利用关键字message,用户可以将一个过程定义为响应特定的Windows消息。如:
procedure WMDrawClipboard(var Msg:TWMDrawClipboard);
message WM_DRAWCLIPBOARD;
可以响应WM_DRAWCLIPBOARD消息。类TWMDrawClipboard是消息类Message 的子类。Delphi把所有的消息都重新进行了定义,使用户在使用时可以直接引用其便于记忆的数据成员,而不必再自己动手去分解消息。虽然这并不能算作是一个重大的改进,但却体现了Delphi处处为用户方便着想的特点。
我们将要建立的程序目的是把截获到剪贴板上的位图保存下来。在本书的写作过程中,这一工作是大量存在的。虽然利用Windows工具PaintBrush(画笔),通过粘贴、保存等操作可以实现这一功能,但却存在以下一些问题:
1.程序频繁切换影响效率,当有大量位图存在时更是如此;
2.画笔有一个很讨厌的缺陷:当剪贴板上的位图比画笔界面的客户区大时,客户区外的位图被截断。因而往往需要根据所截获位图的大小来调整画笔客户区的大小,并重新进行粘贴。而如果开始就把画笔客户区调整到足够大,又会覆盖掉屏幕上一些有用的信息。
为解决这些问题,我开发了下面的程序。程序启动时,以极小化方式运行。此时只要剪贴板中存入位图,则自动弹出一个对话框请求用户保存。如果用户希望查看确认,则可以双击运行程序图标,选择相应按钮,剪贴板中的位图就会显示在屏幕上。
部件关键属性设计如下:
ClipSaveForm:
Caption=‘Save Bitmap in Clipboard '
Panel1:
Align = ' Top '
Image1:
Align = ' Client '
SaveDialog1:
FileEditStyle = fsEdit
FileName = '*.bmp'
Filter = 'Bitmap Files(*.bmp)|*.bmp|Any Files(*.*)|*.*'
InitialDir = 'c:\bmp'
Title = 'Save Bitmap'
程序主窗口是TForm派生类TClipSaveForm的实例。TClipSaveForm通过定义一些私有数据成员和过程,使响应和处理Windows的相应消息成为可能。下面是TClipSaveForm的类定义:
type
TClipSaveForm = class(TForm)
SaveDialog1: TSaveDialog;
Image1: TImage;
Panel1: TPanel;
Button1: TButton;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
private
{ Private declarations }
MyBitmap: TBitmap; { 保存截获的位图 }
View: Boolean; { 判断是否显示 }
NextViewerHandle: HWND; { 下一剪贴板观察器的句柄
}
procedure WMDrawClipboard(var Msg:TWMDrawClipboard);
message WM_DRAWCLIPBOARD;
procedure WMChangeCBChain(var Msg:TWMChangeCBChain);
message WM_CHANGECBCHAIN;
{ 响应Windows的剪贴板消息
}
public
{ Public declarations }
end;
窗口创建时,把该窗口登录为剪贴板观察器,添加到剪贴板观察器链中,同时进行变量、部件和剪贴板的初始化。
procedure TClipSaveForm.FormCreate(Sender: TObject);
begin
View := False;
SpeedButton2.Down := True;
MyBitmap := TBitmap.create;
try
MyBitmap.Width := 0;
MyBitmap.Height := 0 ;
except
Application.terminate;
end;
Clipboard.Clear;
NextViewerHandle := SetClipboardViewer(Handle);
end;
窗口关闭时,退出剪贴板观察器链,并释放内存:
procedure TClipSaveForm.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle,NextViewerHandle);
MyBitmap.Free;
end;
在以上两段程序中用到的两个Windows
API函数SetClipboardViewer和ChangeClipboardChain分别用于登录和退出剪贴板观察器链。
程序保存位图的功能是在消息响应过程WMDrawClipboard中实现的。该过程在剪贴板内容有变化时被调用。
procedure TClipSaveForm.WMDrawClipboard(var Msg: TWMDrawClipboard);
var
FileName: String;
begin
If NextViewerHandle <> 0 then
SendMessage(NextViewerHandle,msg.Msg,0,0);
If ClipBoard.HasFormat(CF_BITMAP) then
begin
MyBitmap.Assign(Clipboard);
If SaveDialog1.Execute then
begin
FileName := SaveDialog1.FileName;
MyBitmap.SaveToFile(FileName);
end;
If View then
begin
WindowState := wsNormal;
Image1.Picture.Bitmap := MyBitmap;
end;
end;
Msg.Result := 0;
end;
程序首先判断在剪贴板观察器链中是否还存在下一个观察器。如果有,则把消息传递下去,这是剪贴板观察器程序的义务。而后判断剪贴板上内容的格式是否为位图。如是,则首先把剪贴板上内容保存到数据成员MyBitmap中,并激活一个文件保存对话框把位图保存到文件中。如果View=True,则把窗口状态(WindowState)设置为wsNormal,并把MyBitmap赋给Image部件的相应值,使用户可以对剪贴板上的位图进行观察。
消息响应过程WMChangeCBChain在剪贴板观察器链上其它观察器退出时被调用。根据被移出观察器的不同位置决定了不同的处理方法。
procedure TClipSaveForm.WMChangeCBChain(var Msg: TWMChangeCBChain);
begin
if Msg.Remove = NextViewerHandle then
NextViewerHandle := Msg.Next
else
if NextViewerHandle <> 0 then
SendMessage(NextViewerHandle,Msg.Msg,Msg.Remove,Msg.Next);
Msg.Result := 0;
end;
窗口上有两个加速按钮,两个按钮。它们击键(click)事件处理过程如下。每一程序段的意义是非常显然的。
procedure TClipSaveForm.Button1Click(Sender: TObject);
begin
Close;
end;
procedure TClipSaveForm.Button2Click(Sender: TObject);
begin
WindowState := wsMinimized;
end;
procedure TClipSaveForm.SpeedButton1Click(Sender: TObject);
begin
View := True;
Image1.Picture.Bitmap := MyBitmap;
end;
procedure TClipSaveForm.SpeedButton2Click(Sender: TObject);
begin
View := False;
Image1.Picture.Bitmap := nil;
end;
通过对这个程序的介绍,以下几点是应该注意的:
1.提供了一种自己截获和处理剪贴板上内容的方法。读者可以根据需要进一步扩充;
2.提供了响应Windows消息的方法。在第三篇有关自定义部件开发的内容中,这一问题还要详细论述;
3.最后的一点启示是:在Delphi程序开发中巧妙应用传统的Windows方法(如消息处理、
API函数等)仍是很有必要的。而在应用这些方法中所体现的方便之处,正是Delphi胜过其它可视化开发工具的一个重要方面。
7.2 Windows的DDE原理和 Dephi的DDE实现机制
7.2.1 Windows的DDE原理
Windows的DDE机制基于Windows的消息机制。两个Windows应用程序通过相互之间传递DDE消息进行DDE会话(Conversation),从而完成数据的请求、应答、传输。这两个应用程序分别称为服务器(Server)和客户(Client)。服务器是 [1] [2] [3] [4] 下一页 |