【问题标题】:How to create your own non system Clipboard?如何创建自己的非系统剪贴板?
【发布时间】:2012-02-13 01:52:12
【问题描述】:

有可能吗?如果可以,您将如何实现自己的剪贴板?

我的意思是能够像 Windows 剪贴板一样在其中复制和粘贴任何内容,但实际上不会干扰系统剪贴板。

为了更好地了解这是我尝试过的:

uses
  ClipBrd;

...

procedure TMainForm.actCopyExecute(Sender: TObject);
var
  MyClipboard: TClipboard;
begin
  MyClipboard := TClipboard.Create;
  try
    MyClipboard.AsText := 'Copy this text';
  finally
    MyClipboard.Free;
  end;
end;

它的工作原理是将字符串“复制此文本”复制到剪贴板,但它会覆盖 Windows 剪贴板上的任何内容。

以上内容必须只是创建 Windows 剪贴板的一个实例,而不是实际创建您自己的。

请注意,自定义剪贴板可以保存任何数据,而不仅仅是纯文本。它应该与 Windows 剪贴板一样工作,但不会干扰它(丢失上面的任何内容)。

如何做到这一点?

谢谢。

【问题讨论】:

  • 你应该这样做Clipboard.AsText := 'Copy this text';;无需创建TClipboard 的新实例。
  • 是的,我知道。我的评论跑题了。
  • 创建一个列表,复制的时候把东西放进去,粘贴的时候再拿出来。
  • 对我来说这个问题听起来像:"I'd like to create a wheel, just like a wheel, but it shouldn't be a wheel"。呃,如果它是圆形的并且像轮子一样工作,那么它就是轮子。请解释为什么您认为您需要自己的私人剪贴板,因为目前您只是在尝试重新发明轮子。
  • 如果您只想对自己的类型进行特殊处理,那么 RegisterClipboardFormat 是要走的路,@Ken 的答案就是要走的路。这样,您还可以(如果适用)使用系统剪贴板在您自己的应用程序实例之间复制和粘贴。

标签: delphi clipboard


【解决方案1】:

您的问题令人困惑;你说你想在不影响系统剪贴板的情况下做到这一点,但是(从你自己的评论到你的问题)你似乎想要实现像 MS Office 的Paste Special 这样的东西。

如果它是第一个,正如其他人所说,你不能使用 TClipboard 包装器来做到这一点;您必须自己实现,并且在应用程序之间传递信息将非常困难。

如果是第二个,您可以使用 Windows API RegisterClipboardFormat 来定义您自己的格式。

type
  TForm1=class(TForm)
    YourCustomFormat: Word;
    procedure FormCreate(Sender: TObject);
  end;

implementation

constructor TForm1.FormCreate(Sender: TObject);
begin
  YourCustomFormat := RegisterClipboardFormat('Your Custom Format Name');
end;

要将信息以自定义格式放入剪贴板,您必须使用 GlobalAllocGlobalLock 分配和锁定全局内存块,将数据复制到该块中,使用 GlobalUnlock 解锁块,使用TClipboard.SetAsHandle 将内存块传输到剪贴板。然后您需要调用GlobalFree 来释放内存块。

要以您的自定义格式检索内容,您只需颠倒几个步骤即可执行基本相同的操作。你像以前一样使用 GlobalAlloc/GlobalLock,使用TClipboard.GetAsHandle 来检索剪贴板的内容,将其复制到一个局部变量中,然后调用 GlobalFree。

这是一个将自定义格式(在本例中为 RTF 文本)放入剪贴板的旧示例 - 它来自 TeamB 的 Peter 博士的 newsgroup post。 (代码和格式是他从原始帖子中获得的;我没有对其进行测试甚至编译它。)从我上面关于更改内容的说明中应该可以清楚地了解将其恢复的过程,我把它留给你解决。 :)

procedure TForm1.BtnSetRTFClick(Sender: TObject);
Const
  testtext: PChar = '{\rtf1\ansi\pard\plain 12{\ul 44444}}';
  testtext2: PChar = '{\rtf1\ansi'+
  '\deff4\deflang1033{\fonttbl{\f4\froman\fcharset0\fprq2 Times New Roman;}}'
                     +'\pard\plain 12{\ul 44444}}';
  flap: Boolean = False;
Var
  MemHandle: THandle;
  rtfstring: PChar;
begin
    If flap Then
      rtfstring := testtext2
    Else
      rtfstring := testtext;
    flap := not flap;
    MemHandle := GlobalAlloc( GHND or GMEM_SHARE, StrLen(rtfstring)+1 );
    If MemHandle <> 0 Then Begin
      try
        StrCopy( GlobalLock( MemHandle ), rtfstring );
        GlobalUnlock( MemHandle );
        With Clipboard Do Begin
          Open;
          try
            AsText := '1244444';
            SetAsHandle( CF_RTF, MemHandle );
          finally
            Close;
          end;
        End;
      Finally
        GlobalFree( MemHandle );
      End;
    End
    Else
      MessageDlg('Global Alloc failed!',
                 mtError, [mbOK], 0 );
end;

【讨论】:

  • +1 RegisterClipboardFormat 似乎是@Blobby 的最佳选择
  • 不太可能一个真正权威的医生(他是医生吗?)执行 copy 作为 RTF 片段(根本不是私有格式)的代码将解决 hypothetical i> OP 的 paste special 问题。
  • RTF 不是预定义的剪贴板格式 whearas Text 是(CF_OEMTEXT 或 CF_TEXT 或 CF_UNICODETEXT):如果要使用 WinAPI,则必须将其实现为自定义剪贴板格式。 EasyGPS 使用gpx 自定义格式,实际上是 XML(文本)。
  • 我遇到了自定义格式的问题,我在粘贴端看不到它。这是因为我在复制中使用了GlobalFree( MemHandle ); 行,这在我指向粘贴端的数据之前释放了我的句柄。仅在复制文本等标准格式时可能不适用。有点具体,但也许这些信息会对某些人有所帮助!
【解决方案2】:

您应该定义自己的自定义剪贴板。它可能看起来像这样:

type
  TMyCustomClipboard = class
  private
    FStream: TMemoryStream;
    function GetAsText: string;
    procedure SetAsText(const Value: string);
    ...
  public
    constructor Create;
    destructor Destroy; override;
    procedure Clear;
    property AsText: string read GetAsText write SetAsText;
    procedure AsAnyThing: AnyType read GetAsAnyThing write AsAnyThing;
    ...
  end;

然后您可以使用FStream 作为自定义剪贴板容器。您可以在该流中存储(复制)任何数据,并在需要时使用(粘贴)它。您只需要为您的数据类型编写一些 Get/Set 方法。

【讨论】:

  • 有趣的帖子感谢您提供如何实现它的示例
  • 理想情况下应该是这样,抽象基TClipboard,然后是WinAPI具体后代,X/freedesktop具体后代,以此类推……
【解决方案3】:

TClipboard 是一个封装系统剪贴板的类,因此您不能使用它来实例化剪贴板的另一个副本。您应该实现自己的类,用 setter 和 getter 表示一个通用缓冲区。

【讨论】:

  • 虽然这肯定是可行的,但这并非完全无关紧要。
  • 视情况而定。如果您想“理解”自定义剪贴板支持的每种数据类型,那么这并非易事。但是您可能会承认“按原样”存储和恢复数据(例如,作为二进制流),前提是剪贴板客户端“知道”他们设置和获取的内容。
  • 好吧,另一个 TClipboard 实例的行为就像一个剪贴板函数返回一样。因此,扩展 TClipboard 需要对这个函数进行一些钩子。
【解决方案4】:

你不能。您可以有一个内部内存缓冲区,您可以将数据移入和移出,如果需要,您可以将其称为“复制”和“粘贴”,但不要将其放在用户界面中,否则只会混淆你的用户。系统剪贴板只有一个,不能在不影响其他程序的情况下将数据放入其中。如果您的下一个想法是保存剪贴板,用您的内容覆盖,然后恢复原始内容,请不要打扰。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多