Sign in Join
Wiki copytemporary

Revision 2 of 3, by WikiArchive on 11-4-2026. The page as it is now.

Clipboard/ru

Contents

Предопределенные типы

TPredefinedClipboardFormat тип MIME
pcfText text/plain
pcfBitmap image/bmp
pcfPixmap image/xpm
pcfIcon image/lcl.icon
pcfPicture image/lcl.picture
pcfMetaFilePict image/lcl.metafilepict
pcfObject application/lcl.object
pcfComponent application/lcl.component
pcfCustomData application/lcl.customdata

Текст

Для использования с простым текстом объект Clipboard предоставляет свойство AsText , которое может быть использовано для чтения и записи текста.

Запись текста:

pascal
Clipboard.AsText := 'Hello clipboard!';

Чтение текста:

pascal
ShowMessage('Clipboard content: ' + Clipboard.AsText);

Clipboard является объектом класса TClipboard и для его использования необходимо подключить модуль Clipbrd в разделе uses :

pascal
uses
    ..., Clipbrd;

Текстовые элементы управления

Некоторые визуальные компоненты, такие как TEdit, TMemo, TStringGrid, TLabeledEdit, TMaskEdit, TSpinEdit и TFloatSpinEdit обладают возможностью выделения части текста, находящегося в них, и предоставляют дополнительные функциональные возможности для выделенного текста при работе с буфером обмена.

pascal
procedure CopyToClipboard; 
      procedure CutToClipboard; 
      procedure PasteFromClipboard;

Текст в формате HTML

Объект ClipBoard поддерживает чтение и запись текста в формате HTML.

Пример чтения из буфера обмена и записи в буфер обмена текста в формате HTML:

pascal
uses
      Clipbrd, ...;
    var
      Html, PlainText: String;
    ...
    begin
      Html := ClipBoard.GetAsHtml;
      ...
      Html := '<b>Formatted</b> text';
      PlainText := 'Simple Text';
      ClipBoard.SetAsHtml(Html, PlainText);
    end.

Windows

Для обработки Html-текста в буфере обмена Windows требуется подключение заголовочных файлов.
В то время, как раньше пользователям необходимо было делать это вручную, теперь это прозрачно делается с помощью подключения модуля ClipBrd.

Изображения

Загрузка из буфера обмена

pascal
uses 
      Clipbrd, LCLIntf, LCLType, ...;
    
    procedure LoadBitmapFromClipboard(Bitmap: TBitmap);
    begin
      if Clipboard.HasFormat(PredefinedClipboardFormat(pcfDelphiBitmap)) then
        Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfDelphiBitmap));
      if Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap)) then
        Bitmap.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
    end;

Сохранение в буфере обмена

pascal
uses 
      Clipbrd, ...;
    
    procedure SaveBitmapToClipboard(Bitmap: TBitmap);
    begin
      Clipboard.Assign(Bitmap);
    end;

Пользовательский формат

Multiple objects

Получение уведомления об изменении буфера обмена

LCL не передает сообщения Windows (передаются только сообщения WM_USER). Это означает, что вы должны написать свой обработчик сообщения.

Пример кода для реализации обработчика сообщения:

pascal
unit Unit1;
    
    {$mode delphi}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
      Clipbrd, StdCtrls, Windows, Messages;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        FNextClipboardOwner: HWnd;   // хэндл на следующий вьювер в цепочке
        // обработчики события буфера обмена
        function WMChangeCBChain(wParam: WParam; lParam: LParam):LRESULT;
        function WMDrawClipboard(wParam: WParam; lParam: LParam):LRESULT;
      public
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.lfm}
    var
      PrevWndProc:windows.WNDPROC;
    
    function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
    begin
      if uMsg = WM_CHANGECBCHAIN then begin
        Result := Form1.WMChangeCBChain(wParam, lParam);
        Exit;
      end 
      else if uMsg=WM_DRAWCLIPBOARD then begin
        Result := Form1.WMDrawClipboard(wParam, lParam);
        Exit;
      end;
      Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam);
    end;
    
    { TForm1 }
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); // для x64 необходимо использовать SetWindowLongPtr
      FNextClipboardOwner := SetClipboardViewer(Self.Handle);
    end;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      ChangeClipboardChain(Handle, FNextClipboardOwner);
    end;
    
    function TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam): LRESULT;
    var
      Remove, Next: THandle;
    begin
      Remove := WParam;
      Next := LParam;
      if FNextClipboardOwner = Remove then FNextClipboardOwner := Next
        else if FNextClipboardOwner <> 0 then
          SendMessage(FNextClipboardOwner, WM_ChangeCBChain, Remove, Next)
    end;
    
    function TForm1.WMDrawClipboard(wParam: WParam; lParam: LParam): LRESULT;
    begin
      if Clipboard.HasFormat(CF_TEXT) Then Begin
        ShowMessage(Clipboard.AsText);
      end;
      SendMessage(FNextClipboardOwner, WM_DRAWCLIPBOARD, 0, 0);   // ВАЖНО!
      Result := 0;
    end;
    
    end.

Просмотр содержимого буфера обмена

Иногда бывает полезно посмотреть, что находится в данный момент в буфере обмена. Вот несколько методов, которые я использую (на форме расположен элемент TMemo и один таймер с интервалом 1 секунда) -

pascal
procedure TForm1.CheckClipboard();
    var
        I : integer;
        List : TStringList;
    begin
        memo1.clear;
        Memo1.Append('[' + Clipboard.AsText + ']');
        List := TStringList.Create;
        try
            ClipBoard.SupportedFormats(List);
            for i := 0 to List.Count-1 do begin
                //Memo1.Append(List.Strings[i]);        // раскомментируйте, чтобы увидеть все доступные форматы
                case List.Strings[i] of                 // показать конкретные форматы
                    'Rich Text Format', 'text/plain', 'UTF8_STRING' :
                        ReadClip(List.Strings[i]);
                end;
            end;
        finally
          List.Free;
        end;
    end;
    
    function TForm1.ReadClip(TheFormat : ANSIString) : ANSIString;
    var
      Stream: TMemoryStream;
      Fmt : TClipboardFormat;
      List : TStringList;
    begin
        if TheFormat = '' then exit;
        Stream := TMemoryStream.Create;
        List := TStringList.Create;
      try
        if Clipboard.HasFormatName(TheFormat) then begin
            Memo1.Append(#10+TheFormat);
            Fmt := ClipBoard.FindFormatID(TheFormat);
            ClipBoard.GetFormat(Fmt, Stream);
            if Stream.Size > 0 then begin
                Stream.Seek(0, soFromBeginning);
                List.LoadFromStream(Stream);
                Memo1.Lines.AddStrings(List, False);
            end;
        end;
      finally
        List.Free;
        Stream.Free;
      end;
    end;

Как исправить пустой буфер обмена GTK2 при выходе

Обычно, когда ваше GTK2-приложение заверщается, его буфер обмена становится пустым. Для обычного пользователя это плохо. Этот модуль - грубое исправление, добавьте его где-нибудь в uses.

pascal
unit fix_gtk_clipboard;
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      gtk2, gdk2, Clipbrd;
    
    implementation
    
    var
      c: PGtkClipboard;
      t: string;
    
    finalization
      c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
      t := Clipboard.AsText;
      gtk_clipboard_set_text(c, PChar(t), Length(t));
      gtk_clipboard_store(c);
    end.

В мае 2018 года я (dbannon) обнаружил, что помещение этого фрагмента кода в раздел finalization решает проблему, когда содержимое буфера обмена пришло из самого приложения, но если оно было там до запуска приложения, то есть приложение не записывало в буфер обмена, он представляет другую, похожую проблему. В этом случае содержимое буфера обмена снова очищается. И, похоже, это происходит потому, что к моменту выполнения условия завершения буфер обмена уже очищен.

Простое решение - поместить этот же код в событие OnClose основной формы. Достаточно рано, чтобы содержимое из любого источника все еще было там, и достаточно поздно, чтобы впоследствии его не очистить.

pascal
uses .... 
    {$ifdef LINUX}gtk2, gdk2, Clipbrd{$endif};
    .....
    procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
      c: PGtkClipboard;
      t: string;
    begin
        {$ifdef LINUX}
        c := gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
        t := Clipboard.AsText;
        gtk_clipboard_set_text(c, PChar(t), Length(t));
        gtk_clipboard_store(c);
        {$endif}
    end;

Внешние ссылки


From the Free Pascal wiki, page "Clipboard/ru", as the Internet Archive kept it on 2025-01-17. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.