📄 019.htm
字号:
</font><p>procedure TForm1.Cut1Click(Sender: TObject);</p>
<p>var</p>
<p>ARect: TRect;</p>
<p>begin</p>
<p>Clipboard.Assign(Image1.Picture);</p>
<p>with Image.Canvas do</p>
<p>begin</p>
<p>CopyMode := cmWhiteness; </p>
<p>ARect := Rect(0, 0, Image.Width, Image.Height); </p>
<p>CopyRect(ARect, Image.Canvas, ARect); </p>
<p>CopyMode := cmSrcCopy; </p>
<p>end;</p>
<p>end;<font face="宋体" lang="ZH-CN"> </font></p>
<p>7.1.3.3 <font face="宋体" lang="ZH-CN">粘贴 </p>
<p>从剪贴板上粘贴图像,首先检测剪贴板上的数据格式。如果格式为</font>CF_BITMAP<font
face="宋体" lang="ZH-CN">,则调用目标位图的</font>Assign <font face="宋体"
lang="ZH-CN">方法粘贴图像。</p>
<p>程序清单如下。</p>
</font><p>procedure TForm1.PasteButtonClick(Sender: TObject);</p>
<p>var</p>
<p>Bitmap: TBitmap;</p>
<p>begin</p>
<p>if Clipboard.HasFormat(CF_BITMAP) then </p>
<p>begin</p>
<p>Bitmap := TBitmap.Create; </p>
<p>try</p>
<p>Bitmap.Assign(Clipboard); </p>
<p>Image.Canvas.Draw(0, 0, Bitmap); </p>
<p>finally</p>
<p>Bitmap.Free;</p>
<p>end;</p>
<p>end;</p>
<p>end; </p>
<p>try...finally<font face="宋体" lang="ZH-CN">为资源保护块,参第十二章。</p>
</font><p>7.1.4 <font face="宋体" lang="ZH-CN">建立自己的剪贴板观察程序 </p>
</font><p><font face="宋体" lang="ZH-CN">
在这一节中我们要建立一个自己的剪贴板观察程序,用来保存截获到剪贴板中的位图。</p>
</font><p> Windows<font face="宋体" lang="ZH-CN">允许用户建立自己的剪贴板观察程序,并把该程序添加到一个剪贴板观察器链中。在链中,位置靠前的程序有义务把有关剪贴板的消息传递到紧随其后的观察程序。而处于链首的程序由</font>Windows<font
face="宋体" lang="ZH-CN">的消息循环机制直接把剪贴板消息发送过来。</p>
</font><p><font face="宋体" lang="ZH-CN">
建立一个剪贴板观察程序,首先该程序必须能响应相应的</font>Windows<font
face="宋体" lang="ZH-CN">消息。对于那些熟悉</font>Microsoft<font face="宋体"
lang="ZH-CN">公司</font>Visual Basic<font face="宋体" lang="ZH-CN">的读者来说,这是令他们头疼而束手无策的地方。但</font>Delphi<font
face="宋体" lang="ZH-CN">在这方面却有良好的表现:利用关键字</font>message<font
face="宋体" lang="ZH-CN">,用户可以将一个过程定义为响应特定的</font>Windows<font
face="宋体" lang="ZH-CN">消息。如: </p>
</font><p>procedure WMDrawClipboard(var Msg:TWMDrawClipboard);</p>
<p>message WM_DRAWCLIPBOARD; </p>
<p><font face="宋体" lang="ZH-CN">
可以响应</font>WM_DRAWCLIPBOARD<font
face="宋体" lang="ZH-CN">消息。类</font>TWMDrawClipboard<font face="宋体"
lang="ZH-CN">是消息类</font>Message <font face="宋体" lang="ZH-CN">的子类。</font>Delphi<font
face="宋体" lang="ZH-CN">把所有的消息都重新进行了定义,使用户在使用时可以直接引用其便于记忆的数据成员,而不必再自己动手去分解消息。虽然这并不能算作是一个重大的改进,但却体现了</font>Delphi<font
face="宋体" lang="ZH-CN">处处为用户方便着想的特点。</p>
</font><p><font face="宋体" lang="ZH-CN">
我们将要建立的程序目的是把截获到剪贴板上的位图保存下来。在本书的写作过程中,这一工作是大量存在的。虽然利用</font>Windows<font
face="宋体" lang="ZH-CN">工具</font>PaintBrush(<font face="宋体" lang="ZH-CN">画笔),通过粘贴、保存等操作可以实现这一功能,但却存在以下一些问题:</p>
</font><p>1.<font face="宋体" lang="ZH-CN">程序频繁切换影响效率,当有大量位图存在时更是如此;</p>
</font><p>2.<font face="宋体" lang="ZH-CN">画笔有一个很讨厌的缺陷:当剪贴板上的位图比画笔界面的客户区大时,客户区外的位图被截断。因而往往需要根据所截获位图的大小来调整画笔客户区的大小,并重新进行粘贴。而如果开始就把画笔客户区调整到足够大,又会覆盖掉屏幕上一些有用的信息。</p>
</font><p><font face="宋体" lang="ZH-CN">
为解决这些问题,我开发了下面的程序。程序启动时,以极小化方式运行。此时只要剪贴板中存入位图,则自动弹出一个对话框请求用户保存。如果用户希望查看确认,则可以双击运行程序图标,选择相应按钮,剪贴板中的位图就会显示在屏幕上。</font></p>
<font face="宋体" lang="ZH-CN"><p>部件关键属性设计如下: </p>
</font><p>ClipSaveForm<font face="宋体" lang="ZH-CN">:</p>
</font><p>Caption<font face="宋体" lang="ZH-CN">=‘</font>Save Bitmap in Clipboard '</p>
<p>Panel1:</p>
<p>Align = ' Top '</p>
<p>Image1:</p>
<p>Align = ' Client '</p>
<p>SaveDialog1:</p>
<p>FileEditStyle = fsEdit</p>
<p>FileName = '*.bmp'</p>
<p>Filter = 'Bitmap Files(*.bmp)|*.bmp|Any Files(*.*)|*.*'</p>
<p>InitialDir = 'c:\bmp'</p>
<p>Title = 'Save Bitmap' </p>
<p><font face="宋体" lang="ZH-CN">
程序主窗口是</font>TForm<font
face="宋体" lang="ZH-CN">派生类</font>TClipSaveForm<font face="宋体" lang="ZH-CN">的实例。</font>TClipSaveForm<font
face="宋体" lang="ZH-CN">通过定义一些私有数据成员和过程,使响应和处理</font>Windows<font
face="宋体" lang="ZH-CN">的相应消息成为可能。下面是</font>TClipSaveForm<font
face="宋体" lang="ZH-CN">的类定义: </p>
</font><p>type</p>
<p>TClipSaveForm = class(TForm)</p>
<p>SaveDialog1: TSaveDialog;</p>
<p>Image1: TImage;</p>
<p>Panel1: TPanel;</p>
<p>Button1: TButton;</p>
<p>SpeedButton1: TSpeedButton;</p>
<p>SpeedButton2: TSpeedButton;</p>
<p>Button2: TButton;</p>
<p>procedure FormCreate(Sender: TObject);</p>
<p>procedure FormDestroy(Sender: TObject);</p>
<p>procedure Button1Click(Sender: TObject);</p>
<p>procedure Button2Click(Sender: TObject);</p>
<p>procedure SpeedButton1Click(Sender: TObject);</p>
<p>procedure SpeedButton2Click(Sender: TObject);</p>
<p>private</p>
<p>{ Private declarations }</p>
<p>MyBitmap: TBitmap; { <font face="宋体" lang="ZH-CN">保存截获的位图</font> }</p>
<p>View: Boolean; { <font face="宋体" lang="ZH-CN">判断是否显示</font> }</p>
<p>NextViewerHandle: HWND; { <font face="宋体" lang="ZH-CN">下一剪贴板观察器的句柄</font>
}</p>
<p>procedure WMDrawClipboard(var Msg:TWMDrawClipboard);</p>
<p>message WM_DRAWCLIPBOARD;</p>
<p>procedure WMChangeCBChain(var Msg:TWMChangeCBChain);</p>
<p>message WM_CHANGECBCHAIN; </p>
<p>{ <font face="宋体" lang="ZH-CN">响应</font>Windows<font face="宋体" lang="ZH-CN">的剪贴板消息</font>
}</p>
<p>public</p>
<p>{ Public declarations }</p>
<p>end;</p>
<p><font face="宋体" lang="ZH-CN">
窗口创建时,把该窗口登录为剪贴板观察器,添加到剪贴板观察器链中,同时进行变量、部件和剪贴板的初始化。 </p>
</font><p>procedure TClipSaveForm.FormCreate(Sender: TObject);</p>
<p>begin</p>
<p>View := False;</p>
<p>SpeedButton2.Down := True;</p>
<p>MyBitmap := TBitmap.create;</p>
<p>try</p>
<p>MyBitmap.Width := 0;</p>
<p>MyBitmap.Height := 0 ;</p>
<p>except</p>
<p>Application.terminate;</p>
<p>end;</p>
<p>Clipboard.Clear;</p>
<p>NextViewerHandle := SetClipboardViewer(Handle);</p>
<p>end; </p>
<p><font face="宋体" lang="ZH-CN">窗口关闭时,退出剪贴板观察器链,并释放内存: </p>
</font><p>procedure TClipSaveForm.FormDestroy(Sender: TObject);</p>
<p>begin</p>
<p>ChangeClipboardChain(Handle,NextViewerHandle);</p>
<p>MyBitmap.Free;</p>
<p>end; </p>
<p><font face="宋体" lang="ZH-CN">在以上两段程序中用到的两个</font>Windows
API<font face="宋体" lang="ZH-CN">函数</font>SetClipboardViewer<font face="宋体"
lang="ZH-CN">和</font>ChangeClipboardChain<font face="宋体" lang="ZH-CN">分别用于登录和退出剪贴板观察器链。</p>
<p>程序保存位图的功能是在消息响应过程WMDrawClipboard中实现的。该过程在剪贴板内容有变化时被调用。 </p>
</font><p>procedure TClipSaveForm.WMDrawClipboard(var Msg: TWMDrawClipboard);</p>
<p>var</p>
<p>FileName: String;</p>
<p>begin</p>
<p>If NextViewerHandle <> 0 then</p>
<p>SendMessage(NextViewerHandle,msg.Msg,0,0);</p>
<p>If ClipBoard.HasFormat(CF_BITMAP) then</p>
<p>begin</p>
<p>MyBitmap.Assign(Clipboard);</p>
<p>If SaveDialog1.Execute then</p>
<p>begin</p>
<p>FileName := SaveDialog1.FileName;</p>
<p>MyBitmap.SaveToFile(FileName);</p>
<p>end;</p>
<p>If View then</p>
<p>begin</p>
<p>WindowState := wsNormal;</p>
<p>Image1.Picture.Bitmap := MyBitmap;</p>
<p>end;</p>
<p>end;</p>
<p>Msg.Result := 0;</p>
<p>end; </p>
<p><font face="宋体" lang="ZH-CN">
程序首先判断在剪贴板观察器链中是否还存在下一个观察器。如果有,则把消息传递下去,这是剪贴板观察器程序的义务。而后判断剪贴板上内容的格式是否为位图。如是,则首先把剪贴板上内容保存到数据成员</font>MyBitmap<font
face="宋体" lang="ZH-CN">中,并激活一个文件保存对话框把位图保存到文件中。如果</font>View=True<font
face="宋体" lang="ZH-CN">,则把窗口状态</font>(WindowState)<font face="宋体"
lang="ZH-CN">设置为</font>wsNormal<font face="宋体" lang="ZH-CN">,并把</font>MyBitmap<font
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -