2012-02-11 3 views
3

Возможно ли это, и если да, то как вы собираетесь внедрить свой собственный буфер?Как создать свой собственный системный буфер обмена?

Под этим я имею в виду возможность копировать и вставлять что-либо в него и из него точно так же, как это делает буфер обмена 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, но не вмешиваться в него (теряя все, что на нем было).

Как это можно достичь?

Спасибо.

+1

Вы должны сделать 'Clipboard.AsText: = 'Скопировать этот текст';'; нет необходимости создавать новый экземпляр «TClipboard». –

+0

Да, но мне нужен мой собственный буфер обмена, а не Windows. –

+1

Да, я знаю. Мой комментарий был вне темы. –

ответ

5

Ваш вопрос смущает; вы говорите, что хотите сделать это, не затрагивая системный буфер обмена, но затем (из вашего собственного комментария к вашему вопросу) вы, похоже, хотите реализовать что-то вроде 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; 

Чтобы поместить данные в буфер обмена в пользовательском формате, вы должны использовать GlobalAlloc и GlobalLock выделить и зафиксировать глобальный блок памяти, копировать данные в этот блок, разблокировать блок, используя GlobalUnlock, используйте TClipboard.SetAsHandle для переместите блок памяти в буфер обмена. Затем вам необходимо позвонить GlobalFree, чтобы освободить блок памяти.

Чтобы получить вещи в своем обычном формате, вы делаете в основном то же самое с несколькими шагами в обратном порядке. Вы используете GlobalAlloc/GlobalLock, как и раньше, используйте TClipboard.GetAsHandle для извлечения содержимого буфера обмена, копирования его в локальную переменную и последующего вызова GlobalFree.

Вот старый пример ввода пользовательского формата (в данном случае текста RTF) в буфер обмена - это от newsgroup post от Dr. Peter Below от TeamB. (Код и форматирование - это его исходное сообщение, я его не тестировал или даже не скомпилировал.) Обратный процесс, чтобы получить его обратно, должен быть ясным из моих инструкций о том, что нужно изменить выше, и я оставляю это для вас выработать. :)

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; 
+3

+1 RegisterClipboardFormat делает похоже, путь для @Blobby –

+1

Вряд ли действительно авторитетный доктор (он еще врач?) код, который выполняет ** copy ** как RTF-фрагмент (не частный формат вообще), решит * гипотетическую * проблему OP с ** вставить специальный **. – OnTheFly

+0

RTF не является предопределенным форматом буфера обмена. «Text» (CF_OEMTEXT или CF_TEXT или CF_UNICODETEXT): он должен быть реализован как пользовательский формат буфера обмена, если WinAPI - это путь. EasyGPS использует пользовательский формат 'gpx', который на самом деле является XML (Text). – menjaraz

1

TClipboard - это классный инкапсулирующий системный буфер обмена, поэтому вы не можете использовать его для создания экземпляра другой копии буфера обмена. Вы должны реализовать свой собственный класс, представляя универсальный буфер с сеттерами и геттерами.

+0

И это не совсем тривиально, хотя, безусловно, выполнимо. –

+0

Всё зависит от меня. Если вы хотите «понять» все типы данных, поддерживаемые вашим настраиваемым буфером обмена, то это не тривиально. Но вы можете признать, что хранить и восстанавливать данные просто «как есть» (скажем, как двоичный поток), при условии, что клиенты клиберта «знают», что они устанавливают и получают. – Stan

+0

Ну, другой экземпляр TClipboard будет вести себя точно так же, как возвращает одна функция Clipboard. Таким образом, расширение TClipboard потребует некоторой привязки этой функции. – OnTheFly

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 для ваших типов данных.

+0

Интересное сообщение спасибо за предоставление образца того, как он может быть достигнут. –

+1

В идеальном мире это должно быть так, абстрактная базовая TClipboard, затем потомок потомка WinAPI и конечный потомок X/freedesktop, и так далее ... – OnTheFly

1

Вы не можете. У вас может быть буфер внутренней памяти, в который вы перемещаете данные в и из них, вы можете называть его «копировать» и «вставлять», если хотите, но не помещать его в пользовательский интерфейс, иначе вы просто смутитесь ваших пользователей. Существует только один системный буфер обмена, и вы не можете поместить в него данные, не затрагивая другие программы. Если ваша следующая мысль заключается в том, чтобы сохранить буфер обмена, перезаписать его, а затем восстановить исходное содержимое, не беспокойтесь.

Смежные вопросы