如何通过Delphi FireMonkey剪贴板服务检测剪贴板内容变化?
Delphi FireMonkey跨平台剪贴板实时更新方案
一、原生平台监听(推荐方案)
FMX的ClipboardServices确实未内置剪贴板变化监听机制,因此需要针对Windows和macOS分别编写原生平台代码实现实时监听:
Windows平台
利用Win32 API的剪贴板查看器机制,系统会在剪贴板内容变化时主动发送消息通知:
- 通过窗口
Handle注册剪贴板查看器; - 重写窗口消息处理逻辑,捕获
WM_DRAWCLIPBOARD(剪贴板内容变化)和WM_CHANGECBCHAIN(查看器链变更)消息; - 收到消息后调用FMX剪贴板API判断是否有文本,有则更新Memo。
代码片段示例:
private NextClipboardViewer: HWND; procedure WndProc(var Message: TMessage); override; procedure TForm1.FormCreate(Sender: TObject); begin NextClipboardViewer := SetClipboardViewer(Handle); end; procedure TForm1.WndProc(var Message: TMessage); begin inherited; case Message.Msg of WM_DRAWCLIPBOARD: begin if TClipboard.Current.HasText then Memo1.Text := TClipboard.Current.GetText; // 传递消息给下一个查看器 if NextClipboardViewer <> 0 then SendMessage(NextClipboardViewer, Message.Msg, Message.WParam, Message.LParam); end; WM_CHANGECBCHAIN: begin if Message.WParam = NextClipboardViewer then NextClipboardViewer := Message.LParam else if NextClipboardViewer <> 0 then SendMessage(NextClipboardViewer, Message.Msg, Message.WParam, Message.LParam); end; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin ChangeClipboardChain(Handle, NextClipboardViewer); end;
macOS平台
基于Cocoa框架的NSPasteboard通知机制监听剪贴板变化:
- 获取系统通用剪贴板实例;
- 添加观察者监听
NSPasteboardChangedNotification通知; - 收到通知后切换到UI线程更新Memo(避免跨线程操作FMX控件)。
代码片段示例:
uses Macapi.AppKit, Macapi.Foundation, Macapi.ObjectiveC, System.Classes; private FPasteboardObserver: NSObject; procedure OnPasteboardChanged(Notification: NSNotification); procedure TForm1.FormCreate(Sender: TObject); var Block: TNotifyNSNotification; begin Block := procedure(Notification: NSNotification) begin OnPasteboardChanged(Notification); end; FPasteboardObserver := TNSBlockObserver.Create(Block); NSPasteboard.generalPasteboard.addObserverForNameObjectQueueUsingBlock( NSPasteboardChangedNotification, nil, nil, FPasteboardObserver.Block ); end; procedure TForm1.OnPasteboardChanged(Notification: NSNotification); begin if TClipboard.Current.HasText then begin TThread.Synchronize(nil, procedure begin Memo1.Text := TClipboard.Current.GetText; end); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin NSPasteboard.generalPasteboard.removeObserverNameObject( FPasteboardObserver, NSPasteboardChangedNotification, nil ); end;
二、TTimer轮询方案(快速实现方案)
用TTimer定期检测剪贴板是可行的,需注意以下细节:
- 轮询间隔:1秒间隔在多数场景下足够,若需更实时可缩短至500ms,系统开销可忽略;
- 避免重复更新:记录上一次剪贴板文本,仅当内容变化时才更新Memo,防止无效刷新。
代码片段示例:
private FLastClipboardText: string; procedure TForm1.Timer1Timer(Sender: TObject); var CurrentText: string; begin if TClipboard.Current.HasText then begin CurrentText := TClipboard.Current.GetText; if CurrentText <> FLastClipboardText then begin FLastClipboardText := CurrentText; Memo1.Text := CurrentText; end; end else FLastClipboardText := ''; end;
方案对比
- 原生监听:实时性强、系统开销低,是最优方案,但需维护平台特定代码;
- TTimer轮询:实现简单、无需平台适配,适合快速开发,但实时性依赖轮询间隔。
内容的提问来源于stack exchange,提问作者Mike Stephenson
相关产品推荐
相关产品推荐

